QuranFlow Admin · onboarding
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.
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.
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.
| Contract | Source of truth | Drift 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.
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.
The diagram shows the shape. The table answers the lookup. Most of day-2 onward, this is what you need:
| Task | Path |
|---|---|
| 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/ |
packages/db/src/schema/,
packages/api/src/routers/,
apps/admin/src/routes/,
and docs/spec/ for reference.
Memorise those four.
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.
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.
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 |
Don't read either tree linearly. Read these six in order, then pull the rest on demand:
| # | File | Why |
|---|---|---|
| 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. |
Every feature follows the same 7-step loop. The names of the files and tools change; the shape doesn't.
| # | Step | What 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. |
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.
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.
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.
| Command | When to run it | What 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. |
.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.
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
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.
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.
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
docs/issues/phase-0/). Come with the questions from your morning read.
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.
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.
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.)
@Kamran-AM, and link the doc you were reading when you got stuck. Day-2 starts from those notes.
@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.
packages/db/src/schema/, packages/api/src/routers/, apps/admin/src/, docs/spec/).