refactor(measurements): move the list modes and the hand-entry writes out of their route

GET /api/measurements keeps authentication and the query refusal and hands
the validated query to measurementListResponse (lib/measurements/list),
which tries the list modes in their old order. POST keeps authentication,
the body, the bridge-source refusal and the three validation answers; the
single and combined writes with their shared tail move to
lib/measurements/create/create-readings.ts, the named sleep-stage write to
create-sleep-stage.ts. The route falls from 938 to 274 lines.

The parity walk recorded before the move is unchanged; the guards that name
the measurement writers, the write tail and the bounded reads follow the
code.
This commit is contained in:
Marc-André Bombeck committed 2026-10-23 12:38:27 +02:00
1 parent 05b9697848
commit 9725ba394d
7 files changed
+809 -707

No files matched your search

@@ -67,6 +67,8 @@ const SCOPED_DIRS = [
// Request-handler logic moved out of its route into a service keeps the
// route's scope.
"lib/measurements/batch-ingest/",
"lib/measurements/create/",
"lib/measurements/list/measurement-list.ts",
];
/** Types a device writes at sampling rate rather than a few times a day. */
@@ -108,7 +110,7 @@ const ALLOWED: Record<string, string> = {
"The 30-day per-context glucose summary, the same window and bound as the dashboard and coach glucose panels: at a sensor's fixed rate, below 45 000 rows.",
"lib/measurements/batch-ingest/write-measurements.ts::p.row.type as MeasurementType":
"Cross-source merge probe: one ±tolerance window around each posted reading's instant, so the rows found are bounded by the batch size.",
"app/api/measurements/route.ts::(shorthand)":
"lib/measurements/create/create-sleep-stage.ts::(shorthand)":
"Cross-source merge probe for one posted sleep segment: SLEEP_DURATION in a ±tolerance window around its end.",
"lib/targets/build-response.ts::{ in: recentTypes":
"Thirty days of weight, blood pressure, resting heart rate, body fat and steps (drained to one row per day). PULSE is filtered out of `recentTypes` and folds in SQL.",
@@ -68,7 +68,8 @@ const WRITERS: Record<string, Disposition> = {
"lib/measurements/reconcile-external-measurement.ts": { kind: "gate" },
// ── Person-driven write paths, validated ──────────────────────────────
"app/api/measurements/route.ts": {
// The hand-entry writes behind `POST /api/measurements`.
"lib/measurements/create/create-readings.ts": {
kind: "upstream",
validatedIn: "lib/validations/measurement.ts",
},
@@ -54,7 +54,7 @@ const WRITE_SITES: Record<string, string> = {
"lib/measurements/batch-ingest/write-measurements.ts": TAIL_VIA(
"lib/measurements/batch-ingest/tail.ts",
),
"app/api/measurements/route.ts": TAIL,
"lib/measurements/create/create-readings.ts": TAIL,
"app/api/mental-health/assessments/route.ts": TAIL,
"lib/insights/score-row.ts": TAIL,
"lib/mcp/writes.ts": TAIL,