The review stack
Orders the pass: correctness and security, then principles, then patterns, then tests and contracts, then style. You commit to that order in writing before reading a line of source — the header is already on the page.
The last two chapters gave you two disciplines: the five-layer review stack with its four-part comment shape, and the Nygard ADR template for the decisions worth recording. This project is where you run both for real, against a running SaaS app seeded with deliberate review defects.
There is no pull-request branch and no diff here. The “PR under review” is a new /plan surface added to the invoices app you have built across the course — a page showing the org’s current entitlement, seats used, and a renewal countdown. You read it and its supporting modules against the conventions the rest of the app already follows, and the defects live in those /plan files. You fix nothing: you change none of the audited source. Instead you produce two written artifacts — a review file with five file-and-line-anchored comments plus a summary and a verdict, and one architecture decision record for the single design choice the surface earns.
**blocking:** `src/app/(app)/plan/actions.ts` L18-36 — `updatePlanLabel` hand-rolls the session check, runs no role gate, and writes `org.planLabel` past the `tenantDb` facade (the `if (!session)` guard is also dead — `getSession()` never returns null).Principle/pattern: SaaS pattern #2 (lesson 2 of chapter 057 — `authedAction(role, schema, fn)`) + Principle #5 (use the named wrapper, don't hand-roll it).Action: wrap in `authedAction('admin', updatePlanLabelSchema, async (input, ctx) => { ... })` and route the write through `tenantDb(ctx.orgId).update.organizationPlanLabel(input.planLabel)`.This first lesson writes no comment. By the end you will have the audit target running, the /plan surface open in the browser, and the review file’s pass-order header acknowledged with a one-line note on where your pass begins — ready to write the first finding next.
Each item below is a reflex the later lessons teach in full; here you just exercise it.
This is a reading-and-writing project, not a feature build. The architecture is four disciplines and the one fixed target they all point at.
The review stack
Orders the pass: correctness and security, then principles, then patterns, then tests and contracts, then style. You commit to that order in writing before reading a line of source — the header is already on the page.
The principle-and-pattern map
The one-page cheatsheet from the review chapter, each rule tagged with its diff signature and lesson ID. Every comment cites it, so keep it open in a second tab.
The four-part comment template
The shape every finding takes — severity, observation, principle/pattern, action. It ships as reviews/template.md; read it once, then write each comment to it.
The Nygard ADR scaffold
The shape the one recorded decision takes — Status, Context, Decision, Consequences. It ships pre-titled with four empty sections to fill.
The audit target — the running app’s /plan surface — never changes: your proposed fixes live in the body of each comment, never in an edit. What grows is the work you produce — the two deliverable scaffolds (reviews/chapter 104.md and the ADR) and the one-line row you append to the ADR index.
The starter is the invoices app you already know, plus the new /plan surface and its supporting modules. Most of the tree is carried-over code you will not touch. The bolded files are your focus: the files the review walks — the /plan surface and its src/lib/plan/ modules — and the two deliverables you fill. The source carries no TODO comments; it is a read-only target. The only TODO markers live in the two deliverable scaffolds, naming the lesson that fills each.
Started at: line + a <!-- TODO(L2) --> marker; you fill the comments, summary, and verdict## sections + a <!-- TODO(L4) --> marker; you fill the sectionslogAudit(tx, event) — the audit seaminvoiceTags + orgPlanEntitlementTag'use cache' reads — the ADR’s precedentupdateTag mutation seams — the ADR’s precedentupdatePlanLabelSchemaSpend the first pass calibrating your eye, before you hunt for defects. Read the canonical helpers once — the authedAction wrapper, the logAudit seam, the tenantDb facade, the Temporal time primitive, and the existing cached reads in src/lib/invoices/queries.ts with their updateTag mutation seams in src/lib/invoices/actions.ts. These are the convention every finding is measured against. Learn what right looks like here so the bypass jumps out when you read /plan in the next lesson.
Each lesson produces one piece of the written deliverable, building from the first worked comment to the full review to the ADR and a self-grade.
Lesson 2 — The auth bypass
Walks the first finding end to end — the plan-label mutation that hand-rolls its own session check instead of using the wrapper — the worked example every later comment follows.
Lesson 3 — Four more blocking findings
You find the remaining four — the side-effect import, the Date arithmetic, the derived-state effect, the missing audit-log write — then close the review with the severity summary and a request-changes verdict.
Lesson 4 — ADR 0007
Runs the three-test inclusion check to find the one decision worth recording, writes the cache-decision ADR with a clear Decision and an honest Consequences list, and self-grades both artifacts against the reference.
The brief sets the bar: five is the floor, seven or eight is the experienced reach. Five blocking findings is a complete review. The surface also ships softer opportunities — a missing doc comment, a vague name, a choice worth praising — that are optional, not required. Restraint matters as much as coverage: the right mix of severities beats the highest comment count.
The audit target runs entirely on your machine: no accounts, no environment variables, just an in-memory store seeded at boot (src/server/store.ts), so nothing reaches a database or third-party service. You’re done when the app is up, /plan is on screen, and the review file’s Started at: line carries your note.
Get the starter codebase from the project repository, under Chapter 104/start/.
Install dependencies.
pnpm installBoot the app.
pnpm devOpen http://localhost:3000/plan. Read the surface, then read its source — src/app/(app)/plan/* and src/lib/plan/* — against the conventions you just calibrated on. There is no PR diff; the surface itself is the unit under review. The inspector at /inspector has an identity switcher if you want to view a second org.
Open reviews/chapter 104.md. It ships with the line Pass order: correctness/security → principles → patterns → tests/contracts → style, a blank Started at: line, and a <!-- TODO(L2) --> marker. Fill Started at: with a one-line note on where your pass begins. Read reviews/template.md once for the four-part comment shape, and keep the principle-and-pattern cheatsheet open in a second tab.
Expected result. The app runs at http://localhost:3000, /plan is visible, and your Started at: note sits under the shipped pass-order header. No comment, no ADR yet — that begins in the next lesson.
The pass-order header keeps the disciplined order on the page before you touch a line of source. A review reads top-down on the stack, not down the file list: opening file one at line one and reading straight through is the failure mode that drifts into style commentary before checking whether the code is even correct.
This is a principle-and-pattern review. It is not a style review (the linter and formatter already pass, so pnpm verify is green), not a security audit (a separate project), and not a re-implementation, since you edit no source. Every check here is one you run and tick off by hand, exactly as you would when a real PR lands with no rubric attached.