High-Level Overview
┌──────────────────────┐
│ Browser / Client │
└──────────┬───────────┘
│ HTTPS
v
┌────────────────────────────────────────────┐
│ Next.js 16 frontend (port 3000) │
│ │
│ RSC + Server Actions │
│ NextAuth v5 (database session strategy) │
│ Custom BackendAdapter (lib/auth-adapter) │
│ Magic-link Nodemailer provider (sync) │
│ │
│ lib/api.ts │
│ api (public, no auth) │
│ serverApi() (server-only, Bearer │
│ from httpOnly cookie)│
│ internalApi() (server-only, X-Tok) │
└──────┬──────────────────────────┬──────────┘
│ │
Bearer session token X-Internal-Token
(read server-side from (server-only, shared bearer)
httpOnly cookie)
│ │
v v
┌────────────────────────────────────────────┐
│ NestJS backend (port 4000) │
│ PostgreSQL via Knex + pg │
│ │
│ REST + OpenAPI surface. │
│ /openapi.json (always) · /docs (dev only) │
│ │
│ Public: GET /items, /blog/* │
│ Session: item writes, /users/* │
│ Admin: /admin/* │
│ Internal: /internal/auth-adapter/* │
│ Health: GET / │
│ MCP: POST /admin/mcp (stateless) │
│ │
│ Workers (cron): EmailProcessor, │
│ UserDeletionWorker, │
│ SessionCleanupWorker │
└──────────────────────┬─────────────────────┘
│
v
┌──────────────────────────────┐
│ PostgreSQL │
│ auth: users, sessions, │
│ accounts, │
│ verification_tokens│
│ app: items, blog_posts │
│ queues: email_jobs, │
│ user_deletion_queue│
│ billing: 4 tables, see │
│ docs/Billing/ │
└──────────────────────────────┘
The browser only ever talks to the frontend. Calls to the backend go server-side: from a Server Component, from a Server Action, or from the NextAuth adapter. The session token and the X-Internal-Token never reach client-side JavaScript.