Files
HealthLog/prisma/migrations/0411_encrypt_insights_cached_text/migration.sql
T
Marc-André Bombeck 9c89503019 fix(migrations): bound 0412's lock wait where it takes effect and retry a lock timeout on boot
migrate deploy runs a migration file statement by statement, so the
top-level SET LOCAL lock_timeout in 0412 did nothing: the migration
waited as long as the lock was held, with every write to measurements
queued behind it, and a file that failed half-way stayed half-applied.
0412 now takes its locks inside one DO block with a statement-scoped
timeout, which rolls back whole, after an idempotent CREATE OR REPLACE.

The entrypoint runs migrate deploy through scripts/migrate-deploy.mjs.
A 55P03 failure of a migration marked -- @retry-on-lock-timeout is
marked rolled back and retried after 15/30/60/120/240 s, read from
Prisma's report or, after P3009, from the stored row. Every other
failure stays fatal. A guard holds migrations to the shape that makes
the marker true, and 0411/0413 add their columns with IF NOT EXISTS so
a manual re-run is safe too.
2026-10-20 10:45:14 +02:00

27 lines
1.4 KiB
SQL

-- The cached AI insights payload moves to AES-256-GCM at rest.
--
-- `users.insights_cached_text` held the model's last full reading of the
-- account in the clear: the daily briefing, the per-domain status text and the
-- recommendations. It was the last readable column of that kind on the user
-- row. From this release every write goes to `insights_cached_text_encrypted`
-- (binary layout, purpose-bound label) and leaves the readable column NULL.
--
-- SQL cannot encrypt, so this migration only adds the ciphertext column and
-- the discovery index. The boot-time `free-text-encryption-backfill` job seals
-- the existing rows one at a time and nulls the readable value in the same
-- transaction; it is fail-closed, so a missing or malformed key leaves the row
-- untouched and the job retries. Readers fall back to the readable column until
-- the backfill has reached a row. The readable column is dropped in a later
-- release, once the backfill reports nothing left on every instance.
--
-- Additive only: no table rewrite, no data change.
ALTER TABLE "users" ADD COLUMN IF NOT EXISTS "insights_cached_text_encrypted" BYTEA;
-- Partial index on exactly the backfill's discovery predicate, so the boot
-- scan is index-only and shrinks to nothing as the backfill converges (the
-- 0357 precedent).
CREATE INDEX IF NOT EXISTS "users_insights_cached_text_backfill_idx"
ON "users" ("id")
WHERE "insights_cached_text" IS NOT NULL;