Data Flow: westside-admin

arch-dataflow-westside-admin Architecture

architecture active

Data Flow: westside-admin

Diagram

Flow 1: Authenticated page load

Flow 2: Row mutation via form action

Components

Component Purpose Notes
Browser Renders SSR HTML, submits forms No JS-accessible tokens. No keycloak-js.
SvelteKit Server (adapter-node) Receives requests, runs load()/actions Single Node process per pod.
hooks.server.ts Auth gate on every request Validates JWT, populates event.locals.
Keycloak Identity provider OIDC code+PKCE flow. JWKS cached with TTL.
Postgres basketball db Connection pool via pg. tenant_id scoping enforced by helper.
scopedDb helper Tenant-scoped query builder Wraps Drizzle db; auto-injects tenant_id WHERE clause.
+page.server.ts Server-only data loading + actions The seam. Imports Drizzle here only.
+page.svelte Renders typed PageData Cannot import from $lib/server/* (compile error).

Key Decisions

  • JWT validated on EVERY request. JWKS is cached, JWT is not. Trades CPU for security against revocation lag.
  • HttpOnly cookies, no Bearer in browser. Funnel exposure forces this. Tokens never reach JS — no XSS exfiltration path.
  • tenant_id sourced from constant, not claim. v1 single-tenant; constant + helper makes the future swap to claim-sourced trivial.
  • Mutations use SvelteKit form actions, not REST endpoints. Form submission semantics, progressive enhancement, ActionResult typing.
  • Audit row written in same transaction as data mutation. Either both succeed or both fail. No mutations without audit trail.
  • Server-side token refresh. Browser never knows tokens exist; refresh happens transparently when within 30s of expiry.
  • arch-domain-westside-admin — sibling: what entities flow
  • arch-deployment-westside-admin — sibling: where the flow lives
  • project-westside-admin — parent project page
  • feedback_funnel_requires_auth — drives the cookie SSR choice