mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 04:32:42 +00:00
The title of a Coach conversation is the first 80 characters of the opening message, and the note on a custom-metric reading is free text; both were stored readable while every other note was encrypted. Migration 0357 adds coach_conversations.title_encrypted and custom_metric_entries.note_encrypted (the title loses its NOT NULL) plus partial indexes on the backfill's discovery predicate. Every writer now stores ciphertext only: conversation create, proactive nudge, reminder surfacing, rename, entry create and edit, and both restore formats. Readers prefer the ciphertext and fall back to the old column for rows not yet migrated; a ciphertext that does not open throws instead of falling back. The history title search decrypts in memory, since SQL can no longer match the title. free-text-encryption-backfill is a boot-time, idempotent pg-boss job (staggered past the startup storm, daily discovery tick) that seals each remaining readable value and nulls it in one transaction per row. A pass that sees a row twice stops with an error instead of looping. Both columns are registered for key rotation (registry, CLI script, and the in-app rotation that walks the registry). A disaster-recovery backup carries ciphertext only, sealing a not-yet-migrated row on the way out; a portable export carries readable text. The old columns are marked for removal in a later release.
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
From a source checkout:
pnpm dlx tsx scripts/<file>.ts
The production image intentionally removes npm, pnpm, and Corepack. Only
container-safe scripts named by an operator runbook use its pinned
healthlog-tsx launcher; scripts that import the full application dependency
graph must run from a source checkout. scripts/ is excluded from the project
typecheck.
What lives here
generate-openapi.ts— emitsdocs/api/openapi.yamlfrom 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 againstenv-manifest.json(pnpm check-env); wired into CI.assert-deploy.ts— post-deploy/api/versionassertion.rotate-encryption-key.ts— AES-256-GCM key rotation; seedocs/ops/encryption-key-rotation.md.restore-backup.ts— restore an off-host AES-GCM backup from an S3-compatible bucket.repair-apple-health-distance.ts— repair walking-distance rows theexport.zipimport stored 1000x too small; dry-run by default, seedocs/ops/apple-health-distance-repair.md.repair-intake-anomalies.ts— repair historic medication-ledger defects (duplicate dose-slot rows, implausibletaken_at); dry-run by default, seedocs/ops/intake-repair.md.backfill-rollups.ts,drain-per-sample-cumulative.ts,backfill-mood-note-column.ts— historical data backfills (note: the boot-timerollup-full-backfillqueue 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) beforedocker 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 "Tests and commands" + "Self-hosting gotchas". Operator runbooks that drive these scripts live in ../docs/ops/.