Files
HealthLog/prisma/migrations/0087_v156_step_consolidation/migration.sql
T
Marc-André BombeckandClaude Opus 4.7 8528c3b4fe chore(release): v1.5.6
Pure-history medication detail page, legacy step consolidation, and the
finish of the outbound-fetch migration.

- /medications/[id] becomes a read-only history surface; every setting
  moves into a new advanced-settings sheet, and the edit trigger becomes
  a two-option picker. The list page is unchanged.
- A pg-boss job folds pre-v1.5.0 granular step rows into one canonical
  daily total per user per day and soft-deletes the originals; migration
  0087 adds a partial index for the converging discovery scan.
- Every remaining server-side fetch routes through safeFetch (Withings,
  Codex OAuth + SSE, bug-report, Umami, GlitchTip, Loki); a new
  healthlog/safe-fetch-required ESLint rule guards the boundary.
- Fixes: intake-edit dialog seeded from real values, consolidation skips
  a unique-constraint day instead of stranding it, avatar upload reads
  the body once under a bounded cap, egress lint rejects absolute URLs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-29 22:07:10 +02:00

39 lines
2.1 KiB
SQL

-- v1.5.6 — accelerate the legacy step-consolidation discovery query.
--
-- The boot-time consolidation pass (`enqueueBootTimeStepConsolidation`
-- in src/lib/jobs/step-consolidation.ts) repeatedly scans for users
-- still holding live pre-v1.5.0 granular step rows: `ACTIVITY_STEPS`
-- rows that are not tombstoned and whose `external_id` is NULL or does
-- not carry the `stats:HKQuantityTypeIdentifierStepCount:` daily-total
-- prefix. On an account with a multi-year HealthKit history that
-- predicate matches hundreds-of-thousands of rows before the
-- consolidation tombstones them.
--
-- A partial index keyed on the legacy-candidate predicate keeps both
-- the per-boot discovery scan and the per-user `findMany` cheap, and —
-- because the index only covers `deleted_at IS NULL` rows — it shrinks
-- to (eventually) empty as the pass converges, so it carries no
-- steady-state write cost once every legacy row is consolidated.
--
-- Additive + order-safe: a pure `CREATE INDEX IF NOT EXISTS`, no column
-- add, no backfill, no rewrite of `measurements`.
--
-- Lock note (conscious trade-off): this is a plain, non-`CONCURRENTLY`
-- index build, so it runs inside Prisma's migration transaction and
-- holds an ACCESS EXCLUSIVE lock on `measurements` for the duration of
-- the build — reads and writes to the table block until it completes.
-- The `deleted_at IS NULL` + `type = 'ACTIVITY_STEPS'` partial predicate
-- keeps the index tiny (most tenants carry no legacy step rows at all,
-- and the covered set shrinks to empty as the pass converges), so on a
-- typical self-host the build is sub-second and the lock is not felt.
-- The largest multi-year HealthKit tenants are the ones who both need
-- this index and would feel a longer lock; for those, run the deploy at
-- a low-traffic window. A `CONCURRENTLY` build cannot run inside the
-- migration transaction and is not warranted given the partial-index
-- size on the overwhelming majority of deployments.
CREATE INDEX IF NOT EXISTS "measurements_legacy_step_consolidation_idx"
ON "measurements" ("user_id", "measured_at")
WHERE "type" = 'ACTIVITY_STEPS'
AND "deleted_at" IS NULL;