90x architecture atlas
Ten diagrams drawn from the code on main (e82417c, 2026-10-10), each passing Archify's checks. Read them in order: the big picture first, then how content is made, then a learner's day, then what happens on one tap, then safety. Every box has source links (SRC) to the file it came from.
1 · The big picture
01architecture
System architecture
- Every request meets the proxy first (session, /admin lock, maintenance).
- Server actions are the hub: Postgres via Drizzle, Redis, R2, Resend.
- All AI spend passes one gate, aiGate(); Coach drops to the fast model past a spend line.
- QStash wakes job routes: push, LeetCode sync, weekly reviews.
- The Python pipeline and GitHub Actions run offline and write in.
02workflow
Delivery and ops
- PR → filter decides which jobs run; gitleaks always runs.
- e2e runs as two shards behind one required check.
- Vercel deploys main only (bom1), then /api/health.
- Nightly GPG-encrypted backup to private R2, 30 days.
- Prod migrations: by hand, with your go.
2 · How content is made
03dataflow
Content pipeline
- Download → normalize + enrich (importance) → staging.duckdb.
- Lessons first (NoSource: no downloaded source, no lesson); cards, audio and Coach chunks come from lessons.
- Every paid LLM call stops at PIPELINE_MAX_USD.
- Only three steps write to prod: Vector embed, R2 audio, publish to Supabase.
04lifecycle
Content status
- staged → draft → live → retired; publish only creates drafts.
- Live needs an admin batch review or pipeline swap.
- "hidden" is a separate switch: 2 reader flags or 14 days of skips; admin keeps or retires.
3 · A learner's day
05workflow
Today: the daily loop
- ensureToday closes past days, claims today in one transaction, then plans.
- planDay: due reviews first, then weakest-pattern problems, weakest-area topic, always one 10-cards mission.
- A solve ticks a mission → awardXp → review ladder → refreshDay → streak.
- An hourly tick drives rollover, morning push, 8 pm reminder, Sunday review.
06lifecycle
Review schedule
- Two schedulers: problems use a fixed 3 → 7 → 21 day ladder; cards use FSRS.
- Only failed or hinted problems enter the ladder; a clean solve never returns.
- Cards wait at least 7 / 14 / 30 days (Hard / Good / Easy).
4 · One tap, end to end
07sequence
Answering a Feed card
- A server action, submitAnswer, not an API route.
- Most kinds are graded by code (free, 2 XP); only written answers go through the AI gate (1 XP).
- One transaction saves review + FSRS state + XP.
- The next card comes back in the same request from the Redis queue.
08sequence
Sending a Coach message
- Three checks before the model: sign-in, AI gate, per-user message slot.
- Each thread kind brings its own prompt and tools; user text is fenced as untrusted.
- The reply is stored even if you leave; usage is logged.
5 · Safety and accounts
09sequence
What protects a request
- Firewall → proxy (maintenance, /admin lock, cookie refresh) → getViewer.
- getViewer fails closed: ES256 signature check; approval and admin read from the DB each request.
- The browser has no path to data (Data API closed).
- CSP and security headers on every response.
10lifecycle
Account lifecycle
- Sign-in creates a pending row; auto_approve approves at once.
- Approved → /setup → active. Welcome is a one-time overlay, not a state.
- Blocked can still sign in to delete; admin delete needs the typed email.
- Deleted keeps details 90 days, then only a count.
One thing worth knowing. The database role the app uses is not limited by row-level security.
What keeps one user's data apart is that every server query filters by
user_id from getViewer, plus the
closed Data API. RLS policies stay only as a backstop, and CI checks them.