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"| CMSSvcCore Anatomy Principles:
Section titled “Core Anatomy Principles:”- 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. - 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. - 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.
- 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.
- 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 --> CloudflareAssets2.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"inastro.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
.astropages 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 undersrc/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.cfor authenticated portal views):- The developer/agent must seek explicit human architectural approval.
- The exception must be documented in
swarm.config.tsunder vertical customizations. - 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 |
Island Hydration Directives:
Section titled “Island Hydration Directives:”- Never use
client:loadon below-the-fold components:client:loadblocks critical main-thread parsing. Useclient:visiblefor calculators, testimonials, or forms located below the initial viewport. - Never hydrate purely presentational content: Do not wrap static cards, menus, or heroes in React or Vue components. Author them directly in
.astrotemplates. - Lazy Framework Runtimes: UI framework integrations (such as
@astrojs/react) must only be installed inapps/<client>/package.jsonif 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 suite3.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:
- Tier 1: Single-File Components (
< 200 LOC):- Presentational components such as
Header.astro,Card.astro,Badge.astro, orHero.astrowith fewer than 200 lines of code should remain single, self-contained.astrofiles containing frontmatter, template markup, and scoped<style>blocks.
- Presentational components such as
- Tier 2: Modular Component Directories (
> 200 LOCor 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.
- Components exceeding 200 lines of code, or components that combine complex markup, extensive CSS rules, and interactive client JavaScript (e.g.,
3.2 Role of src/contracts/
Section titled “3.2 Role of src/contracts/”- 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.
4. Data Access & Edge Binding Topology
Section titled “4. Data Access & Edge Binding Topology”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*"| CMSService4.1 Strict Binding Invariants
Section titled “4.1 Strict Binding Invariants”- Zero D1 Database Bindings in Worker A: Client frontend workers must never define
d1_databasesinwrangler.jsonc. They have no direct SQL query capabilities. - Zero KV Namespace Bindings in Worker A: Client frontend workers must never define
kv_namespacesinwrangler.jsonc. - 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"}]}
4.2 Standardized Tenant Context Injection
Section titled “4.2 Standardized Tenant Context Injection”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.tsimport 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:
- 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.
- 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. - 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 nullor hidden container). Displaying no emergency alert is vastly superior to displaying a hardcoded mock emergency alert authored months prior. - 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"]5.1 Standard Client Middleware Structure
Section titled “5.1 Standard Client Middleware Structure”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.tsimport { sequence } from "astro:middleware";import { createPlatformMiddleware } from "@siteswarm/governance";import manifest from "./swarm.config";
// 1. Canonical platform middleware: security headers, tenant context, /admin proxyconst platformMiddleware = createPlatformMiddleware({ manifest,});
// 2. (Optional) Bespoke client-specific middleware hookconst clientCustomMiddleware = async ({ request, locals }, next) => { // Bespoke routing, redirect logic, or client telemetry return next();};
export const onRequest = sequence(platformMiddleware, clientCustomMiddleware);5.2 Mandatory Security Headers
Section titled “5.2 Mandatory Security Headers”The platform middleware enforces the following baseline HTTP headers across all client responses:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preloadX-Content-Type-Options: nosniffX-Frame-Options: SAMEORIGINReferrer-Policy: strict-origin-when-cross-originPermissions-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.
6.1 public/assets/ Taxonomy
Section titled “6.1 public/assets/ Taxonomy”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)6.2 Asset Delivery Directives
Section titled “6.2 Asset Delivery Directives”- Mandatory Self-Hosted Fonts: Client applications must never load fonts from external third-party CDNs (e.g.
fonts.googleapis.comoruse.typekit.net).- Fonts must be stored as self-hosted WOFF2 files in
public/assets/fonts/. - Fonts must be loaded using
@font-facedeclarations withfont-display: swapto eliminate layout shift (CLS). - This eliminates GDPR privacy violations, prevents blocking network waterfalls, and ensures full offline local development fidelity.
- Fonts must be stored as self-hosted WOFF2 files in
- Modern Image Formats: Photographic assets should be converted to modern formats (WebP or AVIF). Avoid uncompressed multi-megabyte JPEG or PNG files.
- 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):
- Turnstile Local Dev & CI Fallbacks: Edge security capabilities must not require live Cloudflare credentials for local testing.
@siteswarm/lead-captureand form components must transparently accept Cloudflare dummy test keys (1x0000000000000000000000000000000AAfor success) in non-production environments. - 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. - Prevention of AI Context Fatigue: AI coding agents suffer line-offset misalignment when maintaining monolithic
.astrofiles 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. - 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.
8. Fleet Conformance & Governance Matrix
Section titled “8. Fleet Conformance & Governance Matrix”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.