QuranFlow Admin · onboarding

30-minute walkthrough · orient before you write code

You opened this file because someone handed you a repo and said "start here." This is the orientation. Read it once, end to end. By the time you reach the bottom you will know what we are building, where the documentation lives, what to read first, how we keep the codebase in sync with the design, and what your day one looks like.

Audience: incoming engineers · Time: 15 minutes · Then: HANDOFF.mdCLAUDE.mddocs/spec/index.md

§1 Mental model: the four contracts how the build is partitioned

The production build is partitioned across four contracts that lock together. Each contract has a single source of truth and a different drift profile. Get this picture first; every other doc in the bundle slots into it.

YOUR READING PATH ON DAY 1 · LEFT TO RIGHT STEP 1 Visual The mockup quranflow-admin .pages.dev/v2/ what does the screen do? STEP 2 API surface tRPC routers packages/api/ src/routers/ what does it call? STEP 3 Schema Drizzle TS packages/db/ src/schema/ what's the data shape? STEP 4 Decisions 17 ADRs docs/spec/ decisions/ why was it built this way? Start at the mockup. Trace through the layers until you have enough to write the code. (Most days you stop at Step 3. Open Step 4 only when something is non-obvious.)

Start at the mockup. Walk right. The mockup tells you what the screen is. Tracing the data backward tells you what to build. Most features you finish at Step 3; you only open the ADRs when the spec asks for something non-obvious and you need the rationale.

Design direction is the reverse of reading direction — a new requirement starts as an ADR, drives a schema change, reshapes the API, lands in the visual. You don't need that picture today; the design lead owns it.

The contracts at a glance

ContractSource of truthDrift cost
Visual The live mockup at quranflow-admin.pages.dev/v2/ Slowest — a screenshot tells the story
Schema Drizzle TS in packages/db/src/schema/ + the schema design doc Most expensive — wrong column types cost a migration round trip
API surface tRPC routers in packages/api/src/routers/ + the API contract doc Most subtle — types compile but semantics drift
Decisions 17 ADRs in docs/spec/decisions/ Thinnest — read them yourself before disagreeing

Pixel match the visual. Don't paraphrase the schema. Don't add procedures that aren't in the API contract without flagging it. Don't argue an ADR without reading it. Everything else in this bundle exists to make those four things easy.

§2 Bundle tour: where things live three layers, top to bottom

The bundle is a monorepo organised as three layers. Apps sit on top — what users actually run. Packages sit underneath — code shared between the apps. Docs and tooling sit at the bottom — guidance and process. Reading the system top-to-bottom mirrors how an engineer's attention moves on day 1.

APPS what runs in production apps/admin/ Vite · React · TanStack · 39 screens apps/backend/ Hono · cron · webhooks (Stripe, Zoom) depends on PACKAGES shared between both apps ★ db Drizzle schema 12 domain files ★ api tRPC routers 1 file per procedure auth Better Auth 5 roles · ADR-009 emails Resend React Email shared cross-pkg types empty at start ★ = you open this every day described by DOCS + TOOLING guidance & process — see §3 for the docs tree docs/spec/ WHAT to build docs/architecture/ HOW it's built .claude/ commands & skills · §5 .github/ PR template · CI

Where do I... ?

The diagram shows the shape. The table answers the lookup. Most of day-2 onward, this is what you need:

TaskPath
Add a database column packages/db/src/schema/<domain>.ts
Add an API procedure packages/api/src/routers/<domain>/<name>.ts
Add a page apps/admin/src/routes/<domain>/<screen>.tsx
Find the spec for a screen docs/spec/bindings/<screen>.md  ·  or run /spec <screen>
Find out WHY a decision was made docs/spec/decisions/ADR-NNN.md  ·  or run /why <topic>
Change a shared component apps/admin/src/components/shared/  ·  locked — needs review
Add a slash command or skill .claude/commands/  ·  .claude/skills/
High-traffic paths For 80% of feature work you only touch four places: packages/db/src/schema/, packages/api/src/routers/, apps/admin/src/routes/, and docs/spec/ for reference. Memorise those four.

§3 The docs trees two trees, two questions

docs/ splits into two trees because the work splits into two jobs. docs/spec/ answers WHAT to build — it's the product layer. docs/architecture/ answers HOW it's built — it's the engineering layer. Same bookshelf, two columns.

docs/spec/ WHAT to build — the product layer docs/architecture/ HOW it's built — the engineering layer index.md The map. Read first — tells you what every other spec doc is for and which to open when. open: day 1 domains/ (9 files) Long-form spec per domain — students, teachers, semesters, billing, content, … open: before any feature bindings/ (~55 files) One file per screen. Maps each UI field to a schema column and a tRPC procedure name. open: while writing the page decisions/ (17 ADRs) Why a non-obvious choice was made. Open via /why when the spec surprises you. stack.md The library lock — Drizzle, tRPC, Hono, Better Auth, Vite, Tailwind. Swaps need ADRs. open: day 1 schema.md 3000+ line DB design doc — the source of truth for every table. Drizzle files are the translation. open: when touching schema api-contract.md · flows.md · rbac.md Router-tree shape · auth + webhook + cron data flows · 5-role permission matrix. open: when wiring procedures integrations/ · roadmap.md Stripe, Zoom, Resend integration patterns. 12-week phase plan + per-phase exit gates.

Spec changes are product changes. A new ADR or a revised binding changes what gets built. Architecture changes are engineering changes. A stack swap or a new flow changes how it gets built. Different review paths, different cadences.

How this maps back to §1

The four contracts from §1 each have a documentation home in this tree. Same shelf, different perspective:

Contract (§1)Documented in
Visual The mockup itself + docs/spec/domains/ + docs/spec/bindings/
Schema docs/architecture/schema.md (long-form) + Drizzle TS files (translation)
API surface docs/architecture/api-contract.md + per-screen bindings in docs/spec/bindings/
Decisions docs/spec/decisions/ — 17 ADRs, one per non-obvious choice

Day-1 reading order

Don't read either tree linearly. Read these six in order, then pull the rest on demand:

#FileWhy
1 HANDOFF.md The cover letter. The four-contract model. Day-1 first-actions.
2 CLAUDE.md The in-code conventions. Locked-surface tiers. Reading order in detail.
3 docs/spec/index.md The map for the spec tree. Tells you what every other spec doc is for.
4 docs/architecture/stack.md What we picked and what is locked. Read sections 1 through 4.
5 docs/architecture/schema.md Skim only — sections 0 (rules) and 1 (core tables). You will return.
6 One domain in docs/spec/domains/ Pick student-management. Read it end to end. Then click through the mockup at /v2/students and feel the mapping.
Precedence rule When two docs disagree: an applied ADR > the live mockup > the v2.1 domain spec > the v2 narrative > legacy v1 docs. If you can't resolve a conflict from that list, flag it on GitHub — don't pick.

§4 The build workflow loop how a feature flows from spec to merge

Every feature follows the same 7-step loop. The names of the files and tools change; the shape doesn't.

1 Read spec 2 Check schema 3 Build 4 Verify 5 Open PR 6 Review 7 Merge one feature = one loop
#StepWhat you actually do
1 Read spec Open the matching binding in docs/spec/bindings/. Read columns, filters, role-visibility, and which ADRs apply. The /spec slash command pulls this into your editor in one keystroke.
2 Check schema Open the matching file in packages/db/src/schema/. Confirm the columns the binding references exist with the expected types. If the binding wants a column the schema doesn't have, stop and flag.
3 Build Add the procedure under packages/api/src/routers/<domain>/ following the patterns in docs/process/trpc-patterns.md. Add the page under apps/admin/src/routes/<domain>/ (TanStack file-routing). Run /visual-check <screen> to pull the mockup URL + binding alongside your editor — it is the visual contract.
4 Verify /pre-pr runs all of this in one shot: bun run typecheck · lint · test · build, plus a locked-surface scan and a secret scan. All green or the PR is not ready. Local run: bun run dev and click the screen.
5 Open PR The PR template asks for the spec link, the binding link, the mockup screenshot, and an ADR check. Fill every field — they exist because they catch real bugs. CODEOWNERS auto-tags @Kamran-AM on locked-surface edits.
6 Review CODEOWNERS routes spec-touching, schema-touching, auth-touching, and shared-component PRs to the design lead. Other PRs self-review between you and your teammate. CI runs typecheck + lint + build on every push.
7 Merge Squash-merge with a conventional-commit message. The branch deletes on merge. Move to the next issue.
The mockup is the visual contract Before you write any UI, open the matching screen at quranflow-admin.pages.dev/v2/. Read the columns. Note the filters. Watch the empty / loading / error states. Then code. Reviewers will screenshot the mockup and your PR side by side.

§5 The verification mesh four mechanisms that catch drift

Drift between spec / schema / code is the failure mode this bundle exists to prevent. We catch it with a mesh of four independent mechanisms, not a single linear gate. Defence in depth: each mechanism is loose on its own, but together they are hard to slip past.

Slash commands fires: while you're coding, in your IDE /spec <name> pulls the binding + ADRs into context /locked-check <path> says "needs an ADR" before edit catches: spec drift, accidental edits to locked paths file: .claude/commands/ Repo-local skills + CLAUDE.md fires: every Claude turn, automatically • CLAUDE.md loaded every turn — conventions + locked surface .claude/skills/ for repo-specific patterns on demand catches: convention drift, "I forgot the audit-log rule" file: CLAUDE.md, .claude/skills/ PR template + CODEOWNERS fires: when you open a pull request • 7-item checklist: spec link, mockup screenshot, ADR check… • CODEOWNERS routes locked paths to @Kamran-AM catches: reviewer drift, "we forgot to surface the schema change" file: .github/PULL_REQUEST_TEMPLATE.md CI checks fires: on every push to a PR branch bun run typecheck · lint · build • Blocks merge until green catches: type drift, build drift, the easy automatic stuff file: .github/workflows/ci.yml spec ↔ code drift

Mechanism by mechanism

1 · Slash commands (in your IDE)

/spec <screen> pulls the binding, the relevant domain section, and any touching ADRs into the conversation. /locked-check <path> tells you whether a path needs an ADR before you edit it. Run them before you start; don't wait until reviewer time.

2 · CLAUDE.md + repo skills

CLAUDE.md is loaded on every Claude turn — it carries the locked surface, the conventions, and the precedence rules. .claude/skills/ holds on-demand patterns (e.g. "how to add a new tRPC procedure end-to-end"). Treat them as advisory, not enforcement.

3 · PR template + CODEOWNERS

The PR template's 7-item checklist forces you to surface a screenshot + the spec link + the ADR check before reviewers see it. CODEOWNERS auto-requests @Kamran-AM on schema, API, auth, or shared-component changes — so a locked-path edit can't merge without explicit sign-off.

4 · CI checks

GitHub Actions runs bun run typecheck · lint · build on every push. Merge is blocked until green. CI catches the easy automatic stuff; the other three layers catch the judgement stuff CI can't see.

The six slash commands — full reference

Type any of these in Claude Code to load context, run a check, or pull a decision. Each one runs a small shell + file lookup and dumps the result into your conversation. They live in .claude/commands/<name>.md — open one if you want to see exactly what it does.

CommandWhen to run itWhat it does
/spec <screen> Before building a feature Pulls the domain narrative, the per-screen binding, and any touching ADRs into the conversation. Argument matches against docs/spec/domains/ headings, docs/spec/bindings/ filenames, and docs/spec/decisions/ ADR names. E.g. /spec students, /spec student-detail, /spec coupons.
/visual-check <screen> When porting a UI screen Surfaces the mockup URL (quranflow-admin.pages.dev/v2/<screen>), the matching binding doc, and the code path you'll be working in. Run it side-by-side with your editor so the visual contract is in view as you code.
/why <topic-or-#> When the spec surprises you Loads the ADR(s) for a given decision. Accepts a keyword (/why coupons, /why rbac, /why audit-log) or a number (/why 009, /why 018). Use it before disagreeing with a locked surface.
/locked-check <path> Before editing schema, auth, or a shared component Cross-references your current diff against .github/CODEOWNERS and tells you whether the path is LOCKED (needs an ADR + design-lead review), NEGOTIABLE, or YOURS. Run before committing so you don't surprise yourself at PR-open time.
/pre-pr Before opening a PR Runs the pre-flight locally: diff summary, bun run typecheck, lint, build, test, a locked-surface scan, and a secret scan. Mirrors what CI does plus the manual checks CI can't run.
/verify-phase <n> At a phase boundary Loads the exit gate for build phase n (0, 1, 2, …) and walks the acceptance criteria. Backed by a skill at .claude/skills/phase-<n>-exit-gate/ for phases 0-2. Don't declare a phase done until this passes.
Not on Claude Code? The commands are markdown files — open .claude/commands/<name>.md in any editor and run the shell snippets manually. The verification mesh works either way; the commands just make the lookups faster.
No hooks We do not use Claude Code hooks for blocking. Hooks are deterministic — they fire on every matching tool call regardless of context — and at this stage of the build that's too blunt. We rely on the slash commands + CLAUDE.md + PR template + CI together. If drift becomes a real pattern, the design lead has a documented hook upgrade path in CLAUDE.md §5.3.
Reading the mesh Each mechanism is loose. Slash commands are advisory. CLAUDE.md is advisory. The PR template can be lied to. CI only catches type and lint. Combined, they make drift expensive enough that you notice before merge. That is the whole design.

§6 Phase 0: your day one 9 AM to 5 PM

A concrete sequence for your first working day. Treat the times as a pacing guide, not a strict schedule. If a step takes longer, slide the next one. The goal of day one is orientation — not shipping code.

Morning

09:00
Clone the repo. Run bun install. Set up env files. Copy each package's .env.example to .env and fill from the secrets vault. Run bun run dev to verify the Week-0 exit gate (hello-world route + tRPC round-trip + Better Auth signup/signin pages). Migrations and seed land in Week 1 — don't try to run db:migrate today (no migration files exist yet). If anything fails on bun install or bun run dev, open a GitHub issue tagging @Kamran-AM before lunch.
10:00
Read HANDOFF.md and CLAUDE.md from the bundle root. ~50 minutes total. HANDOFF.md gives you the four-contract model; CLAUDE.md gives you the conventions and the locked surface. Come to the kickoff call with questions on either.
11:00
Read docs/spec/index.md and two ADRs. The two to start with: ADR-009 (RBAC future state — the 5-role model) and ADR-018 (family-plan coupon strategy — most-recently-amended). Together they show you what an ADR looks like and how amendments get layered in.

Lunch break

Afternoon

13:00
60-minute walkthrough call with the design lead. Agenda: bundle tour, four-contract demo, Week-0 exit-gate live, Phase-0 issue assignments (issues listed in docs/issues/phase-0/). Come with the questions from your morning read.
14:00
Run the mockup locally. Clone QuranFlow-Admin-Mock, bun install, bun run dev. Or just open the live build at quranflow-admin.pages.dev/v2/. Click through Dashboard, Students list, Student Detail. Note one thing that surprises you — flag it in your standup notes tomorrow.
15:00
Browse docs/spec/domains/ and docs/spec/bindings/. Pick one domain — student-management is a good first read. Open the narrative in domains/, then a binding like bindings/03-students-list.md. Notice how the binding maps each UI field to a schema column and procedure name.
16:00
Open the first 5 Phase-0 issues from docs/issues/phase-0/. Vendor signups (Neon, DigitalOcean, Cloudflare R2, Resend, Sentry) — these are not coding tasks but they unblock everything else. Move them into your team's issue tracker. Decide who owns which signup. (Backend host is DigitalOcean App Platform per ADR-019.)
16:45
End of day: file your blockers as GitHub issues. Anything that surprised you, anything you couldn't resolve from the docs, anything that needs Kamran's input — open a GitHub issue per item, tag @Kamran-AM, and link the doc you were reading when you got stuck. Day-2 starts from those notes.
How to reach the design lead GitHub issues with @Kamran-AM tag is the canonical channel — for blockers, design questions, doc gaps, and anything else you'd otherwise DM about. Kamran monitors issue activity and replies in-thread; tagging him ensures it doesn't get lost. Don't use email or Slack — issues are searchable, public to the team, and let the next engineer learn from the answer.

What success looks like at end of day 1

If you're ahead Read CLAUDE.md §4 (conventions) and the schema design doc §0 + §1. Then stop. Day 2 is when you start touching code — don't pre-spend day 2's attention on day 1.