Three surfaces where the words no longer matched the code, plus the missing web control for a preference the server already honours. Delete confirmations. Four dialogs promised permanence on surfaces that render an Undo: the measurements and mood bulk bodies, the lab-result body, and the illness-episode body (which said "cannot be undone" sixty lines below the code that fires the Undo toast). All four now use the same sentence the single-row measurement and mood dialogs already used. A sweep of every other confirmation in the tree found the rest accurate — the biomarker cascade, the mood-tag purge, and the account purge keep their warning because those deletes really are unrecoverable. Sleep debt. v1.19.0 replaced the summed shortfall with a running balance that credits catch-up sleep; the labels still described the old sum, so the word contradicted the number for anyone who slept in after a short night. Corrected in all six locales, plus the places the old semantics had propagated: the Coach system prompt, the OpenAPI field descriptions the native client reads, and four module docblocks. Glucose reference band. `hasDiabetes` selects the tighter reference band and grounds the Coach, but no web surface set it — a web-only account was pinned to the non-diabetic scale with no way out. The control goes on Targets, above the per-metric editor, because it answers the same question that page answers and the two are ordered: it picks the default band, an override below beats it. The copy says what it is — a reference band, not a diagnosis, never inferred from a reading, no clinical action taken on it. The passkey list was reported as always reading "never used". It does not reproduce: the column is selected by the list route and stamped on every verified assertion, both since v1.23.0. Pinned with tests on both halves so the contract cannot quietly regress.
src/app/
The Next.js App Router tree: the page surfaces a logged-in user sees and the REST API under api/. Server components are the default; "use client" is added only where a hook, state, or browser API needs it. Routing is file-based — a page.tsx is a page, a route.ts is an API endpoint.
API routes (api/)
Every endpoint wraps its handler in apiHandler (@/lib/api-handler), parses any body with Zod safeParse, narrows userId from the session or Bearer token (never from the body), and returns the { data, error, meta? } envelope. requireAdmin() is cookie-only, so api/admin/ is unreachable by Bearer token. Notable groups:
auth/— login, register, password, passkey (WebAuthn), refresh, Codex device-OAuth.measurements/,mood-entries/,medications/,sleep/— the core health-data CRUD + batch/bulk ingest.ingest/— external Bearer-token ingest surfaces.insights/,analytics/,dashboard/— AI insights, the Coach SSE stream, trend summaries, the first-paint dashboard snapshot.withings/,whoop/,fitbit/,integrations/,sync/— OAuth connect/sync/webhook surfaces and the offline delta feed.fhir/,share-links/,doctor-report/,export/,import/— clinician-facing FHIR R4 read API, shareable records, report + data export.notifications/,devices/,send/,telegram/— channel registration, device tokens, dispatch, webhook intake.admin/— operator panel APIs (cookie-only).health/,version/,meta/,internal/— health check, build-version probe, runtime metadata, worker-internal routes.
Page surfaces
measurements/, medications/, mood/, insights/, achievements/, notifications/, settings/, onboarding/, admin/, plus the public about/, privacy/, bugreport/, the share-record route c/, and the root dashboard (page.tsx). Shared shell + chrome lives in layout.tsx; error.tsx / global-error.tsx / not-found.tsx / loading.tsx cover the framework boundaries. layout.tsx holds the one nonce-bound dangerouslySetInnerHTML (theme bootstrap).
Conventions
See ../../CLAUDE.md. The request-flow walk in .planning/codebase/arch.md annotates each layer with file:line citations. Related dirs: handlers compose ../lib/; pages render ../components/.