Skip to content

Client Application Anatomy & Edge Rendering Lifecycle Specification

Client Application Anatomy & Edge Rendering Lifecycle Specification

Section titled “Client Application Anatomy & Edge Rendering Lifecycle Specification”

Document Status: Living True Specification (Single Source of Truth)
Authority: Core Systems & Infrastructure Architecture
Related Epics: #34 (Client App Anatomy & Rendering), #35 (Headless Capability Anatomy), #36 (Local Dev Runtime), #37 (Client Scaffolding Blueprint), #38 (Cache Invalidation & Freshness), #101 (Capability Governance), #107 (Fleet Conformance Refactor), #108 (Governance AST Linters)
Related Documents: HIGH_LEVEL_DESIGN.md, ADR-0003, docs/specs/MULTI_WORKER_PLATFORM_SERVICES.md, docs/DATA_ISOLATION_AND_STORAGE.md, docs/CAPABILITY_MANAGEMENT.md, docs/audits/PARADIGM_STRESS_TEST_REPORT.md


1. Executive Summary & Core Anatomy Principles

Section titled “1. Executive Summary & Core Anatomy Principles”

SiteSwarm client applications run as independent, production-grade edge runtimes on Cloudflare Workers and Cloudflare Pages powered by Astro. While the macro architecture enforces runtime isolation between clients, the internal anatomy and rendering mechanics of each client application under apps/<client>/ must adhere to rigorous architectural invariants:

flowchart TD
subgraph ClientWorkspace["apps/<client>/ (Client Application Workspace)"]
direction TB
Config["Configuration & Governance\n• astro.config.mjs (output: 'static')\n• wrangler.jsonc (Zero-KV, Service Bindings)\n• swarm.config.ts (defineAppConfig)"]
StaticEdge["Edge Presentation Tier (Static-First SSG)\n• src/pages/*.astro (prerender = true)\n• Sub-20ms edge TTFB\n• 0 KB runtime JS for marketing routes"]
DynamicEdge["Dynamic Edge APIs (On-Demand SSR)\n• src/pages/api/*.ts (prerender = false)\n• Lead capture, health probes, webhook receivers"]
Middleware["Composable Middleware Pipeline\n• src/middleware.ts (Security headers, tenant context)\n• Proxy /admin* & /_emdash* to Worker B"]
Assets["Self-Contained Static Assets\n• public/assets/ (brand, images, fonts, docs)\n• Zero external CDN dependencies (self-hosted fonts)"]
end
subgraph ServiceMesh["Cloudflare Edge Service Mesh (0ms RPC)"]
LeadsSvc["services/leads-service"]
CMSSvc["services/cms-service / Worker B"]
end
StaticEdge --> Assets
DynamicEdge -->|"Service Binding: env.LEADS_SERVICE"| LeadsSvc
Middleware -->|"Service Binding: env.CMS_SERVICE"| CMSSvc
  1. Static-First Invariant (output: "static"): Public client websites are content-driven marketing applications. Every visitor-facing HTML page is statically pre-rendered at build time (prerender = true), ensuring sub-20ms edge TTFB, immunity from server compute spikes, and zero cold starts.
  2. Zero-Session KV Guarantee (ADR-0003): Public marketing frontends never maintain stateful server visitor sessions. Astro’s default session KV binding (SESSION) is strictly omitted, preventing ephemeral preview namespace proliferation and Cloudflare quota limits.
  3. Shielded Storage Path: Public frontend workers never hold direct Cloudflare D1 database or KV bindings. All mutations and persistent state flow through platform microservices via zero-latency Cloudflare Service Bindings.
  4. Zero-Framework-JS Default: Content pages ship with zero client-side JavaScript. Interactivity defaults to vanilla TypeScript and HTML5/CSS primitives. Heavy framework islands (e.g., React) are strictly opt-in and restricted to complex interactive calculators.
  5. Extreme Visual Freedom, Zero Template Monopoly: Applications share headless capabilities (packages/capabilities/*) and governance contracts, but author 100% bespoke markup, CSS, and layouts tailored to each client’s distinct brand identity.

2. Rendering Model Boundaries & Edge Lifecycle

Section titled “2. Rendering Model Boundaries & Edge Lifecycle”

SiteSwarm draws strict, unambiguous boundaries between the three execution tiers of a client application: Static Site Generation (SSG), On-Demand Edge Server-Side Rendering (SSR), and Client-Side Island Hydration.

flowchart LR
subgraph RequestIngress["Edge Visitor Request"]
Req["HTTP GET / HTTP POST"]
end
subgraph DecisionTree["Rendering Tier Decision"]
IsAsset{"Is Static Asset\nor HTML Page?"}
IsAPI{"Is /api/* Endpoint?"}
IsAdmin{"Is /admin* or /_emdash*?"}
end
subgraph SSG["Tier 1: Static-First Edge (SSG)"]
CloudflareAssets["Cloudflare Assets Cache\n(Sub-20ms TTFB, 0ms compute)"]
end
subgraph EdgeSSR["Tier 2: On-Demand Edge SSR"]
DynamicEndpoint["Edge API Route (prerender = false)\n• Lead intake verification\n• Synthetic health probes"]
end
subgraph ProxySSR["Tier 3: Service Binding Delegation"]
CMSProxy["Proxy to Worker B via env.CMS_SERVICE\n(Zero-latency V8 isolate dispatch)"]
end
Req --> IsAdmin
IsAdmin -- Yes --> CMSProxy
IsAdmin -- No --> IsAPI
IsAPI -- Yes --> DynamicEndpoint
IsAPI -- No --> IsAsset
IsAsset -- Yes --> CloudflareAssets

2.1 Static Site Generation (SSG) — The Universal Default

Section titled “2.1 Static Site Generation (SSG) — The Universal Default”
  • Configuration: All client applications must declare output: "static" in astro.config.mjs.
  • Scope: Every public content page—including /, /about, /services, /menu, /contact, and legal pages—must be compiled to static HTML and CSS at build time.
  • Prohibition on Visitor Request-Path I/O: Public .astro pages must never execute database queries, external REST API calls, or non-deterministic compute during the visitor request path.
  • Dynamic Content Injection: When pages display dynamic content (e.g. live announcements, urgent closure banners, or real-time business hours overrides), they are either pre-rendered into the static build and refreshed globally via edge cache-tag invalidation (Epic #38), or hydrated client-side against services/cms-service. If dynamic queries fail or return empty, the UI degrades gracefully to an empty state (null) rather than rendering fabricated or hardcoded fallback data.

2.2 On-Demand Edge Server-Side Rendering (SSR) — The Exception Tier

Section titled “2.2 On-Demand Edge Server-Side Rendering (SSR) — The Exception Tier”
  • Strict Confinement to /api/*: Dynamic edge execution (export const prerender = false;) is permitted exclusively for API endpoints under src/pages/api/ (e.g., form submissions, webhooks, health checks).
  • The Red-Flag Rule for HTML Pages: Rendering visitor-facing HTML pages via on-demand SSR is considered an architectural red flag. If a client requirement genuinely requires request-time HTML rendering (e.g., edge geolocation personalization via request.cf or authenticated portal views):
    1. The developer/agent must seek explicit human architectural approval.
    2. The exception must be documented in swarm.config.ts under vertical customizations.
    3. The route must be shielded by edge rate limiting and cache-control headers (s-maxage, stale-while-revalidate).

2.3 Astro Islands & Client-Side Hydration Mechanics

Section titled “2.3 Astro Islands & Client-Side Hydration Mechanics”

SiteSwarm enforces a “Zero-JS by Default” philosophy for client frontends:

Interactivity Requirement Technology Choice Hydration Strategy Permissible Payload Budget
Mobile Navigation Toggle, Accordions, Tabs HTML <details>, CSS :focus-within, or Vanilla TS Zero framework JS < 2 KB vanilla script
Telephone Masks, Modal Dialogs Vanilla TS / Native <dialog> element Zero framework JS < 3 KB vanilla script
VIN Decoder / License Plate Lookup Vanilla TS + Custom Web Component Custom Element, client-side fetch < 10 KB script bundle
Bespoke Interactive Estimator (Cake / Quote) React Component (@astrojs/react) client:visible or client:idle < 45 KB (React runtime + component)
Contact Form with Turnstile Vanilla HTML <form> + Web Component Progressive enhancement < 5 KB script
  1. Never use client:load on below-the-fold components: client:load blocks critical main-thread parsing. Use client:visible for calculators, testimonials, or forms located below the initial viewport.
  2. Never hydrate purely presentational content: Do not wrap static cards, menus, or heroes in React or Vue components. Author them directly in .astro templates.
  3. Lazy Framework Runtimes: UI framework integrations (such as @astrojs/react) must only be installed in apps/<client>/package.json if the application actively mounts a complex interactive island.

3. Canonical Application Directory Taxonomy

Section titled “3. Canonical Application Directory Taxonomy”

Every client application in apps/<client>/ must strictly conform to the following directory structure:

apps/<client>/
├── astro.config.mjs # Static-first Cloudflare adapter configuration
├── wrangler.jsonc # Zero-KV edge worker configuration & service bindings
├── swarm.config.ts # Strongly typed AppConfig manifest (@siteswarm/governance)
├── package.json # Workspace dependencies & capability bindings
├── tsconfig.json # Project TypeScript configuration extending base
├── playwright.config.ts # Local & CI end-to-end regression test suite
├── public/
│ ├── favicon.svg # Client favicon
│ ├── robots.txt # SEO crawl policy
│ └── assets/ # Self-contained static media taxonomy
│ ├── brand/ # Logos, vector marks, badges
│ ├── images/ # Photography, hero images, gallery (WebP/AVIF)
│ ├── fonts/ # Self-hosted variable fonts (WOFF2)
│ └── docs/ # Public downloadable PDFs (menus, brochures)
├── src/
│ ├── env.d.ts # Astro & Cloudflare environment types
│ ├── middleware.ts # Standardized composable edge middleware pipeline
│ ├── layouts/ # Root HTML layouts, meta tags, and typography
│ │ └── Layout.astro # Canonical page wrapper
│ ├── components/ # Bespoke Astro UI components & modular subdirectories
│ │ ├── Header.astro # Single-file component (< 200 LOC)
│ │ ├── Footer.astro # Single-file component (< 200 LOC)
│ │ └── QuoteEstimator/ # Modular component directory (> 200 LOC)
│ │ ├── index.astro # Structural markup & props
│ │ ├── styles.css # Scoped stylesheet
│ │ └── adapter.ts # Client-side state & calculation adapter
│ ├── contracts/ # (Optional) Client-specific domain types & schemas
│ │ ├── domain.ts # Client data interfaces (menu items, tiers)
│ │ └── index.ts # Clean contract exports
│ └── pages/ # Statically rendered routes & edge API handlers
│ ├── index.astro # Home page (prerender = true)
│ ├── about.astro # About page (prerender = true)
│ ├── contact.astro # Contact page (prerender = true)
│ └── api/ # Edge API endpoints (prerender = false)
│ ├── health.ts # Synthetic edge health probe
│ └── leads.ts # Form submission endpoint delegating to leads-service
└── e2e/ # Playwright integration & visual regression tests
└── smoke.spec.ts # Automated accessibility & critical path suite

3.1 Two-Tier Component Modularity Threshold

Section titled “3.1 Two-Tier Component Modularity Threshold”

To resolve the AI agent context fatigue and line-drift issues identified in the empirical stress test audit:

  1. Tier 1: Single-File Components (< 200 LOC):
    • Presentational components such as Header.astro, Card.astro, Badge.astro, or Hero.astro with fewer than 200 lines of code should remain single, self-contained .astro files containing frontmatter, template markup, and scoped <style> blocks.
  2. Tier 2: Modular Component Directories (> 200 LOC or Script-Heavy):
    • Components exceeding 200 lines of code, or components that combine complex markup, extensive CSS rules, and interactive client JavaScript (e.g., QuoteEstimator, VinLookup, CateringCalculator), must be extracted into a dedicated component folder:
      src/components/<ComponentName>/
      ├── index.astro # Component template & props contract
      ├── styles.css # Dedicated styling
      ├── adapter.ts # Client-side DOM binding, math, or event handlers
      └── types.ts # Component-specific interfaces (optional)
    • This allows AI coding agents to edit CSS or logic in isolation without re-parsing 800+ lines of mixed HTML and script tags.
  • Optional & Non-Mandatory: src/contracts/ is not enforced for simple marketing sites. It should never cause lint failures if omitted.
  • Domain Scope: When present, src/contracts/ is reserved strictly for client-specific vertical data models (e.g., BakeryMenuItem, RepairServicePackage) and vertical API validation schemas. All platform-wide horizontal contracts reside strictly in @siteswarm/governance.

Client applications must operate with zero direct access to multi-tenant databases or shared infrastructure credentials.

flowchart TD
subgraph ClientEdge["Client Worker (Worker A: apps/<client>)"]
APIRoute["src/pages/api/leads.ts"]
Middleware["src/middleware.ts"]
end
subgraph ServiceMesh["Cloudflare Zero-Latency Service Mesh"]
LeadsService["services/leads-service\n(Holds TWILIO, RESEND, TURNSTILE secrets)"]
CMSService["services/cms-service / Worker B\n(Holds D1 and R2 bindings)"]
end
APIRoute -->|"env.LEADS_SERVICE.fetch()\nHeaders: X-SiteSwarm-Tenant-Id"| LeadsService
Middleware -->|"env.CMS_SERVICE.fetch()\nPath: /admin* or /_emdash*"| CMSService
  1. Zero D1 Database Bindings in Worker A: Client frontend workers must never define d1_databases in wrangler.jsonc. They have no direct SQL query capabilities.
  2. Zero KV Namespace Bindings in Worker A: Client frontend workers must never define kv_namespaces in wrangler.jsonc.
  3. Mandatory Service Bindings: Interactions with horizontal platform services must use Cloudflare Service Bindings declared in wrangler.jsonc:
    {
    "name": "green-leaf-bakery",
    "compatibility_date": "2026-09-29",
    "compatibility_flags": ["nodejs_compat"],
    "services": [
    {
    "binding": "LEADS_SERVICE",
    "service": "siteswarm-leads-service"
    },
    {
    "binding": "CMS_SERVICE",
    "service": "siteswarm-cms-service"
    }
    ]
    }

Whenever a client application makes an RPC or fetch request over a Service Binding, it must inject the authoritative X-SiteSwarm-Tenant-Id header populated from manifest.appId:

// apps/<client>/src/pages/api/leads.ts
import type { APIRoute } from "astro";
import manifest from "../../swarm.config";
export const prerender = false;
export const POST: APIRoute = async ({ request, locals }) => {
const env = locals.runtime.env;
if (!env.LEADS_SERVICE) {
return new Response(JSON.stringify({ error: "Service unavailable" }), { status: 503 });
}
// Clone and forward request with tenant identity
const outgoingHeaders = new Headers(request.headers);
outgoingHeaders.set("X-SiteSwarm-Tenant-Id", manifest.appId);
return env.LEADS_SERVICE.fetch(request.url, {
method: "POST",
headers: outgoingHeaders,
body: request.body,
});
};

4.3 Fail-Safe Graceful Degradation & Edge Resilience (The Anti-Fabrication Invariant)

Section titled “4.3 Fail-Safe Graceful Degradation & Edge Resilience (The Anti-Fabrication Invariant)”

Public client sites must guarantee 100% visitor availability without displaying fabricated or misleading real-world business data.

The platform strictly rejects hardcoded runtime “fallback seeds” (e.g. baking fake emergency notices or dummy menu specials into client code). In production, hardcoded mock data risks active customer misinformation (e.g. displaying “Open today on normal schedule” when the physical store closed for an emergency) and masks upstream infrastructure outages.

Instead, SiteSwarm enforces a three-tier resilience model:

  1. Pure SSG Baseline: The client’s core marketing pages (home, about, core services, contact info) are compiled to static HTML on Cloudflare Assets. They have zero database or worker dependencies on the visitor request path and cannot crash.
  2. Edge Cache Absorption (SWR): Dynamic content slots served via Cloudflare Anycast edge cache absorb upstream microservice hiccups by serving the last-known-good authentic state (stale-while-revalidate=60, stale-if-error=86400), ensuring visitors see authentic data rather than synthetic placeholder text.
  3. Graceful UI Absence (Render Nothing, Don’t Fabricate): If a client-side fetch or dynamic request for an emergency banner, daily special, or hours override fails or returns empty, the UI component gracefully renders nothing (return null or hidden container). Displaying no emergency alert is vastly superior to displaying a hardcoded mock emergency alert authored months prior.
  4. Deploy-Time Migrations: Database initialization and table seeding belong strictly in deterministic deployment scripts (schema.sql / pnpm run db:seed), never in visitor runtime request handlers.

5. Composable Middleware Pipeline (src/middleware.ts)

Section titled “5. Composable Middleware Pipeline (src/middleware.ts)”

To ensure consistent security headers, tenant context, and service routing across the fleet without duplicating boilerplate, SiteSwarm utilizes a composable middleware architecture.

flowchart LR
IncomingReq["Visitor Request"] --> M1["1. Security Headers\nHSTS, CSP, Referrer, Permissions"]
M1 --> M2["2. Tenant & Runtime Locals\nInject tenantId & env into Astro.locals"]
M2 --> M3{"3. Route Check:\n/admin* or /_emdash*?"}
M3 -- Yes --> M4["Proxy to Worker B via env.CMS_SERVICE"]
M3 -- No --> M5["4. Optional Client Custom Middleware"]
M5 --> NextRoute["Serve Static Route / Edge API"]

Each client application defines src/middleware.ts. It leverages the shared platform middleware pipeline while retaining full capability to compose client-specific vertical hooks:

// apps/<client>/src/middleware.ts
import { sequence } from "astro:middleware";
import { createPlatformMiddleware } from "@siteswarm/governance";
import manifest from "./swarm.config";
// 1. Canonical platform middleware: security headers, tenant context, /admin proxy
const platformMiddleware = createPlatformMiddleware({
manifest,
});
// 2. (Optional) Bespoke client-specific middleware hook
const clientCustomMiddleware = async ({ request, locals }, next) => {
// Bespoke routing, redirect logic, or client telemetry
return next();
};
export const onRequest = sequence(platformMiddleware, clientCustomMiddleware);

The platform middleware enforces the following baseline HTTP headers across all client responses:

  • Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
  • X-Content-Type-Options: nosniff
  • X-Frame-Options: SAMEORIGIN
  • Referrer-Policy: strict-origin-when-cross-origin
  • Permissions-Policy: camera=(), microphone=(), geolocation=()

6. Static Asset, Photography & Typography Conventions

Section titled “6. Static Asset, Photography & Typography Conventions”

Client websites must deliver elite Core Web Vitals (Lighthouse $\ge 95$) and sub-second visual load times on cellular mobile connections.

All raw client media is stored in public/assets/ according to a standardized taxonomy:

public/assets/
├── brand/ # Logos, vector marks, favicons, app icons (SVG / PNG)
├── images/ # Photography, hero images, banners, staff portraits
│ ├── heroes/ # Full-bleed responsive header photography
│ └── gallery/ # Service or product thumbnails
├── fonts/ # Self-hosted variable typography (WOFF2)
└── docs/ # Downloadable customer collateral (PDFs)
  1. Mandatory Self-Hosted Fonts: Client applications must never load fonts from external third-party CDNs (e.g. fonts.googleapis.com or use.typekit.net).
    • Fonts must be stored as self-hosted WOFF2 files in public/assets/fonts/.
    • Fonts must be loaded using @font-face declarations with font-display: swap to eliminate layout shift (CLS).
    • This eliminates GDPR privacy violations, prevents blocking network waterfalls, and ensures full offline local development fidelity.
  2. Modern Image Formats: Photographic assets should be converted to modern formats (WebP or AVIF). Avoid uncompressed multi-megabyte JPEG or PNG files.
  3. Extensibility via Platform Capability Workers: While static assets are served directly via Cloudflare Assets by default, future high-performance asset optimization (e.g. dynamic edge resizing, responsive AVIF generation, or R2 offloading) can be seamlessly integrated via platform capability packages without altering the client’s local asset directory layout.

7. Lessons Learned & Empirical Spike Directives

Section titled “7. Lessons Learned & Empirical Spike Directives”

This specification codifies the critical findings from the Client Emulation Harness spike track (Epic #39 / Audit Report):

  1. Turnstile Local Dev & CI Fallbacks: Edge security capabilities must not require live Cloudflare credentials for local testing. @siteswarm/lead-capture and form components must transparently accept Cloudflare dummy test keys (1x0000000000000000000000000000000AA for success) in non-production environments.
  2. Elimination of KV Sprawl: Previous attempts to use SSR without worker splitting triggered automatic Astro session KV creation, creating orphaned namespaces during PR previews. Strictly adhering to output: "static" and Worker Splitting (ADR-0003) completely eliminates KV quota consumption.
  3. Prevention of AI Context Fatigue: AI coding agents suffer line-offset misalignment when maintaining monolithic .astro files exceeding 600 LOC. Adhering to the Two-Tier Component Modularity Threshold (< 200 LOC single-file vs > 200 LOC modular directory) keeps files compact, readable, and cleanly maintainable.
  4. Pure Headless Leverage with Bespoke UI: Headless packages (@siteswarm/quote-estimator, @siteswarm/lead-capture) provide 100% of mathematical and state logic across multiple disparate industries (bakeries, tech consultancies, auto repair shops) while allowing 100% unique visual styling and semantic markup.

Every client application must satisfy the following verification matrix before merging to main:

Domain Conformance Check Verification Command / Gate
Output Mode output: "static" declared in astro.config.mjs pnpm --filter <app> build
KV Elimination Zero kv_namespaces declared in wrangler.jsonc Monorepo change detection & linter
D1 Elimination Zero d1_databases declared in frontend wrangler.jsonc Monorepo change detection & linter
Type Integrity 0 TypeScript errors across client and contracts pnpm run check (astro check)
Governance Manifest Validated swarm.config.ts conforming to @siteswarm/governance pnpm swarm audit
E2E Regressions Playwright test suite passes (0 failures) pnpm test / pnpm test:e2e
Performance Mobile Lighthouse score $\ge 95$, initial JS payload $< 50$ KB Automated CI lighthouse run
Accessibility WCAG 2.1 AA compliant, 0 violations Automated axe-core smoke tests

Specification officially adopted by the SiteSwarm Platform Architecture Council under Epic #34.