Files
HealthLog/src/app
Marc-André Bombeck 1a6e523b29 refactor(medications): one admission path and one replay key for intake imports
The per-medication import and the account-wide dose-history import queued
their work through ninety near-identical lines each: row lock, stale-job
sweep, active-job refusal, job row, pg-boss send, and the fallback that fails
the row when the queue is not there. Five steps written twice drift, and the
drift shows up as an import that hangs on one surface and not the other. The
status projection moved out of these routes for the same reason; this is the
write half.

Scope is the only real difference, and it is one argument. What the two
surfaces legitimately say differently — the 409 wording, the envelope, the
kickoff audit line — stays at the call site.

The replay key had the same shape of problem in smaller form: the export
reader owned a function for it and the hand-listed body inlined the same
template. Both now call one function, with a test that pins them equal for
the same medication and instant.
2026-07-27 14:47:55 +02:00
..
2026-03-10 20:14:33 +01:00
2026-03-10 20:14:33 +01:00

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/.