mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 12:32:43 +00:00
Post-publish verify proves the published image boots. Nothing proved that
on a running instance a person can sign in, write a reading and read it
back — which is exactly the shape of the defects this line keeps
rediscovering: a value written and never read.
`scripts/synthetic-journey.mjs` walks that journey in plain Node 22 with no
dependencies, so it runs from a workstation, a runner or the deploy host.
It warms `/`, `/api/health`, `/api/version` and the measurements list first
and discards those timings (the first hit on each route after a deploy is a
cold start), then asserts five legs in order: the served version equals the
expected one, the password flow signs in through a cookie jar, a weight
reading is written with an Idempotency-Key, the same row reads back with
its value, unit and source, and the reversible delete leaves the account
clean. One line per leg with the elapsed time; the first failure ends the
run non-zero with the status and a body excerpt that has every token shape
redacted out of it.
The workflow is `workflow_dispatch` only, with `base_url` and
`expected_version` as inputs and the credentials read from repository
secrets. It is deliberately not wired into the deploy path: the target
instance and the secrets are the maintainer's call.
Mutation proof, against a production build served from
`.next/standalone/server.js` on a throwaway Postgres.
Green:
warm 35 ms (discarded)
ok version 2 ms serves 1.38.13
ok sign in 78 ms session cookie held
ok write 64 ms wrote cmtup9lwu0007zhovn0mxajdz
ok read back 8 ms 77.7 kg (MANUAL)
ok delete 27 ms account left clean
synthetic journey green
Read leg broken deliberately — the same server behind a throwaway forwarder
that empties the `GET /api/measurements` list and changes nothing else:
ok version 4 ms serves 1.38.13
ok sign in 38 ms session cookie held
ok write 40 ms wrote cmtupa4ck000gzhovwnij64fz
FAILED read back 8 ms read back: the list came back without the reading
status 200
body {"data":{"measurements":[],"meta":{"total":0}},"error":null}
synthetic journey RED on "read back"
Version leg broken the same way, by asking the instance for the previous
tag:
FAILED version 3 ms version: instance serves "1.38.13", expected "v1.38.12"
synthetic journey RED on "version"
`--self-test` carries that proof in the repository: it runs the journey
against an in-process instance nine times, once with nothing broken and
once per broken leg, and fails if a broken leg still comes back green. The
workflow runs it before it touches the real instance.
Gates: typecheck, `node --check`, lint (the three known warnings, no
errors), prettier, the workflow and CI-determinism guards.
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-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/.