fix(medications-intake): recompute compliance rollup after bulk projection backfill

Closes the v1.4.39.4 hook gap surfaced by the QA reconcile pass. The
`scope=today` branch's bulk `createMany` mints fresh
`(medicationId, scheduledFor)` PENDING rows when the morning
projection lands; without this hook the compliance rollup for the
affected `(user, medication, day)` tuples stays at its pre-projection
`scheduled` count, inflating the apparent compliance % until the user
actually logs against the new row.

Fires `recomputeMedicationComplianceForEvent` once per distinct
`(medication_id, dayKey)` (coalesced by Set) so a 5-meds-3-times-a-
day projection drops 15 createMany rows down to ≤3 recompute round-
trips. Best-effort: errors stay caught inside the helper so a
populator hiccup doesn't surface as a 5xx on the intake request.
This commit is contained in:
Marc-André Bombeck committed 2026-05-21 11:52:42 +02:00
1 parent ca7d00ffbf
commit de1e65d4a1
1 file changed
+28
+28
View File
@@ -156,6 +156,34 @@ export const GET = apiHandler(async (request: NextRequest) => {
// structural backstop, this is the defense-in-depth.
skipDuplicates: true,
});
// v1.4.40 — close the compliance-rollup hook gap from v1.4.39.4.
// The bulk projection mints fresh `(medicationId, scheduledFor)`
// rows in PENDING state; without this hook the rollup for the
// affected `(user, medication, day)` tuples stays at its previous
// (pre-projection) `scheduled` count, which inflates the apparent
// compliance % until the user actually logs against the new
// row. Coalesce by `(medicationId, dayKey)` so we fire one
// recompute per distinct day-tuple instead of one per row.
// Best-effort: errors stay caught inside the helper so a
// populator hiccup doesn't surface as a 5xx on the intake
// request. Mirror call site in `dashboard/summary/route.ts`.
const seenDayKeys = new Set<string>();
const recomputeJobs: Array<Promise<void>> = [];
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: user.id,
medicationId: m.medicationId,
scheduledFor: m.scheduledFor,
tz: userTz,
}),
);
}
await Promise.all(recomputeJobs);
}
const events = await prisma.medicationIntakeEvent.findMany({