feat: baseline-drift, breathing-screening and lab-change insight cards

Add three read-only awareness cards to the Insights overview, each drawn
off an existing engine and each honest about empty state — the section
un-mounts rather than surfacing a husk.

- Health status: surfaces what is drifting from the user's own normal by
  folding the personal-band deviations (coincident-deviation engine) with
  the dated, sustained level shifts (changepoint detector) at
  GET /api/insights/health-status. Awareness only, never a diagnosis.
- Breathing screening: summarises the last 30 nights of the per-night
  sleep-breathing-disturbance index plus device-flagged events at
  GET /api/insights/breathing-screening. Mirrors the device's own
  classification and states plainly that it is a screening signal, not a
  diagnosis — discuss with a clinician.
- Lab changes: pairs the two most-recent numeric lab panels and reports
  each shared analyte's signed delta and reference-band standing at
  GET /api/insights/labs-changes. Neutral framing only.

Each reshaping helper is pure and unit-tested for its present/absent
states. Register the three sections in the insights-layout universe so
they merge in as default-visible, wire them into the overview and the
edit-mode title map, add the query-factory keys, document the routes in
the OpenAPI contract, and translate every new string across all six
locales.
This commit is contained in:
Marc-André Bombeck committed 2026-06-28 03:20:49 +02:00
1 parent 31c35baec2
commit ec3fcea84f
27 files changed
+2148 -13

No files matched your search

+453
View File
@@ -44,6 +44,7 @@ tags:
- name: Illness
- name: Admin
- name: Meta
- name: Hydration
paths:
/api/cycle/day-logs:
get:
@@ -2087,6 +2088,7 @@ paths:
- SLEEP_SCORE
- BODY_TEMPERATURE_DEVIATION
- RESILIENCE
- WATER_INTAKE
- in: query
name: from
schema:
@@ -2276,6 +2278,7 @@ paths:
- SLEEP_SCORE
- BODY_TEMPERATURE_DEVIATION
- RESILIENCE
- WATER_INTAKE
value:
type: number
measuredAt:
@@ -5770,6 +5773,7 @@ paths:
- SLEEP_SCORE
- BODY_TEMPERATURE_DEVIATION
- RESILIENCE
- WATER_INTAKE
description: "The measurement type to read (single metric — no fan-out). Closed enum: an unknown type 422s."
required: true
description: "The measurement type to read (single metric — no fan-out). Closed enum: an unknown type 422s."
@@ -6178,6 +6182,60 @@ paths:
"401": *a1
"422": *a3
"429": *a4
/api/insights/health-status:
get:
tags:
- Insights
summary: Baseline-drift health status
description: Surfaces vitals drifting from the user's personal normal — out-of-band deviations from the
personal-baseline engine plus dated, sustained level shifts from the changepoint detector. Pure compute over the
rollup tier; awareness only, never a diagnosis. Requires the insights module. Cookie or Bearer auth.
responses:
"200":
description: The drift summary.
content:
application/json:
schema:
$ref: "#/components/schemas/InsightsHealthStatusEnvelope"
"401": *a1
"422": *a3
"429": *a4
/api/insights/breathing-screening:
get:
tags:
- Insights
summary: Sleep-breathing screening signal
description: Summarises the last ~30 nights of the per-night sleep-breathing-disturbance index plus device-flagged
events into a calm awareness read. A screening signal only — never a HealthLog diagnosis. Requires the insights
module. Cookie or Bearer auth.
responses:
"200":
description: The breathing-screening summary.
content:
application/json:
schema:
$ref: "#/components/schemas/InsightsBreathingScreeningEnvelope"
"401": *a1
"422": *a3
"429": *a4
/api/insights/labs-changes:
get:
tags:
- Insights
summary: What changed since your last lab panel
description: Pairs the two most-recent numeric lab panels and reports each shared analyte's signed delta plus its
reference-band standing. Absent when there are fewer than two panels or no analyte is shared. Neutral framing,
never a diagnosis. Cookie or Bearer auth.
responses:
"200":
description: The lab-change summary.
content:
application/json:
schema:
$ref: "#/components/schemas/InsightsLabsChangesEnvelope"
"401": *a1
"422": *a3
"429": *a4
/api/mood/tags:
get:
tags:
@@ -7945,6 +8003,44 @@ paths:
"401": *a1
"422": *a3
"429": *a4
/api/hydration:
get:
tags:
- Hydration
summary: Today's hydration total vs goal
description: Sums the calling user's WATER_INTAKE measurements for the current local day and compares them against the
per-user goal (default 2000 ml).
responses:
"200":
description: Today's hydration summary.
content:
application/json:
schema:
$ref: "#/components/schemas/HydrationTodayEnvelope"
"401": *a1
"422": *a3
"429": *a4
patch:
tags:
- Hydration
summary: Set the daily hydration goal
description: Updates the per-user daily hydration goal in millilitres.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/HydrationGoalRequest"
responses:
"200":
description: Goal updated.
content:
application/json:
schema:
$ref: "#/components/schemas/HydrationGoalEnvelope"
"401": *a1
"422": *a3
"429": *a4
components:
schemas:
EncryptedExportRequest:
@@ -9245,6 +9341,10 @@ components:
- cycle-summary
- signals
- rhythm-events
- hydration
- health-status
- breathing
- labs-changes
visible:
type: boolean
order:
@@ -9654,6 +9754,17 @@ components:
- updatedAt
description: Resumable module-tour progress point. `lastStopId` seeds the resume index; `status` is the running/terminal
state.
HydrationGoalRequest:
type: object
properties:
goalMl:
type: integer
minimum: 250
maximum: 8000
description: Daily hydration goal in millilitres.
required:
- goalMl
description: Set the per-user daily hydration goal (ml).
MedicationTreatmentClass:
type: string
enum:
@@ -12255,6 +12366,7 @@ components:
- SLEEP_SCORE
- BODY_TEMPERATURE_DEVIATION
- RESILIENCE
- WATER_INTAKE
value:
type: number
unit:
@@ -12571,6 +12683,7 @@ components:
- SLEEP_SCORE
- BODY_TEMPERATURE_DEVIATION
- RESILIENCE
- WATER_INTAKE
additionalProperties:
type: array
items:
@@ -12648,6 +12761,7 @@ components:
- SLEEP_SCORE
- BODY_TEMPERATURE_DEVIATION
- RESILIENCE
- WATER_INTAKE
value:
type: number
description: Daily mean (spot metrics) or SUM (cumulative).
@@ -12746,6 +12860,7 @@ components:
- SLEEP_SCORE
- BODY_TEMPERATURE_DEVIATION
- RESILIENCE
- WATER_INTAKE
description: Per-type daily series, keyed by MeasurementType.
required:
- series
@@ -12979,6 +13094,7 @@ components:
- SLEEP_SCORE
- BODY_TEMPERATURE_DEVIATION
- RESILIENCE
- WATER_INTAKE
value:
type: number
unit:
@@ -20663,6 +20779,244 @@ components:
- windowDays
- interpretation
additionalProperties: false
InsightsHealthStatusEnvelope:
type: object
properties:
data:
$ref: "#/components/schemas/InsightsHealthStatus"
error:
type: "null"
meta:
type: object
properties:
requestId:
type: string
additionalProperties: false
required:
- data
- error
additionalProperties: false
InsightsHealthStatus:
type: object
properties:
present:
type: boolean
description: True when at least one deviation or shift is surfaced.
deviations:
type: array
items:
type: object
properties:
type:
type: string
description: MeasurementType token.
value:
type: number
description: Today's value.
center:
type: number
description: Personal band center (median).
low:
type: number
high:
type: number
direction:
type: string
enum:
- above
- below
required:
- type
- value
- center
- low
- high
- direction
additionalProperties: false
shifts:
type: array
items:
type: object
properties:
metric:
type: string
description: MeasurementType token.
breakDate:
type: string
description: YYYY-MM-DD of the new level's first day.
beforeMean:
type: number
afterMean:
type: number
direction:
type: string
enum:
- up
- down
required:
- metric
- breakDate
- beforeMean
- afterMean
- direction
additionalProperties: false
generatedAt:
type: string
description: ISO-8601 instant the read was computed.
required:
- present
- deviations
- shifts
- generatedAt
additionalProperties: false
description: Vitals drifting from the user's personal normal — band deviations plus dated, sustained level shifts.
Awareness only, never a diagnosis.
InsightsBreathingScreeningEnvelope:
type: object
properties:
data:
$ref: "#/components/schemas/InsightsBreathingScreening"
error:
type: "null"
meta:
type: object
properties:
requestId:
type: string
additionalProperties: false
required:
- data
- error
additionalProperties: false
InsightsBreathingScreening:
type: object
properties:
present:
type: boolean
nights:
type: integer
minimum: -9007199254740991
maximum: 9007199254740991
description: Nights with a per-night index reading.
recentMeanIndex:
anyOf:
- type: number
- type: "null"
description: Mean of the index readings (lower-better); null when none.
trend:
anyOf:
- type: string
enum:
- up
- down
- stable
- type: "null"
description: Recent index vs the prior window; null when too few nights.
eventCount:
type: integer
minimum: -9007199254740991
maximum: 9007199254740991
description: Device-flagged breathing-disturbance / apnea events.
classification:
anyOf:
- type: string
enum:
- not-elevated
- elevated
- type: "null"
description: The device's own classification; null when no data.
generatedAt:
type: string
required:
- present
- nights
- recentMeanIndex
- trend
- eventCount
- classification
- generatedAt
additionalProperties: false
description: Sleep-breathing-disturbance screening signal — a screening signal only, never a diagnosis.
InsightsLabsChangesEnvelope:
type: object
properties:
data:
$ref: "#/components/schemas/InsightsLabsChanges"
error:
type: "null"
meta:
type: object
properties:
requestId:
type: string
additionalProperties: false
required:
- data
- error
additionalProperties: false
InsightsLabsChanges:
type: object
properties:
present:
type: boolean
latestDate:
anyOf:
- type: string
- type: "null"
description: YYYY-MM-DD of the most-recent panel.
previousDate:
anyOf:
- type: string
- type: "null"
description: YYYY-MM-DD of the prior panel.
changes:
type: array
items:
type: object
properties:
analyte:
type: string
unit:
type: string
latest:
type: number
previous:
type: number
delta:
type: number
description: Signed latest − previous.
direction:
type: string
enum:
- up
- down
- flat
status:
type: string
enum:
- in-range
- below
- above
- unknown
required:
- analyte
- unit
- latest
- previous
- delta
- direction
- status
additionalProperties: false
generatedAt:
type: string
required:
- present
- latestDate
- previousDate
- changes
- generatedAt
additionalProperties: false
description: Per-analyte change between the two most-recent numeric lab panels. Neutral framing, never a diagnosis.
MoodTagTreeEnvelope:
type: object
properties:
@@ -23024,6 +23378,101 @@ components:
- progress
additionalProperties: false
description: The persisted completion flag and resume point after the write.
HydrationTodayEnvelope:
type: object
properties:
data:
$ref: "#/components/schemas/HydrationToday"
error:
type: "null"
meta:
type: object
properties:
requestId:
type: string
additionalProperties: false
required:
- data
- error
additionalProperties: false
HydrationToday:
type: object
properties:
date:
type: string
description: ISO-8601 start of the user's local day.
totalMl:
type: number
description: Today's summed intake in ml.
goalMl:
type: number
description: Effective daily goal in ml.
percent:
type: number
description: Progress toward the goal, capped at 100.
rawPercent:
type: number
description: Uncapped progress; can exceed 100.
met:
type: boolean
description: Whether the day's total reached the goal.
remainingMl:
type: number
description: Remaining ml to the goal (0 once met).
entries:
type: array
items:
type: object
properties:
id:
type: string
value:
type: number
description: Logged amount in millilitres.
measuredAt:
type: string
description: ISO-8601 instant the entry was logged.
required:
- id
- value
- measuredAt
additionalProperties: false
required:
- date
- totalMl
- goalMl
- percent
- rawPercent
- met
- remainingMl
- entries
additionalProperties: false
description: Today's water-intake total vs the user's daily goal.
HydrationGoalEnvelope:
type: object
properties:
data:
$ref: "#/components/schemas/HydrationGoalResponse"
error:
type: "null"
meta:
type: object
properties:
requestId:
type: string
additionalProperties: false
required:
- data
- error
additionalProperties: false
HydrationGoalResponse:
type: object
properties:
goalMl:
type: number
required:
- goalMl
additionalProperties: false
MedicationScheduleOutput:
type: object
properties:
@@ -23201,6 +23650,10 @@ components:
- cycle-summary
- signals
- rhythm-events
- hydration
- health-status
- breathing
- labs-changes
visible:
type: boolean
order: