# pages — Architecture Full design + security analysis: `plans/2026-07-12-pages-design.md`. ## Components ``` ┌─────────────────────────────────────────┐ browser ──────────▶ │ Cloudflare Worker (Rust → wasm, axum) │ │ │ GET / │ routes/mod.rs router construction │ GET /auth/* │ routes/auth.rs GitHub OAuth, sessions │──▶ github.com (token exchange) * /api/* │ routes/api.rs pages + users JSON API │──▶ D1 `DB` (users/sessions/pages) GET //* │ routes/serve.rs page content serving │──▶ R2 `PAGES` (/) │ │ │ core/ pure policy logic (native- │ │ tested): slug, mime, upload │ │ validation, security headers │ └─────────────────────────────────────────┘ ``` ## Component interactions - **core/** has no Cloudflare dependencies; it compiles natively and holds every security-relevant decision (slug grammar, reserved names, zip limits, MIME allowlist, CSP header values). Unit tests live here. - **db.rs** (wasm-only) wraps D1 queries; **routes/** (wasm-only) are thin axum handlers that call core + db + R2. - **auth.rs** builds OAuth URLs and cookie/session token logic (pure parts native-tested); the GitHub HTTP calls are wasm-only. - **static/index.html** is the whole management UI, embedded at compile time with `include_str!` and served at `/`. ## Trust boundaries 1. **Uploaded content** is untrusted: validated in core/upload.rs, stored in R2, and always served with a sandboxing CSP (opaque origin) so it can never make credentialed calls to `/api`. 2. **Browser → API**: session cookie (`__Host-`, HttpOnly, SameSite=Lax, hashed in D1) + Origin check on mutating routes. 3. **Worker → GitHub**: client secret only ever used server-side.