mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 12:32:43 +00:00
A cluster of related correctness gaps in the compliance denominator and the insight surfaces that read it: - Paused medications. A doctor-ordered pause flipped `active` off and stamped `pausedAt`, but resume nulled `pausedAt`, so the interval was irrecoverable and every paused day became a missed dose after resume — collapsing adherence across the Health Score, the BP gate, the Coach snapshot and the report. Persist pause intervals as durable eras (new `MedicationPauseEra`, migration 0211), close the open era on resume, thread the eras through the compliance context and drop slots inside a paused interval from the denominator. Every compliance call site now fetches and passes the eras. - Health Score eras. The Health-Score fast path was the only compliance caller that skipped the shared schedule select and schedule revisions, so after a schedule edit it scored past days against the current schedule while every other surface used the historical era. Switch it to the shared select and thread revisions (and pause eras) like the canonical path. - Insight bucketing timezone. The per-metric status series bucketed every user in Europe/Berlin, so a near-midnight reading landed in the wrong day and the relative-day phrasing was off for non-Berlin self-hosters. Thread the resolved user timezone and key off `userDayKey`. - Correlation significance. User-facing correlations surfaced from five paired points with strength read straight off the coefficient. Route them through the rigorous engine (at least twenty pairs, Student-t p below 0.05) so small-N coincidences no longer render as confident findings. - Resting-pulse input. The mood-versus-"resting pulse" correlation fed the raw PULSE day-mean, which folds in workout HR, under a "Resting pulse" label. Feed `resolveRestingPulseSeries` (clean RESTING_HEART_RATE, else a daily low-percentile proxy) so the label matches the input.
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_casecolumns via@map(...), encrypted columns mostly suffixed*Encrypted(search the file; there are 24 encrypted column references). Thegenerator clientblock emits to../src/generated/prisma(imported as@/generated/prisma).migrations/— numbered, forward-only SQL migrations (0001_…upward).migration_lock.tomlpins the provider topostgresql.
Migration workflow
# 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:
*Encryptedcolumns are written through@/lib/crypto(AES-256-GCM, versioned key ids); never store plaintext in an encrypted column. Key rotation isscripts/rotate-encryption-key.ts+docs/ops/encryption-key-rotation.md. - The generated client under
src/generated/prismais build output — do not edit it. - Schema-touching changes that affect the API surface must regenerate
docs/api/openapi.yaml(see../CLAUDE.md).
Related: ../src/lib/README.md (db.ts, rollups/), ../docs/ops/ (migrations + backup runbooks).