mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 12:32:43 +00:00
Nine visit routes and five practitioner routes, all classified under the existing profile domain and each reviewed into the frozen sharing literal with the sentence that argues for it. An address book of a person's own doctors is record content, not account configuration: it names no credential, no integration and no notification channel, which is the fence that classification turns on. The eight sharing domains are unchanged. Link and unlink stay bare, matching document link and unlink, and the pair is revisited as one decision later. Nothing is a required field. A visit saves with a date and nothing else. Every id a body may carry is re-narrowed to the caller before anything is written, and an unknown link id never blocks a save. A booked visit mints exactly one reminder on the existing engine with the new origin, and the appointment half is the part worth reading twice. Both cadence columns stay null, which is the schema's one-shot, so the first due instant is stamped directly and the never-nag property is structural rather than guarded: after it fires, the cadence helper has no occurrence to return. Rescheduling re-anchors that row and never mints a second, which the tests assert by counting rows rather than by checking the date moved. Filing a visit as done closes the checkup it was filed against, on the transition rather than on every later edit. Writing the test first found that: satisfying is forward-only, so re-saving a completed visit was pushing the checkup's next due date out again as if the person had been a second time. An appointment must appear on no preventive-care surface, and that is four separate reads, one of them in the assistant tooling. Each carries the exclusion, a guard proves all four by source text with a non-zero match count, and the reminder mapper refuses such a row outright — so a read site that loses its filter fails loudly instead of showing an appointment as a checkup. The published origin enum is untouched.
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— theapiHandlerwrapper 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/— the only legal source of TanStack QueryqueryKey/mutationKeyarrays (enforced by an ESLint rule); per-feature files behind theindex.tsbarrel.safe-fetch.ts— the one documented outbound-egress entry (redirect: "manual"+ timeout; optional connect-time DNS-rebinding pin). Rawfetch(underlib/+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-channelsenders/, retry policy, VAPID config.jobs/— pg-boss workers: reminders, insight pre-generation, backups, retention sweeps, integration backfills. Recurring work belongs here, not inscripts/.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 medicationcompliance.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 fordocs/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 SSRFisPublicUrlfloor.i18n/,tz/+timezone.ts,format*.ts— translations, timezone helpers (Berlin for display, UTC in DB), locale formatting.
Conventions
Kebab-case filenames. See ../../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__/.