From 08cf85496010d1ba33e03ed05c0fb21bd5bdcf7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Thu, 21 May 2026 11:52:54 +0200 Subject: [PATCH] fix(dashboard-summary): recompute compliance rollup after bulk projection backfill Mirrors the intake-route call site (v1.4.40 close of v1.4.39.4 hook gap). `projectAndReadTodaysIntakes` runs the same idempotent projection helper the intake route uses; without this hook the compliance rollup stayed pre-projection on the second call site too. Fires `recomputeMedicationComplianceForEvent` once per distinct `(medication_id, dayKey)` after the bulk `createMany`, best-effort inside the helper's try/catch so a populator hiccup doesn't surface as a 5xx on the dashboard summary. --- src/app/api/dashboard/summary/route.ts | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/app/api/dashboard/summary/route.ts b/src/app/api/dashboard/summary/route.ts index d21728721..78038ddf7 100644 --- a/src/app/api/dashboard/summary/route.ts +++ b/src/app/api/dashboard/summary/route.ts @@ -49,6 +49,7 @@ import { defaultLocale, type Locale } from "@/lib/i18n/config"; import { userDayKey, DEFAULT_TIMEZONE } from "@/lib/tz/resolver"; import { cached, caches, type ServerCache } from "@/lib/cache/server-cache"; import { expandTodayIntakes } from "@/lib/medication-schedule"; +import { recomputeMedicationComplianceForEvent } from "@/lib/medications/compliance-rollups"; const SPARK_DAYS = 7; const STREAK_WINDOW_DAYS = 365; @@ -349,6 +350,30 @@ async function projectAndReadTodaysIntakes( })), skipDuplicates: true, }); + + // v1.4.40 — close the compliance-rollup hook gap from v1.4.39.4. + // Mirrors the intake-route call site: after a bulk projection + // backfill, fire one rollup recompute per distinct + // `(medication_id, dayKey)` so the rollup row reflects the new + // `scheduled` count before the next read. Best-effort: errors + // stay caught inside the helper so a populator hiccup doesn't + // surface as a 5xx on the dashboard summary. + const seenDayKeys = new Set(); + const recomputeJobs: Array> = []; + for (const m of missing) { + const key = `${m.medicationId}|${m.scheduledFor.toISOString().slice(0, 10)}`; + if (seenDayKeys.has(key)) continue; + seenDayKeys.add(key); + recomputeJobs.push( + recomputeMedicationComplianceForEvent({ + userId, + medicationId: m.medicationId, + scheduledFor: m.scheduledFor, + tz: userTz, + }), + ); + } + await Promise.all(recomputeJobs); } }