docs: add navigational READMEs to key code directories

Add a README to src, src/lib, src/app, src/components, prisma, scripts,
and e2e so a technical visitor browsing the tree gets oriented: what
lives in each directory, the most important files, the local
conventions, and pointers to related dirs and docs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Marc-André BombeckandClaude Opus 4.8 committed 2026-06-05 15:26:34 +02:00
1 parent e7c76e5bca
commit b3a626d83c
7 files changed
+188

No files matched your search

+21
View File
@@ -0,0 +1,21 @@
# `e2e/`
End-to-end browser tests. Playwright 1.60 drives a production build of the app against a real PostgreSQL, with `@axe-core/playwright` for accessibility assertions. This is the heaviest test tier; CI runs it on every PR, and locally it is worth running when a change touches a UI flow.
## Running
```bash
pnpm e2e
```
The Playwright config (`../playwright.config.ts`) builds the app (`next build`) and brings up Postgres before the specs run; `setup/global-setup.ts` seeds the auth + fixture state. The suite is not part of the fast local gate (`typecheck` / `lint` / `test`) — it surfaces at PR CI, so expect responsive/wizard/nav reworks to flag here first.
## Layout
- **`setup/`** — `global-setup.ts` (auth + DB seeding), `test-helpers.ts` (shared login + navigation helpers).
- **`utils/`** — fixtures such as `mock-dashboard-snapshot.ts`.
- **`*.spec.ts`** — one spec per flow: auth/login/redirect, dashboard, charts, the medication-wizard cadences (`medications-wizard-*`), insights generation + scroll restoration, doctor report, settings, mobile-viewport consistency, locale switch, accessibility (`a11y.spec.ts`), and the `v1427-*` regression set.
## Convention
Assert against stable `data-*` attributes (`data-slot`, `data-display-step`, root display attrs), not viewport-dependent visible text. Responsive `sm:hidden` UI changes break `getByText` on desktop while the underlying element is still present — anchoring on data attributes keeps the specs stable across breakpoints. See [`../CLAUDE.md`](../CLAUDE.md).
+28
View File
@@ -0,0 +1,28 @@
# `prisma/`
The database layer. HealthLog runs PostgreSQL 16 via Prisma 7. This directory holds the single schema file and the forward-only migration history; the generated client is emitted elsewhere.
## Contents
- **`schema.prisma`** — 61 models, one file. `cuid()` primary keys, `snake_case` columns via `@map(...)`, encrypted columns mostly suffixed `*Encrypted` (search the file; there are 24 encrypted column references). The `generator client` block emits to `../src/generated/prisma` (imported as `@/generated/prisma`).
- **`migrations/`** — numbered, forward-only SQL migrations (`0001_…` upward). `migration_lock.toml` pins the provider to `postgresql`.
## Migration workflow
```bash
# author a migration from a schema edit
pnpm dlx prisma migrate dev --name <short_snake_case_name>
# regenerate the client after any schema change
pnpm dlx prisma generate
```
Number a new migration with the next free prefix. The production entrypoint runs `prisma migrate deploy` on boot, so every migration must apply cleanly forward — there is no down-migration path. Always include the migration file in the same change as the schema edit.
## Conventions
- Encryption is fail-closed: `*Encrypted` columns are written through `@/lib/crypto` (AES-256-GCM, versioned key ids); never store plaintext in an encrypted column. Key rotation is `scripts/rotate-encryption-key.ts` + `docs/ops/encryption-key-rotation.md`.
- The generated client under `src/generated/prisma` is build output — do not edit it.
- Schema-touching changes that affect the API surface must regenerate `docs/api/openapi.yaml` (see [`../CLAUDE.md`](../CLAUDE.md)).
Related: [`../src/lib/README.md`](../src/lib/README.md) (`db.ts`, `rollups/`), [`../docs/ops/`](../docs/ops/) (migrations + backup runbooks).
+31
View File
@@ -0,0 +1,31 @@
# `scripts/`
One-shot operator and build scripts. These are not part of the running application — they are run by hand during a deploy, a backfill, or a release, or wired into CI. Recurring work belongs on pg-boss (`src/lib/jobs/`), not here.
## How to run them
```bash
pnpm dlx tsx scripts/<file>.ts
```
Use `pnpm dlx tsx`, not bare `pnpm tsx`. The production standalone image strips `tsx`, so the bare invocation fails inside the container. `scripts/` is excluded from the project typecheck.
## What lives here
- **`generate-openapi.ts`** — emits `docs/api/openapi.yaml` from the registered Zod schemas (`pnpm openapi:generate`).
- **`check-openapi.ts`** — compares a freshly generated spec against the committed YAML; CI fails on drift (`pnpm openapi:check`).
- **`check-env.ts`** — pre-deploy env-var sanity check against `env-manifest.json` (`pnpm check-env`); wired into CI.
- **`assert-deploy.ts`** — post-deploy `/api/version` assertion.
- **`rotate-encryption-key.ts`** — AES-256-GCM key rotation; see `docs/ops/encryption-key-rotation.md`.
- **`restore-backup.ts`** — restore an off-host AES-GCM backup from an S3-compatible bucket.
- **`backfill-rollups.ts`**, **`drain-per-sample-cumulative.ts`**, **`backfill-mood-note-column.ts`** — historical data backfills (note: the boot-time `rollup-full-backfill` queue handles new accounts automatically; the CLI is the manual fallback).
- **`seed-demo.ts`** + **`seed-demo-v15.sql`** — populate a demo tenant.
- **`test-notifications.ts`** — exercise the notification dispatcher + reminder check.
- **`fetch-geolite2.sh`** — download the MaxMind GeoLite2 MMDBs (needs a licence key) before `docker build`.
- **`install-hooks.sh`** — install the local git hooks.
- **`generate-sw-version.mjs`**, **`print-bundle-report.mjs`** — service-worker version stamp and bundle-size report.
- **`i18n/`** — locale tooling; **`__tests__/`** — tests for the scripts above.
## Conventions
See [`../CLAUDE.md`](../CLAUDE.md) "Tests and commands" + "Self-hosting gotchas". Operator runbooks that drive these scripts live in [`../docs/ops/`](../docs/ops/).
+26
View File
@@ -0,0 +1,26 @@
# `src/`
Application source. HealthLog is a Next.js 16 App Router project (`output: "standalone"`, React 19, TypeScript strict). The path alias `@/*` resolves to this directory. Everything a request touches lives under here; the layout below follows the request flow rather than alphabetical order.
## Request flow
```
client → src/proxy.ts → src/app/<route>/route.ts → src/lib/api-handler.ts → handler body → src/lib/api-response.ts → client
```
- **`proxy.ts`** — the HTTP edge (Next.js 16's renamed `middleware`). Public-path allowlist, demo-mode mutation block, server-side onboarding redirect, worker-only refusal, `x-request-id` + CSP nonce generation, every security header.
- **`app/`** — App Router pages (RSC by default) and API routes. Every API route wraps its handler in `apiHandler`. See [`app/README.md`](app/README.md).
- **`lib/`** — the server/runtime toolkit: `apiHandler`, auth, crypto, rollups, AI, notifications, pg-boss jobs, integrations, rate limiting. See [`lib/README.md`](lib/README.md).
- **`components/`** — React components (shadcn/ui new-york, kebab-case files). See [`components/README.md`](components/README.md).
## Other directories
- **`hooks/`** — shared React hooks (`use-` prefix, kebab-case).
- **`types/`** — shared TypeScript declarations.
- **`generated/prisma/`** — the generated Prisma client (do not edit; regenerated by `prisma generate`). Imported as `@/generated/prisma`.
- **`instrumentation.ts`** — Next.js startup hook; boots the pg-boss worker registry and boot-time backfill queues.
- **`__tests__/`** — cross-cutting unit tests; most tests live in `__tests__/` folders next to the code they cover.
## Conventions
See [`../CLAUDE.md`](../CLAUDE.md) for the full set. The load-bearing ones: RSC by default (`"use client"` only when a hook/state/browser API needs it); every API route wraps `apiHandler` and parses its body with Zod `safeParse`; `userId` is always narrowed from session or Bearer, never accepted as a body field; TanStack Query keys come only from `src/lib/query-keys.ts`; outbound HTTP goes through `src/lib/safe-fetch.ts`.
+25
View File
@@ -0,0 +1,25 @@
# `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`](../../CLAUDE.md). The request-flow walk in `.planning/codebase/arch.md` annotates each layer with file:line citations. Related dirs: handlers compose [`../lib/`](../lib/README.md); pages render [`../components/`](../components/README.md).
+24
View File
@@ -0,0 +1,24 @@
# `src/components/`
React components. The UI primitives are shadcn/ui (new-york style, zinc base) over Radix + Tailwind 4 + Lucide; everything above the primitives is feature-grouped by surface. Components are server components unless they need a hook, state, or browser API, in which case they open with `"use client"`. Charts use Recharts 3 — replacing the chart library requires explicit approval.
## Primitives and shell
- **`ui/`** — shadcn/ui primitives (button, dialog, sheet, table, …). Generated by the shadcn CLI; keep edits minimal and on-style.
- **`layout/`** — the app shell: sidebar, topbar, bottom nav.
- **`providers.tsx`, `app-settings-provider.tsx`, `version-poller.tsx`** — top-level context providers and the self-healing stale-shell poller.
- **`i18n/`** — translation context + locale switcher.
## Feature groups
- **`insights/`** — insight status, assessment cards, Coach surface, advisor cards (the largest group).
- **`medications/`** — medication cards, the schedule wizard, intake timeline, detail history.
- **`settings/`** — the section components behind each settings page.
- **`measurements/`, `mood/`, `dashboard/`** — entry forms, lists, dashboard tiles.
- **`charts/`** — Recharts wrappers.
- **`monitoring/`** — Umami / GlitchTip client bootstrap.
- **`gamification/`, `targets/`, `comparison/`, `doctor-report/`, `clinician/`, `onboarding/`, `admin/`** — the remaining per-surface groups.
## Conventions
Kebab-case filenames; React component exports stay PascalCase regardless. (A handful of PascalCase-filename outliers under `medications/` + `onboarding/` are pre-existing drift, noted in [`../../CLAUDE.md`](../../CLAUDE.md).) Every `t()` call needs a matching key in `messages/en.json` — guarded by `i18n-call-site-coverage.test.ts`. Data reads go through TanStack Query with keys from `@/lib/query-keys` and unwrap `(await res.json()).data`. Tests live in [`__tests__/`](__tests__/).
+33
View File
@@ -0,0 +1,33 @@
# `src/lib/`
The server and runtime toolkit. Everything that is not a page, component, or route handler lives here: the API kit, auth, crypto, the rollup tier, AI providers, notifications, background jobs, and the integration clients. Route handlers and RSC pages compose these modules; the modules never reach back into `app/`.
## Core request kit
- **`api-handler.ts`** — the `apiHandler` wrapper every route uses. Auth resolver (cookie OR Bearer), `requireAuth` / `requireAdmin` (admin is cookie-only by construction), idempotency plumbing, Wide-Event builder, GlitchTip forwarder.
- **`api-response.ts`** — the `{ data, error, meta? }` envelope: `apiSuccess` / `apiError`, `safeJson`, trusted-proxy IP resolver, `returnAllZodIssues` + `sanitiseZodIssues`.
- **`rate-limit.ts`** — Postgres-backed sliding-window limiter (single atomic upsert); multi-instance correct.
- **`idempotency.ts`** — user-scoped idempotency keys that refuse to cache secret-shaped responses.
- **`query-keys.ts`** — the only legal source of TanStack Query `queryKey` / `mutationKey` arrays (enforced by an ESLint rule).
- **`safe-fetch.ts`** — the one documented outbound-egress entry (`redirect: "manual"` + timeout; optional connect-time DNS-rebinding pin). Raw `fetch(` under `lib/` + `app/` is banned by ESLint.
- **`db.ts`** — the Prisma client singleton.
- **`crypto.ts`** — AES-256-GCM at rest with versioned key ids, fail-closed loader, rotation primitives.
## Subsystems
- **`auth/`** — Postgres sessions, secure-cookie flag policy, passkey (WebAuthn) + Argon2id password, per-device refresh-token rotation, HMAC Bearer tokens.
- **`ai/`** — multi-provider insight + Coach engine: `provider-chain.ts`, hand-rolled `{openai,anthropic,local,codex,mock}-client.ts`, `coach/`, `prompts/`, citation + confidence helpers.
- **`rollups/`** — DAY/WEEK/MONTH/YEAR pre-aggregations for measurements, mood, and medication compliance. Read-swap pattern: probe the rollup, fall back to live SQL on a coverage miss.
- **`notifications/`** — the dispatcher cascade (APNs → Telegram → ntfy → Web Push), per-channel `senders/`, retry policy, VAPID config.
- **`jobs/`** — pg-boss workers: reminders, insight pre-generation, backups, retention sweeps, integration backfills. Recurring work belongs here, not in `scripts/`.
- **`integrations/`**, **`withings/`**, **`whoop/`**, **`fitbit/`** — OAuth clients and sync services for the device providers; `sync/` holds the shared delta-feed plumbing.
- **`analytics/`** — trend calculations, cadence-aware medication `compliance.ts`, correlations.
- **`insights/`**, **`fhir/`**, **`doctor-report-*.ts`** — insight pipeline, FHIR R4 export, client-side doctor-report PDF.
- **`openapi/`** — Zod registry that is the source of truth for `docs/api/openapi.yaml`.
- **`logging/`**, **`observability/`**, **`monitoring/`** — Wide-Event transports and the central redaction denylists (redact at the egress boundary, not the call site).
- **`validations/`** — shared Zod schemas, including the SSRF `isPublicUrl` floor.
- **`i18n/`**, **`tz/`** + **`timezone.ts`**, **`format*.ts`** — translations, timezone helpers (Berlin for display, UTC in DB), locale formatting.
## Conventions
Kebab-case filenames. See [`../../CLAUDE.md`](../../CLAUDE.md) "Code conventions" and "Security-relevant patterns"; the critical-files map there cites the exact entry points. Most modules carry tests in a sibling `__tests__/`.