Files
HealthLog/prisma/migrations/0071_v1439_medication_compliance_rollups/migration.sql
T
Marc-André Bombeck d84922cdc3 chore(release): v1.4.39 — mood, medication-compliance, and cumulative-sum rollup tiers
Squashed merge of the v1.4.39 wave work from develop. The release
extends the v1.4.38 fast-path posture to two more endpoints that
still walked the source table on every cold mount and folds a
cumulative `sum_value` column into the existing rollup tier so step /
flight / distance / daylight / active-energy sparklines no longer
re-derive their daily totals in Node.

Raw measurements / mood_entries / medication_intake_events tables are
byte-unchanged. Three new tiers (mood_entry_rollups,
medication_compliance_rollups, measurement_rollups.sum_value) are
derived caches that self-heal via boot-time backfill on first reach.

Migrations 0070, 0071, 0072 are additive only. The sum_value column
add is catalog-only DDL on PostgreSQL 11+ — no table rewrite, writes
resume in milliseconds. No environment-variable change. No API
contract break. No iOS contract change.

Expected wins (live perf-verify rides the post-deploy window):
- /api/mood/analytics cold 12.7 s -> ~200 ms
- /api/medications/intake?scope=compliance cold 3.2 s -> ~200 ms
- /api/dashboard/summary cumulative sparkline ~500 ms -> ~300 ms
- /api/analytics live-fallback row cap 347 k -> ~5 k (425 d cap
  preserves the year-ago baseline tile)

Tests 4 524 -> 4 640 (+116). Typecheck clean. Lint clean.

See CHANGELOG.md for the full v1.4.39 entry.
2026-05-21 07:39:10 +02:00

50 lines
2.0 KiB
SQL

-- v1.4.39 W-MED — persistent medication compliance rollup table.
--
-- Replaces the unbounded MedicationIntakeEvent.findMany walk on
-- `/api/medications/intake?scope=compliance` and the equivalent fan-out
-- inside `computeUserHealthScoreFastPath`. Per-(userId, medicationId,
-- day) stats with scheduled / taken / skipped counts.
--
-- `day` is a TEXT column (YYYY-MM-DD anchored to the user's timezone)
-- rather than a DATE because the day-key has to survive a
-- multi-instance read that may pick a different node than the writer.
-- Storing the user-tz-anchored string removes the per-row tz round-trip
-- the writer would otherwise have to perform.
--
-- Additive only. PK + FK + descending index for the "last N days" read
-- path. IF NOT EXISTS / EXCEPTION guards mirror 0067 / 0069 / 0070.
CREATE TABLE IF NOT EXISTS "medication_compliance_rollups" (
"user_id" TEXT NOT NULL,
"medication_id" TEXT NOT NULL,
"day" TEXT NOT NULL,
"scheduled" INTEGER NOT NULL,
"taken" INTEGER NOT NULL,
"skipped" INTEGER NOT NULL,
"computed_at" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "medication_compliance_rollups_pkey"
PRIMARY KEY ("user_id", "medication_id", "day")
);
CREATE INDEX IF NOT EXISTS "medication_compliance_rollups_user_day_desc_idx"
ON "medication_compliance_rollups" ("user_id", "day" DESC);
DO $$ BEGIN
ALTER TABLE "medication_compliance_rollups"
ADD CONSTRAINT "medication_compliance_rollups_user_id_fkey"
FOREIGN KEY ("user_id") REFERENCES "users"("id")
ON DELETE CASCADE ON UPDATE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
END $$;
DO $$ BEGIN
ALTER TABLE "medication_compliance_rollups"
ADD CONSTRAINT "medication_compliance_rollups_medication_id_fkey"
FOREIGN KEY ("medication_id") REFERENCES "medications"("id")
ON DELETE CASCADE ON UPDATE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
END $$;