mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 13:01:00 +00:00
feat(arrivals): add the data-arrival event spine
Every ingest path in the product can now emit a typed, salience-classified event into pg-boss, consumed by one worker that claims a durable per-day reaction marker and fans out to the reaction surfaces. The recency classifier runs at the seam, before anything is enqueued, so a mass backfill — a multi-year Apple Health export, a provider re-sync, a 30-day catch-up — emits nothing at all. Non-salient writes are annotated and dropped. The worker makes no provider call by construction: it imports no provider module, writes only markers, and enqueues nothing that is not budget-gated downstream. Business refusals return a status rather than throwing, so a refusal is never retried against a ceiling that will not move until the local day rolls over. Seams: sleep (one hook, inherited by all seven transports), workouts (the batch route, the four provider syncs, the export importer), weight and blood pressure (both measurement routes), labs (manual, OCR commit, document fact commit). The provider workout syncs could not previously tell a created row from an updated one, so a re-sync of a recent session would have re-fired on every poll; they now recover the distinction from the row the upsert already returns. Reaction lines are AES-256-GCM at rest, following the InsightNarrative precedent, and the column is registered for key rotation. Markers are pruned after 14 days by a daily maintenance job.
This commit is contained in:
1 parent
571e415eaa
commit
5d62236412
25 files changed
+1302
-28
No files matched your search
@@ -25,6 +25,7 @@ import { auditLog } from "@/lib/auth/audit";
|
||||
import { prisma } from "@/lib/db";
|
||||
import { withIdempotency } from "@/lib/idempotency";
|
||||
import { enqueueReminderSatisfy } from "@/lib/jobs/reminder-satisfy";
|
||||
import { emitDataArrival } from "@/lib/arrivals/emit-shared";
|
||||
import { resolveOrMintBiomarker } from "@/lib/labs/biomarker-store";
|
||||
import { serialiseLabResult } from "@/lib/labs/serialise";
|
||||
import {
|
||||
@@ -214,6 +215,24 @@ async function commitOcrRows(request: NextRequest) {
|
||||
fireAndForget(enqueueReminderSatisfy(user.id), {
|
||||
action: "reminder.satisfy.enqueue",
|
||||
});
|
||||
|
||||
// v1.31.0 — the labs arm of the data-arrival spine. This seam DOES know
|
||||
// its whole panel (the commit builds a per-row `linkable` list), so it
|
||||
// emits once with the newest draw date and the true inserted count rather
|
||||
// than leaning on the singleton key to collapse per-row emits.
|
||||
const newestTakenAt = linkable.reduce<Date | null>(
|
||||
(acc, r) => (!acc || r.takenAt > acc ? r.takenAt : acc),
|
||||
null,
|
||||
);
|
||||
if (newestTakenAt) {
|
||||
void emitDataArrival({
|
||||
userId: user.id,
|
||||
kind: "labs_panel",
|
||||
newestSampleAt: newestTakenAt,
|
||||
insertedCount: inserted.length,
|
||||
source: "ocr",
|
||||
}).catch(() => {});
|
||||
}
|
||||
}
|
||||
|
||||
return apiSuccess({ inserted, skipped });
|
||||
|
||||
@@ -14,6 +14,7 @@ import { auditLog } from "@/lib/auth/audit";
|
||||
import { prisma } from "@/lib/db";
|
||||
import { withIdempotency } from "@/lib/idempotency";
|
||||
import { enqueueReminderSatisfy } from "@/lib/jobs/reminder-satisfy";
|
||||
import { emitDataArrival } from "@/lib/arrivals/emit-shared";
|
||||
import { resolveOrMintBiomarker } from "@/lib/labs/biomarker-store";
|
||||
import {
|
||||
type ResolvedBiomarker,
|
||||
@@ -276,5 +277,18 @@ async function postLabResult(request: NextRequest) {
|
||||
action: "reminder.satisfy.enqueue",
|
||||
});
|
||||
|
||||
// v1.31.0 — the labs arm of the data-arrival spine. A "panel" has no
|
||||
// first-class entity in the schema (it is a nullable label plus a `takenAt`),
|
||||
// so the day-scoped singleton key IS the panel grouping: pasting twelve
|
||||
// markers from one draw fires twelve emits that collapse into one arrival.
|
||||
void emitDataArrival({
|
||||
userId: user.id,
|
||||
kind: "labs_panel",
|
||||
newestSampleAt: created.takenAt,
|
||||
insertedCount: 1,
|
||||
refId: created.panel ?? undefined,
|
||||
source: "manual",
|
||||
}).catch(() => {});
|
||||
|
||||
return apiSuccess(serialiseLabResult(created, biomarker), 201);
|
||||
}
|
||||
Reference in new issue
Block a user