mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-14 14:40:52 +00:00
feat(measurements): add per-bucket heart-rate min/max to the hourly contract
The v1.19.0 hourly heart-rate bucket (`stats:HKQuantityTypeIdentifierHeartRate:<UTC-hour>`) shipped avg-only: one PULSE row carrying the hour's mean bpm. Add the hour's min/max so a client can render the intra-hour range without re-uploading raw samples. - Two nullable columns on `measurements` (`value_min` / `value_max`), migration 0188. Set only on a well-formed hourly HR bucket row; null for per-sample readings, per-day cumulative totals, and manual entries. - Batch ingest threads the spread through the same unit conversion as the average and persists / overwrites it alongside `value` on the bucket row, pinning it null everywhere else. - The series reader returns the spread for `kind=pulse` (null on a per-sample PULSE row); the OpenAPI Zod contract documents both fields on the batch entry and the series point. The avg path is unchanged.
This commit is contained in:
1 parent
02ce177ac4
commit
868dfb72bd
8 files changed
+286
-3
No files matched your search
@@ -0,0 +1,33 @@
|
||||
-- v1.19.2 (iOS #34 extension) — per-bucket heart-rate spread.
|
||||
--
|
||||
-- v1.19.0 shipped the hourly heart-rate bucket
|
||||
-- (`stats:HKQuantityTypeIdentifierHeartRate:<UTC-hour>`) carrying the
|
||||
-- hour's AVERAGE bpm as one PULSE row. This adds the hour's MIN / MAX bpm
|
||||
-- as two companion columns so a client can render the intra-hour range
|
||||
-- (low/high band around the mean) without iOS re-uploading raw samples.
|
||||
--
|
||||
-- Two additive, nullable columns on `measurements`:
|
||||
--
|
||||
-- * `value_min` — the bucket's minimum bpm.
|
||||
-- * `value_max` — the bucket's maximum bpm.
|
||||
--
|
||||
-- Set ONLY on the hourly heart-rate bucket rows; NULL for every other row
|
||||
-- (per-sample readings, per-day cumulative `stats:` totals, manual
|
||||
-- entries). The series reader hands them through only for the heart-rate
|
||||
-- kind, and the batch ingest persists / overwrites them alongside `value`.
|
||||
--
|
||||
-- Additive; no existing row touched. The columns default to NULL so every
|
||||
-- legacy row and every non-HR-bucket write stays unchanged. Idempotent
|
||||
-- guards (`ADD COLUMN IF NOT EXISTS`) so a rerun is safe on prod.
|
||||
--
|
||||
-- Reversibility (down):
|
||||
-- ALTER TABLE "measurements" DROP COLUMN IF EXISTS "value_min";
|
||||
-- ALTER TABLE "measurements" DROP COLUMN IF EXISTS "value_max";
|
||||
-- The columns are read-additive — dropping them reverts to the avg-only
|
||||
-- v1.19.0 contract.
|
||||
|
||||
ALTER TABLE "measurements"
|
||||
ADD COLUMN IF NOT EXISTS "value_min" DOUBLE PRECISION;
|
||||
|
||||
ALTER TABLE "measurements"
|
||||
ADD COLUMN IF NOT EXISTS "value_max" DOUBLE PRECISION;
|
||||
@@ -1026,6 +1026,16 @@ model Measurement {
|
||||
userId String @map("user_id")
|
||||
type MeasurementType
|
||||
value Float
|
||||
// v1.19.2 (iOS #34 extension) — per-bucket spread for an aggregated row.
|
||||
// Set ONLY on the hourly heart-rate bucket
|
||||
// (`stats:HKQuantityTypeIdentifierHeartRate:<UTC-hour>`), where `value`
|
||||
// is the hour's AVERAGE bpm and these carry the hour's MIN / MAX bpm so a
|
||||
// client can render the intra-hour range without re-uploading raw
|
||||
// samples. NULL for every other row (per-sample readings, per-day
|
||||
// cumulative `stats:` totals, manual entries) — the series reader hands
|
||||
// them through only for the heart-rate kind.
|
||||
valueMin Float? @map("value_min")
|
||||
valueMax Float? @map("value_max")
|
||||
unit String // kg, mmHg, bpm, %, minutes (sleep), steps, mg/dL, kcal, m, ms, mL/(kg·min), celsius
|
||||
source MeasurementSource @default(MANUAL)
|
||||
measuredAt DateTime @map("measured_at")
|
||||
|
||||
Reference in new issue
Block a user