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.
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 | 18 ADRs in docs/spec/decisions/ |
Thinnest — read them yourself before disagreeing |
docs/spec/decisions/, numbered ADR-001 through ADR-019 (we skipped 011). Read one before disagreeing with a locked surface.
Match the mockup exactly. Don't rewrite the schema. Don't add procedures that aren't in the API contract without flagging it. Don't override 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.
Quick lookup:
| 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 |
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/ — columns, filters, role-visibility, applicable ADRs. The /spec slash command pulls it instantly. |
| 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. |
| 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. |
| 6 | Review | GitHub's CODEOWNERS file auto-assigns @Kamran-AM as reviewer on spec, schema, auth, or shared-component edits. Other PRs are reviewed by 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 — when the spec, the schema, and the code go out of sync — 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 to understand a locked decision. |
/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. |
/file-issue |
When you hit a spec TBD, OQ code, or any question that needs routing | Interactive flow — asks the type (spec / architecture / billing / infra), 3 focused questions, drafts the issue body, shows it for review, then submits via gh issue create. All four templates default-tag @Kamran-AM + @LejlaPi; Kamran loops in Wasif (infra) or Usama (Stripe) as needed. Backed by a skill at .claude/skills/file-an-issue/. |
.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.