Web Architecture Overview

What lives where — as of 4 Apr 2026

Domains

koda.systems Live
Static documentation dashboard. Public — no auth required.
Hosting Cloudflare Pages Source site/ directory Deploy Auto — fswatch → generate-dashboard.js → wrangler pages deploy Pages / /build /status /changelog /flow
api.koda.systems Live
Koda Core REST API + Console PWA. Protected by Cloudflare Access (zero-trust gate).
Hosting Cloudflare Tunnel → localhost:3033 (Koda Core / Express) Auth Layer 1 Cloudflare Access — email OTP, sets Cf-Access-Jwt-Assertion Auth Layer 2 Koda JWT — issued by /api/auth/token, 24h expiry Serves /api/* REST endpoints   /console/* PWA
console.koda.systems Not deployed
Originally planned as a standalone Pages deployment for the Console PWA. Currently the console lives at api.koda.systems/console/ instead.
Blocker CF Access policy is scoped to api.koda.systems — token not valid for a different origin Status CORS whitelist ready in server.js, but domain not wired up
Why console.koda.systems doesn't work yet

Cloudflare Access issues the Cf-Access-Jwt-Assertion header scoped to api.koda.systems. If the console were served from console.koda.systems, that header wouldn't be present (different origin, different Access application), so POST /api/auth/token would fail.

Additionally, auth.js has a hardcoded CF Access login redirect pointing at api.koda.systems. To split the domains you'd need: a second CF Access application for console.koda.systems, CORS for cross-origin API calls, and an updated auth redirect URL.

For now, serving the console at /console/ on the same origin as /api/ is simpler and avoids all cross-origin issues.

Request Flow

Browser
Console PWA or API client
Cloudflare Access
Zero-trust gate (email OTP)
Cloudflare Tunnel
Encrypted → localhost
Koda Core
:3033 / Express
PostgreSQL
via PostgREST :3000
Koda Core
validates JWT, routes request
Claude CLI
AI processing

API Endpoints on api.koda.systems

/api/auth/token Exchange CF Access JWT for Koda JWT no auth
/api/status System health & component versions JWT
/api/chat/send Send a message to Claude (real-time) JWT
/api/sessions List, view, reset sessions JWT
/api/tasks Task management (CRUD) JWT
/api/memories Memory management (CRUD) JWT
/api/messages Message history JWT
/api/model Get/set active Claude model JWT
/api/usage Claude usage & token tracking JWT
/api/config System configuration JWT
/api/credentials Encrypted credential store JWT
/api/users User management (admin) JWT
/api/groups Signal group management JWT
/api/apps App platform registry JWT
/api/jobs Background job status JWT
/console/* Console PWA (static files + service worker) CF Access

Infrastructure Stack

Tunnel cloudflared (launchd: com.koda.tunnel) — token-based, rules in CF Dashboard Koda Core Node.js / Express on :3033 (launchd: com.koda.core) Database PostgreSQL + PostgREST on :3000 Pages Cloudflare Pages project: koda-systems (auto-deployed via fswatch) Access Team: koda-systems — protects api.koda.systems Console PWA Alpine.js + HTMX + Tailwind (no build step), served from apps/console/

Security & Integration Boundaries

Every external system Koda touches is gated by the External Integration Pattern (EIP) — a five-layer defence covering process isolation, chokepoint modules + lint, the bundle-router meta-loader (3 runtimes, 13 bundles, 62 actions), three-actor audit + anomaly watchdog, and confirm-before-destructive guardrails. The dispatch gate is HARD-FAIL since koda-core 2.82.0: any unregistered action is refused with an audit row + owner DM.

Diagram koda.systems/flow → Reference → External Integration Pattern (EIP) ADR ADR-021: External Integration Pattern — Five-Layer Defence Audit Compliance matrix — per-surface RAG scoring Bundles bundles/<name>.yaml declare actions, chokepoint functions, permissions, destructive flags, and matcher instructions