From ad471a511005e8c740d747fd72aa89c97cf09d25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Tue, 2 Jun 2026 18:39:53 +0200 Subject: [PATCH] docs(planning): refresh roadmap and state to the current release line --- .planning/ROADMAP.md | 362 +++++++++++++------------------------------ .planning/STATE.md | 318 ++++++++++++------------------------- 2 files changed, 203 insertions(+), 477 deletions(-) diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 9253c12ec..8e19fa7e3 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -1,270 +1,124 @@ -# HealthLog v1.4.24 — roadmap +# HealthLog — roadmap -Milestone: **v1.4.24 — pre-iOS final polish** (not yet kicked off) -Latest tag at start: v1.4.23 (live in prod) +Current line: **v1.9.0** (shipping — Insights time-ranges, deeper mood, medication +drug-coding into FHIR, advanced-settings rebuild, connection-pool stability). +Trunk: `main`, always releasable. Release model in CLAUDE.md. -Carry-over candidates already captured in -`.planning/v1423-backlog.md`: - -- Pearson incomplete-beta replacement — v1.4.23 W5 H6 raised - `MIN_PAIRED_N` from 14 → 20 as a conservative surfacing-gate - patch. Land the rigorous incomplete-beta or normal-approx - replacement before v1.5/v1.6 auto-correlation discovery ships. -- OpenAPI drift gate flip from warn-only to hard-fail — generator - covers ~880 lines vs the legacy hand-maintained spec's 5 468; - complete registry coverage in parallel so the lockstep happens - before the iOS DTO codegen is downloading the spec - automatically. -- Settings-cog vs per-message-controls UX consolidation — Design - pushback during W6 raised concern that the dual surface - duplicates intent. Wait on first-week thumbs data, decide - whether per-user prompt prefs drift from per-message ratings. -- `coach-prefs.test.ts` integration `NextRequest` URL mock - regression — pre-existing failure that predates v1.4.23. - Investigate the harness's `cookies()` mock interaction with - `NextRequest`'s URL parsing. -- Sec-MED-1 + LOW cluster — intra-batch dedup accounting - (Sec-LOW-1), idempotency 422 retry hint in the OpenAPI 422 - description (Sec-LOW-2), APNs key-file path redaction in - wide-event meta (Sec-LOW-3), refresh-token failure audit - `userId` extension (Sec-LOW-4). -- S-05 simplify deferral (Session B) — touched too many call - sites for a single reconcile commit. - -Reserved next strategic milestones: - -- **v1.5** — iOS app + Apple Health integration + per-metric APNs - alerts. Refreshed strategic plan with concrete file paths at - `.planning/phase-W6-v1423-product-lead-review.md`. P1 is now a - ~5-day iOS Swift sprint because every server-side contract - landed in v1.4.23. Per-user timezone foundation - (`.planning/feature-user-timezone.md`, issue #167) is now scoped - into v1.4.25 — Marc directive 2026-05-14, packs the iOS-launch - prep into the v1.4.25 polish window instead of slipping it. -- **v1.6+** — Auto-correlation discovery (FDR-controlled), Coach - full-page route at `/insights/coach`, conversation-driven goal - setting. +Next milestone: **v1.10.0 — derived / synthesized wellness metrics + provenance + docs**. --- -## Previous milestone — v1.4.23 (completed 2026-05-11) +## v1.10.0 — derived metrics, provenance, docs, discoverability -| Wave | Goal | State | -| ---- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- | -| 1 | Research — Apple Health type mapping, APNs library decision (`@parse/node-apn`), OpenAPI tooling choice (`zod-openapi` + `yaml@^2`) | done | -| 2 | Apple Health foundation — F1 `MeasurementType` extension + sleep-stage enum + composite dedup index, F2 `APPLE_HEALTH` source + UI badge, F3 `POST /api/measurements/batch` + sleep-stage analytics aggregation | done | -| 3 | APNs scaffolding — F4 `@parse/node-apn` sender + dispatcher cascade rewire, `Device` columns + paired CHECK constraint, `POST /api/devices` apnsToken acceptance + cross-user-hijack guard | done | -| 4 | OpenAPI generator + Coach metric slot + native-auth hardening + Coolify runbook — F5 `zod-openapi` registry + warn-only CI gate, F6 nine HealthKit categories in strict schema + PROMPT_VERSION 4.23.0, F7 per-device refresh-token replay-detection + device-management endpoints, F8 Coolify runbook + `::notice::` line | done | -| 5 | Hygiene (H1-H7) — sentinel parser malformed-enum annotation, analytics chunked-paged aggregate, drawer controlled-prop refactor, per-user prompt prefs surface, `medication_schedules.days_of_week` deploy, Pearson n≥20 gate, Coach feedback observation view | done | -| 6 | Multi-agent QA + reconcile — six reviews (code, security, design, senior-dev, simplify, product-lead); 1 CRIT + 9 HIGH + 4 simplify + 3 MED applied; LOWs triaged into v1423-backlog | done | -| 7 | Release v1.4.23 — bump, CHANGELOG, release-merge, tag, GHCR, Coolify deploy, /api/version=1.4.23, smoke, GH release, docs + landing sync, brief | done | +The headline is derived wellness metrics that are honest on the data HealthLog +actually has — daily snapshots, not continuous streams. The governing constraint: +HRV is a single nightly SDNN value, there is no continuous HR, no EDA, no raw ECG/PPG, +and the nightly drain tombstones per-sample rows to a daily mean. So anything built on +intraday physiology is out of scope; day-scale deviation-from-personal-baseline +statistics are the sweet spot. Full synthesis in +`.planning/v1.10-derived-metrics-PROPOSAL.md`, implementation plan in +`.planning/v1.9.1-derived-metrics-IMPLEMENTATION-PLAN.md` (targeted at v1.10.0, not +1.9.1), research reports under `.planning/v1.10-research/`. -Milestone completed 2026-05-11 — v1.4.23 LIVE in prod. -Release brief: `docs/audit/v1423-summary.md`. -Backlog seeded to `.planning/v1423-backlog.md`. v1.5 strategic plan refresh -at `.planning/phase-W6-v1423-product-lead-review.md`. +### Ordering (data-availability first) + +A derived metric appears only when its required inputs exist; composites degrade +gracefully and never present a headline number secretly computed from one of N signals. +Precedent: the Personal Health Score null-redistributes missing pillars. +(`.planning/v1.10-research/DESIGN-PRINCIPLE-data-availability.md`.) + +1. **Per-metric Vitals dashboard** (flagship) — each available signal shows its own + personal-baseline card; absent signals don't render, so it scales 1→30 metrics with + no data assumptions. Pure rolling stats over inputs we 100% have, plus a multi-signal + early-strain flag. Build this first. +2. **Pre-computed easy wins** — age/sex-adjusted reference ranges (cross-cutting + enabler: `dateOfBirth` / `gender` are stored but unused for norms), Fitness Age / + cardio band from VO2max, Vascular Age framing from PWV. Render only when the device + value exists. +3. **Composites** — Sleep Score and a Readiness / Wellness index (extending the Personal + Health Score), each with a minimum-inputs threshold, reweighting around missing + inputs, a visible coverage / confidence indicator, and a "track BP/HRV to sharpen + this" nudge. +4. **Broader correlation discovery** — expand the fixed-hypothesis correlation engine + into an FDR-controlled behaviour↔outcome discovery engine, surfacing only pairs with + enough paired n (the existing n≥20 gate pattern). + +Out of scope by construction (require sensing we deliberately don't retain): Body +Battery, all-day / real-time Stress, Strain / Training Load, a faithful Recovery score, +AFib / ECG derivation, breathing-disturbance / AHI, Oura Resilience, minute-by-minute +time-in-zone. State this plainly so we never over-promise; surface a device-computed +value as a passthrough where one exists, never re-derive it. + +### Provenance / transparency (acceptance criterion, not an afterthought) + +Every derived metric openly states what it's based on and links the basis: +- exact inputs + method / formula (plain-language + the math), +- why this method (rationale), +- a citation / link to the underlying authority (IEEE / RFC / WHO / LOINC / + peer-reviewed studies / Wikipedia — whichever is right), +- confidence / limitations stated honestly (SDNN≠RMSSD, snapshot-not-continuous, + consumer-sensor validity caveats), +- rendered through the existing collapsible provenance / explainer pattern — no + black-box number. + +Needs a shared provenance / citation data model so each derived metric carries its +sources, surfaced via the explainer component everywhere it appears. +(`.planning/v1.10-research/REQUIREMENT-docs-and-provenance.md`.) + +### Documentation audit + continuation + +- Audit the docs site (`healthlog-docs`), in-repo `docs/`, README, and the OpenAPI + contract for accuracy vs the shipped state — much drifted across the v1.8.x → v1.9.0 + arc. +- Continue / extend docs to cover the new derived metrics with the same provenance: + meaning, computation, linked standard, required data, graceful-degradation behaviour. +- This `ROADMAP.md` / `STATE.md` refresh folds into the audit. + +### Discoverability / growth + +A discoverability / growth workstream stands alongside the milestone (scope to be +shaped during planning). --- -## Previous milestone — v1.4.22 (completed 2026-05-10T22:43:50+02:00) +## Standing deferred items -| Wave | Goal | State | -| ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----- | -| 1 | Research + probe — Playwright PROD probe (BD-Zielbereich 5th attempt, api-tokens 5th attempt, metric token leaks, Targets page brainstorm); health-coach prompt research | done | -| 2 | Insights surface polish — A1 BD framing, A2 BD-Kachel parity, A3 comparison-toggle global, A4 grid normalisation, A5 Muster rename + tabs above hero, A6 token-leak fix | done | -| 3 | Coach polish — B1 prompt rewrite (PROMPT_VERSION 4.20.2 → 4.22.0), B2 collapsible evidence, B3 Gravatar parity, B4 disclaimer move, B5 settings cog removal | done | -| 4 | Other surfaces + backlog cleanup — C1 Zielwerte sparkline + Δ-vs-last-month, C2 api-tokens 5th attempt, C3 Coolify auto-deploy runbook, C4 AuthShell flicker → proxy.ts, C5 node-26-alpine deferred, D backlog wave (12 items) | done | -| 5 | Multi-agent QA + Product-Lead — code, security, design, senior-dev, simplify, product-lead; 0 CRIT, 7 HIGH all applied inline, ~6 MED applied, rest deferred | done | -| 6 | Release v1.4.22 — bump, CHANGELOG, release-merge, tag, GHCR, host-side retag deploy (Coolify secrets still missing), /api/version=1.4.22, smoke, GH release, docs+landing sync, brief | done | +Carried forward; pick up as they become relevant or fold into a milestone. -Milestone completed 2026-05-10T22:43:50+02:00 — v1.4.22 LIVE in prod. -Release brief: `docs/audit/v1422-summary.md`. -Image digest: -`sha256:865154614303fdc362ee3941776f73ec0f60e1f16112ec272a75cbbe28e2cffb`. -Backlog seeded to `.planning/v1422-backlog.md`. v1.5 strategic plan at -`.planning/phase-W5-v1422-product-lead-review.md`. +- **BYOK AI fallback** — resilience gap: no provider fallback is configured, so a single + provider outage stalls assessment generation. +- **`MedicationAdministration` per-export cap tuning** — the per-dose administration + emission added in v1.9.0 needs a sensible cap for high-volume histories. +- **SNOMED route / site upgrade** — route-of-administration + injection-site could carry + SNOMED codes rather than the current local enum. +- **German bfarm ATC URI behind a locale toggle** — the export codes ATC against the WHO + system; a German deployment may prefer the bfarm URI. --- -## Previous patch — v1.4.21 (completed 2026-05-10T17:46+00:00) +## Shipped (coarse — CHANGELOG.md is the record) -| Phase | Goal | State | -| ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | ----- | -| F | Same-day patch on top of v1.4.20 — Daily Briefing regenerate fix, Coach day-level snapshot, duplicate streaming bubble, drawer header, scope picker UI | done | -| E | Release v1.4.21 — develop → main release-merge, bump, CHANGELOG, tag, GHCR, host-side retag fallback, /api/version=1.4.21, smoke, GH release, brief | done | - -Patch completed 2026-05-10T17:46+00:00 — v1.4.21 LIVE in prod. -Release brief: `docs/audit/v1421-summary.md`. -Image digest: -`sha256:4e818d44702c3581a14d6480a953fd20d16cbbaf21c41e0c778c07340d3c4b1c`. - ---- - -## Previous milestone — v1.4.20 (completed 2026-05-10T16:49:25Z) - -| Phase | Goal | State | -| ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- | -| F0 | Bootstrap — commit dangling v1.4.19 reports, scaffold STATE+ROADMAP | done | -| F1 | Branch model — long-lived `develop` from `main` HEAD; GHCR builds on `main` + `v*` only | done | -| F2 | Document branch + release model — CONTRIBUTING.md + docs site mirror page | done | -| FX | User-facing artifact cleanup — PII (no real names, no health figures), internal jargon, German leaks; CHANGELOG + docs/audit + GH releases + docs + landing | done | -| F5 | Best-practice GitHub repo audit — CODE_OF_CONDUCT.md, issue + PR templates, dependabot expansion, package.json metadata | done | -| F6 | Multi-agent QA on new docs — 38 docs pages cross-checked vs deployed state, CRIT + HIGH inline | done | -| B1 | Hero strip + Daily Briefing + Suggested-prompts | done | -| B2 | AI Coach drawer + SSE streaming + encrypted persistence | done | -| B3 | Correlation discovery + Trends row with AI annotations | done | -| B4 | Weekly Report + Storyboard markers + Mobile passes | done | -| B5 | Personal Health Score (composite 0–100, 3 bands) | done | -| D | Multi-agent QA — code, security, design, senior-dev, simplify, product-lead; 13 HIGH + 6 MED + 5 simplify-yes inline; 22 MED + 16 LOW deferred | done | -| E | Release v1.4.20 — develop → main release-merge, bump, CHANGELOG, tag, GHCR, host-side retag deploy fallback, /api/version=1.4.20, smoke, docs+landing sync | done | - -Milestone completed 2026-05-10T16:49:25Z — v1.4.20 LIVE in prod. -Release brief: `docs/audit/v1420-summary.md`. Backlog seeded to -`.planning/v1421-backlog.md`. v1.5 strategic plan at -`.planning/phase-D-v1420-product-lead-review.md`. - ---- - -## Previous milestone — v1.4.19 (completed 2026-05-10T12:39:59Z) - -| Phase | Goal | State | -| ----- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ----- | -| 0 | Bootstrap — STATE+ROADMAP for v1.4.19 | done | -| A1 | BD-Zielbereich constant 50% (4th attempt) — live-DB root-cause + integration test | done | -| A2 | Charts mobile audit — universal X-tick density helper, mobile-first stacked headers across HealthChart / MoodChart / MedicationComplianceChart | done | -| A3 | `/insights` polish — Comparison-toggle relocated, single page-level refresh, BP/Weight tile strip removed, raw-token leak guarded | done | -| A4 | AI prompt — GROUND RULE 7 forbids default-positivity opener, PROMPT_VERSION 4.16.1 → 4.19.0 | done | -| A5 | Settings/Integrations status-UI — `` consolidates Withings + Mood Log, divider parity, locale-aware relative-time | done | -| A6 | Settings mobile audit — input heights equalised at 36 px, action buttons standardised, Sprache select hoisted to its own row | done | -| A7 | Admin polish — feedback tab strip scrollbar, api-tokens 4th-attempt truncate+tooltip, Einklappen toggle removed, Zielwerte i18n | done | -| A8 | Quality-of-life audit — 78 findings prioritised CRITICAL / HIGH / MED / LOW | done | -| B | Apply A8 — 6/6 CRITICAL + 21/25 HIGH inline; 31 MED + 16 LOW carried to v1.4.20 backlog | done | -| D | Multi-agent QA (5 reviewers) + Product-Lead → v1.5 redesign plan filed | done | -| E1-E3 | Release v1.4.19 — tag, GHCR build green, host-side retag deploy via fallback (Coolify deploy hung, retried via SSH), GH release, docs+landing sync | done | - -Milestone completed 2026-05-10T12:39:59Z — v1.4.19 LIVE in prod. -Release brief: `docs/audit/v1419-summary.md`. Backlog seeded to -`.planning/v1420-backlog.md` (carry-over) and v1.5 strategic items in -`.planning/v15-backlog.md` + `.planning/phase-D-v1419-product-lead-review.md`. - ---- - -## Previous milestone — v1.4.18 (completed 2026-05-10T11:45+02:00) - -| Phase | Goal | State | -| ----- | ------------------------------------------------------------------------------------------------------------ | ----- | -| 0 | Bootstrap — STATE+ROADMAP for v1.4.18 | done | -| A1 | BD-Zielbereich tile — 7T/30T sub-values render real numbers (currently "—" even with data) | done | -| A2 | `/admin/api-tokens` table scrollbar (3rd attempt) — Playwright live-verify against prod, fix actual offender | done | -| A3 | Chart visual revert + per-chart toggles — drop gradient/emoji/auto-mean, ship 3 opt-in overlay toggles | done | -| B1 | Achievements expansion — research + 15-25 new, hidden Easter-eggs, lock filter, hidden cards | done | -| D | Multi-agent QA + Product-Lead — code-reviewer, security, design, senior, simplify, product | done | -| E | Release v1.4.18 — bump, CHANGELOG, tag, GHCR, deploy, /api/version=1.4.18, smoke, docs+landing sync | done | - -Marathon completed 2026-05-10T11:45+02:00 — v1.4.18 LIVE in prod. -Full report: `docs/audit/v1418-summary.md`. Backlog seeded to -`.planning/v1419-backlog.md` (tactical) and `.planning/v15-backlog.md` - -- `.planning/phase-D-v1418-product-lead-review.md` (strategic). - ---- - -## Previous milestone — v1.4.17 hotfix (live 2026-05-10T07:58+00:00) - -| Phase | Goal | State | -| ------ | ---------------------------------------------------------------------------------------------------------- | ----- | -| Hotfix | `/insights` TypeError on legacy cached blob — `isLegacyInsightPayload()` flag + advisor card short-circuit | done | -| Audit | `git grep -nE '\.replace\(' src/` — 82 hits scanned, crash site is the only fragile case | done | -| E | Release v1.4.17 — bump, tag, GHCR, host-side retag deploy, GH release | done | - -Hotfix completed 2026-05-10T07:58+00:00 — v1.4.17 LIVE in prod. -Detailed report: `.planning/phase-v1417-hotfix-report.md`. - ---- - -## Previous milestone — v1.4.16 (completed 2026-05-10T04:05+02:00) - -| Phase | Goal | State | -| ----- | ----------------------------------------------------------------------------------------------------- | ----- | -| 0 | Bootstrap — STATE+ROADMAP for v1.4.16 | done | -| A1 | Sidebar admin-expand bug — Admin nav from non-admin route + Gravatar dropdown side-effects | done | -| A2 | BD-Zielbereich real-fix (regression from v1.4.15 A4) — root-cause + E2E | done | -| A3 | `/admin/api-tokens` table responsive — card-list mobile fallback | done | -| A4 | "7-Tage-Schnitt" → "7-Tage-Trend" DE + indicator on ALL charts | done | -| A5 | Top-tile-selector real-fix — widget-id enum drift fixed | done | -| A6 | Medication-chart 7d-trend + target-range — match other charts | done | -| A7 | AI Generator rate-limit 10/h + cache-invalidate-on-new | done | -| A8 | Umlaute encoding bug + login-overview UTF-8 audit + long-window split-half delta | done | -| B1a | Charts visual leap — gradients, baseline, rich tooltip, mood emoji glyphs | done | -| B1b | Insights surface visual leap — page hero, recs grid, summary typography, dashboard preview | done | -| B2 | AI provider settings UX cleanup — single pulldown-driven form, fallback chain editor | done | -| B3 | Admin System-Status host-load chart — CPU/memory/disk-io graph last 2h | done | -| B4 | Admin logs visibility deepening — filterable audit log + structured wide-event tail | done | -| B5a | Medical-reference grounding — AHA / ESC / ESH / WHO bundle + UI citations | done | -| B5b | Multi-provider redundancy — try-each-on-hard-failure, configurable fallback order | done | -| B5c | Per-recommendation explainability — WHY / WINDOW / CITATIONS card with mini-chart | done | -| B5d | Confidence score per recommendation — deterministic 0-100 from sufficiency / recency / signal | done | -| B5e | User-feedback loop — thumbs persisted to RecommendationFeedback + daily aggregator | done | -| B6 | Settings naming-audit — stringency, consistency, no double naming | done | -| B7 | Settings → Export menu (Arztbrief consolidated) — new `/settings/export` route | done | -| B8 | Extended comparison views — Vormonat / Vorjahr overlay across charts + tiles + insights | done | -| C | Catch-up — 5 of 8 deferred HIGH + 3 of 5 mobile MED + docker-publish drop qemu-arm64 | done | -| D | Multi-agent QA + Product-Lead — code-review, security, design, senior, simplify, product-lead | done | -| E1-E3 | Release v1.4.16 — bump, tag, GHCR (both green), host-side retag deploy, GH release, docs+landing sync | done | - -Marathon completed 2026-05-10T04:05+02:00 — v1.4.16 LIVE in prod. -Full report: `docs/audit/v1416-summary.md`. v1.5 backlog seeded at -`.planning/v15-backlog.md`. - ---- - -## Previous milestone — v1.4.15 (completed 2026-05-09T22:50+02:00) - -| Phase | Goal | State | -| -------- | ------------------------------------------------------------------------------------------------------------ | ----- | -| 0 | Bootstrap — STATE+ROADMAP for v1.4.15 | done | -| A1 | Nav conditionals + sidebar context-awareness | done | -| A2 | `/admin` overview redesign + `/admin/api-tokens` responsive | done | -| A3 | Quick-add labels + Stimmung-Card mobile + onboarding flicker | done | -| A4 | Dashboard analytics fixes (BD-Zielbereich, Medikamente graph, Stimmung agg, 7-Tage-Trend, top-tile selector) | done | -| A5 | Mobile UX audit + chart scroll-lockup fix | done | -| B-mobile | Mobile audit fix-application (5 commits, 2/2 CRITICAL, 6/8 HIGH) | done | -| B1 | Backup completeness — restore, download, upload, audit, docs | done | -| B2 | Withings + moodLog sync robustness — status UI, refresh rotation, telegram on fail | done | -| B3 | Notification reliability — auto-disable on 410, exp backoff, status visible | done | -| B4 | Achievements UI — `/achievements` page + dashboard card | done | -| B5 | Onboarding tour first-run — spotlight, Esc/arrows, restart from Settings | done | -| B6 | Doctor-report v2 — configurable date range, practice-name on cover | done | -| C1 | AI/Codex hardening — provider abstraction, JSON schema, citations, scope, slug-drift defense | done | -| C2 | Auto-deployment — Coolify webhook on GHCR push, failure-notify | done | -| C3 | CI/e2e reliability audit — root-cause flaky specs, docker-publish cache fix | done | -| C4 | i18n coverage audit — EN+DE parity, non-empty test guards | done | -| C5 | Empty-states audit — 13 surfaces upgraded | done | -| D | Multi-agent QA (5 reviewers + reconcile) | done | -| E1–E3 | Release v1.4.15 — bump, tag, GHCR, host-side retag deploy, docs+landing sync, Marc-Brief | done | - -Marathon completed 2026-05-09T22:50+02:00 — v1.4.15 LIVE in prod. -Full report: `docs/audit/v1415-summary.md`. - ---- - -## Previous milestone — v1.5 (relabelled v1.4.14, completed 2026-05-09) - -| Phase | Goal | State | -| ----- | -------------------------------------------------------------------------------------------------------------------------------------- | ----- | -| 0 | Bootstrap — STATE+ROADMAP, git/CI/prod sanity, single chore commit | done | -| 1 | Verify Codex-OAuth end-to-end (device-start shape, prod logs, gpt-5.3-codex slug) | done | -| 2 | v1.4.6 deferred backlog — T2.1..T2.7 (wipe scope, DST math, 5xx → 422/503, status-card test, redact regex, Backups view, /admin/users) | done | -| 3 | End-to-end test coverage — authed dashboard, add-measurement, KI flow, doctor PDF, insights, mobile smoke, axe-core extended | done | -| 4 | Performance audit — Playwright capture, `docs/audit/v15-performance.md`, top-3 wins inline | done | -| 4b | Admin Panel refactor — `/admin/[section]` dynamic routes mirror Settings; sidebar Admin group; legacy hash redirects; bundle-size win | done | -| 5 | UX polish — design-review top-10 friction points, CRITICAL/HIGH triage | done | -| 6 | Multi-agent QA (parallel) — code-reviewer, security, visual/UX, simplify | done | -| 7 | Pre-release verification — typecheck / lint / format / test / integration / build / e2e | done | -| 8 | Release v1.4.14 — rebrand patch deploy (host-side retag, GHCR `:1.4.14`, image digest `0ced46004a54…`) | done | -| 9 | Docs + landing site sync to v1.4.14 | done | -| 10 | Backfill GitHub releases v1.4.7..v1.4.13 from CHANGELOG | done | -| 11 | Final summary `docs/audit/v1414-summary.md` with Marc-Brief | done | - -Marathon completed 2026-05-09T18:35+02:00 — v1.4.14 LIVE in prod. -Full report: `docs/audit/v1414-summary.md`. +- **v1.9.0** (2026-06-02) — Insights time-ranges + period-over-period deltas, deeper + mood insights, medication ATC + RxNorm into the FHIR export (+ MedicationAdministration + per dose, Coverage-from-bare-KVNR, Composition narrative), advanced-settings rebuild, + inline targets (`/targets` retired), connection-pool sizing fix, decoupled insight + warm. Migration `0103`. +- **v1.8.7.1** (2026-06-02) — assessment on every HealthKit metric page, one-tap + pre-generation. +- **v1.8.x** (2026-05-31 → 06-02) — Insights big release (reliable assessments, graded + compression, embedded targets, explainers, English slugs), compliance + intake-slot + medical fixes, injection-site tracking, FHIR codesystem + Coverage, instant + assessments, GLP-1 blood-level chart. +- **v1.7.x** (2026-05-31) — health-record PDF + FHIR R4 export, PRN + cyclic schedules, + unified dashboard snapshot + nightly insight pre-gen, offline sync delta feed, full + HealthKit chart coverage, Coach data clustering. +- **v1.6.0** (2026-05-30) — medication editor overhaul + route of administration, + one-time injection, today-tile read-flip, profile-photo upload. +- **v1.5.x** (2026-05-24 → 29) — native iOS client public beta + Apple Health sync, + medication scheduling (RRULE / rolling / one-shot), step consolidation, `safeFetch` + egress hardening, avatar storage, `SESSION_COOKIE_SECURE` through compose. +- **v1.4.24 → v1.4.50** (2026-05-11 → 24) — rollup tiers + perf, APNs + `push_attempts`, + reminder suppression, self-healing stale-shell, localisation, MoodLog reverse-sync. +- **v1.4.23** (2026-05-11) — pre-iOS backend foundation + hygiene (Apple Health enum + + batch ingest + APNs scaffolding + OpenAPI generator). Earlier history archived. + diff --git a/.planning/STATE.md b/.planning/STATE.md index d4dff4c10..8f8fdb82a 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -1,245 +1,117 @@ -# v1.4.23 marathon — state log +# State log — where we are now -Status: SHIPPED — v1.4.23 LIVE in prod -Last update: 2026-05-11 (release wave) +Status: **v1.9.0 shipping** — on branch `release/v1.9.0`, Draft PR #240 → `main`, +about to tag + docker-publish + deploy. +Last update: 2026-06-02 -> Previous milestone: v1.4.22 live (image digest -> `sha256:865154614303…`, `/api/version=1.4.22`). -> v1.4.23 = pre-iOS prep + hygiene. Backend foundation so the iOS -> Health app can ship in v1.5 without contract churn, plus 7 -> hygiene items from `.planning/v1422-backlog.md`. +> Single trunk: `main` is always releasable. `develop` is retired (archived as the +> tag `archive/develop-pre-v1.5`; never recreate it). Releases cut on a short-lived +> `release/vX.Y.Z` branch → PR → merge → tag → `docker-publish.yml` → manual deploy → +> verify `/api/version` on every target. See CLAUDE.md for the full model. -## Wave 1 — Research (single agent, three streams) +--- -- [ ] Apple Health `HKQuantityTypeIdentifier` → `MeasurementType` - mapping, with units + canonical aggregation rules -- [ ] APNs Node library decision (`apn` vs `@parse/node-apn` vs - raw HTTP/2) with maintenance / type-safety / footprint pros/cons -- [ ] OpenAPI 3.1 generator tooling for Next.js routes - (`@asteasolutions/zod-to-openapi`, `ts-rest`, `next-rest`, - hand-rolled) -- Detailed report: `.planning/phase-W1-v1423-research.md` +## v1.9.0 — what it carries -## Wave 2 — Apple Health foundation (F1+F2+F3) +Insights time-ranges + period-over-period deltas, deeper mood insights, medication +drug-coding into the FHIR export, an advanced-settings rebuild, an inline-targets +move, and a stability fix to the connection pool. -### F1 — `MeasurementType` enum extension +### Added -- [x] Added `HEART_RATE_VARIABILITY`, `RESTING_HEART_RATE`, - `ACTIVE_ENERGY_BURNED`, `FLIGHTS_CLIMBED`, - `WALKING_RUNNING_DISTANCE`, `VO2_MAX`, `BODY_TEMPERATURE` - (W1 recommended reusing `ACTIVITY_STEPS` + `SLEEP_DURATION` - verbatim; the iOS DTO already shipped `BODY_TEMPERATURE` so - that joined the additive set — net new = 7) -- [x] Prisma migration `0036_apple_health_measurement_types` -- [x] Sleep unit shifted from hours to minutes; new `SleepStage` - enum + nullable `Measurement.sleepStage` column (CHECK - constraint scopes it to SLEEP_DURATION rows) -- [x] Composite unique index `(user_id, type, source, external_id)` - — Apple Health batch dedup key -- [x] Unit conversions in - `src/lib/measurements/apple-health-mapping.ts` (16 unit tests) +- **Selectable time ranges on the Insights pages** — week / month / quarter / year + range pills per metric, with a period-over-period delta (the change in the average, + stated plainly with its direction). +- **Deeper mood insights** — time-of-day pattern (highest / lowest), a stability read, + and correlation cards against weight and blood pressure. Every correlation is + paired-n gated (only shown when there are enough paired days to mean anything). +- **Standard drug codes on a medication** — an optional ATC and RxNorm code (entered, + never guessed; migration `0103` adds the nullable `atc_code` / `rxnorm_code`). + These flow into the health-record export: the `MedicationStatement` codes the drug + with the WHO ATC system + RxNorm alongside the plain name, and the export adds a + `MedicationAdministration` for every dose actually taken or skipped. +- **`scripts/assert-deploy.ts`** — a deploy-verification script that checks a target + reports the expected version after a release. -### F2 — `MeasurementSource` enum expansion +### Changed -- [x] `APPLE_HEALTH` appended to the enum -- [x] UI badge in measurement-list (Dracula-pink chip) + bilingual - `measurements.sourceAppleHealth` keys + admin restore-route - enum guard sync +- **Medication advanced-settings page rebuilt** — import / intake-import / export in + their own group; the external-API endpoints listed one by one with collapsible + request examples; tidier layout. +- **Targets edited inline** — the standalone `/targets` page is retired; a metric's + target range is set from the metric itself. +- **Health-record export emits insurer Coverage from a bare KVNR** (not only with a + full insurer organisation present) and carries a top-level Composition narrative + summary. -### F3 — `POST /api/measurements/batch` +### Fixed -- [x] New route at `src/app/api/measurements/batch/route.ts`, - idempotent via `Idempotency-Key` -- [x] Validates batch ≤ 500 entries (returns 422 - `coach.batch.too_large`) -- [x] Dedupes via `(userId, type, source, externalId)` composite -- [x] Returns per-entry status (`inserted` / `duplicate` / - `skipped`) + idempotency-replay-safe -- [x] Integration test (`tests/integration/measurements-batch.test.ts`, - 6 cases including idempotency replay) -- [x] Sleep-stage aggregation in `/api/analytics`: - per-Berlin-day summary + `sleepStages` block - (`tests/integration/analytics-sleep-stages.test.ts`) -- Detailed report: `.planning/phase-W2-v1423-report.md` +- **App stays responsive under load** — `DB_CONNECTION_LIMIT` is now sized for real + concurrency (the 9 default could starve while a background insight warm and a + foreground request competed, surfacing as the self-recovering "server not + responding"); tunable for larger self-hosts. +- **Background insight warm decoupled + sync-burst invalidation debounced** — a warm + no longer blocks a page, and a burst of Apple Health / Withings sync no longer + triggers a storm of regenerations. +- **Medication card rows hold an equal height** ("last dose" / "next dose" alignment). +- **Glucose entered in mmol/L converts correctly** in the editor. +- **Scrollbar-gutter reserved** — admin + global layout no longer shifts when a + scrollbar appears. +- **Six legacy `*-status` routes documented** in the OpenAPI contract. -## Wave 3 — APNs scaffolding (F4) +--- -- [x] Library install + lock-file (`@parse/node-apn@8.1.0`, - W1 stream-2 decision) -- [x] `src/lib/notifications/senders/apns.ts` — `sendApnsPush()` - one-shot helper plus `sendViaApns(userId, payload)` dispatcher - entry mirroring the web-push contract -- [x] Env-var contract: `APNS_KEY_ID`, `APNS_TEAM_ID`, - `APNS_BUNDLE_ID`, one of `APNS_KEY` / `APNS_KEY_FILE`, - optional `APNS_PRODUCTION` — documented in `.env.example`, - all-or-none guard with one-shot warning when partially set -- [x] `Device` Prisma model extension via migration - `0037_apns_device_columns`: nullable `apnsToken` + - `apnsEnvironment`, paired CHECK constraint, single-column - index on `apns_token` for the dispatcher fan-out lookup -- [x] Dispatcher wiring: `APNS` joins the cascade as channel-type - 4; cascade order is now deterministic - (APNs → Telegram → ntfy → Web Push) -- [x] Mock provider at `src/lib/notifications/senders/__mocks__/apns.ts` - with queued per-token responses + recorded calls -- [x] Integration test - `tests/integration/apns-dispatch.test.ts` — round-trip, - hard-reject + cleanup, cascade fall-through (3 tests) -- [x] `POST /api/devices` accepts paired `apnsToken` + - `apnsEnvironment`, enforces hex format, applies the - cross-user-hijack guard at the APNs-token layer - (409 `apns_token_owned_by_other_user`) -- Detailed report: `.planning/phase-W3-v1423-report.md` +## What is live (the release arc since v1.4.23) -## Wave 4 — OpenAPI + Coach schema + native auth + Coolify +Coarse summary; CHANGELOG.md is the accurate per-release record. -### F5 — OpenAPI 3.1 generator + CI gate +- **v1.4.24 → v1.4.50** — perf + rollup tiers (measurement / mood / compliance / + cumulative-sum rollups, read-swap with live fallback, auto-converging boot + backfill), APNs delivery + per-channel test endpoint + `push_attempts` ledger, + server-side reminder suppression (`clientManaged`), self-healing stale-shell after + deploy, full localisation push, MoodLog reverse-sync. +- **v1.5.x** — native iOS client public beta + Apple Health sync (`POST /api/measurements/batch`, + per-day cumulative `stats:` overwrite), medication scheduling (RRULE / rolling / + one-shot lifecycle, creation wizard → modal-dialog compose-mode), per-day-cumulative + step consolidation, `safeFetch` egress hardening, self-hosted avatar storage, + `SESSION_COOKIE_SECURE` plumbed through compose. +- **v1.6.0** — medication editor overhaul + route of administration (`deliveryForm`, + migration `0088` ORAL backfill), one-time injection, today-tile read-flip onto the + canonical recurrence engine, profile-photo upload. +- **v1.7.x** — health-record export (enriched PDF + HL7 FHIR R4 bundle), PRN + cyclic + schedules, unified dashboard snapshot + nightly insight pre-generation, offline sync + delta feed (tombstones), full HealthKit chart coverage + display-unit preference, + Coach data clustering, multi-time compliance fixes. +- **v1.8.x** — Insights big release (reliable data-driven assessments, graded + compression, embedded targets, explainers, English slugs + tile-id aliases), + multi-time compliance, one-intake-row-per-dose-slot medical fix, injection-site + tracking, FHIR codesystem for HealthKit-only metrics, FHIR `Coverage`, instant + assessments (stale-while-revalidate), GLP-1 blood-level chart. +- **v1.8.7.1** — a plain-language assessment on every HealthKit metric page (~30 + metrics), one-tap pre-generation of every assessment. -- [x] Tool wired (W1 decision — `zod-openapi` (samchungy) + `yaml@^2`) -- [x] `pnpm openapi:generate` script emits - `docs/api/openapi.yaml` from Zod schemas -- [x] CI step compares generated vs committed; PR warns on drift - (`continue-on-error: true` — flips to hard-fail in v1.4.24+) -- [x] Legacy hand-maintained spec preserved at - `docs/api/openapi-v1422-legacy.yaml` during the incremental - migration +apps01 + demo are LIVE on the latest tag; v1.9.0 deploy is pending the tag. -### F6 — Coach + Daily Briefing schema slot for new metrics +--- -- [x] `aiInsightResponseSchema.dailyBriefing.keyFindings[].sourceMetric` - enum extends to include the 9 Apple Health categories - (hrv, sleep, resting_hr, steps, active_energy, flights, - distance, vo2_max, body_temp) -- [x] `trendAnnotations` schema mirrors the same additive enum -- [x] `coach/snapshot.ts` queries the new measurement types when - scope toggles them on; web-only accounts pay zero extra SQL -- [x] `CoachProvenance.metrics` + `counts` extended symmetrically -- [x] PROMPT_VERSION 4.22.0 → 4.23.0 with new GROUND RULE 12 - ("treat Apple Health categories as silent when absent") -- [x] EN + DE prompt bodies, OUTPUT FORMAT block, and i18n strings - all updated +## Deferred set (carry-forward from v1.9.0) -### F7 — Native API hardening (refresh-token per-device) +| Item | Where it goes | Note | +|---|---|---| +| Derived / synthesized wellness metrics | **v1.10.0** | per-metric Vitals dashboard first, then composites with coverage/confidence gating. Plans in `.planning/v1.10-derived-metrics-PROPOSAL.md` + `.planning/v1.9.1-derived-metrics-IMPLEMENTATION-PLAN.md` (targeted at v1.10.0) + `.planning/v1.10-research/*`. | +| Docs / provenance audit | **v1.10.0** | docs site + in-repo `docs/` + README + OpenAPI drifted across the v1.8.x → v1.9.0 arc; audit + continue, and surface every derived metric's sources via the explainer pattern. Requirement: `.planning/v1.10-research/REQUIREMENT-docs-and-provenance.md`. | +| Discoverability / growth workstream | **v1.10.0** | standing alongside the derived-metrics milestone. | +| BYOK AI fallback | open | resilience gap — no provider fallback is configured, so a single provider outage stalls assessment generation. | +| `MedicationAdministration` per-export cap tuning | open | the per-dose administration emission needs a sensible cap for high-volume histories. | +| SNOMED route / site upgrade | open | route-of-administration + injection-site could carry SNOMED codes rather than the current local enum. | +| German bfarm ATC URI behind a locale toggle | open | the export codes ATC against the WHO system; a German deployment may prefer the bfarm URI — gate behind a locale toggle. | -- [x] Refresh-token reuse-detection switches from "revoke all" to - per-device-token revocation (legacy null-deviceId tokens fall - back to user-wide revoke — safety hatch) -- [x] New route `GET /api/auth/me/devices` lists active devices - with last-seen, label, channels, isCurrent marker -- [x] New route `DELETE /api/auth/me/devices/[id]` revokes one device - (refresh + access tokens + Device row) -- [x] Alternate `DELETE /api/devices/[id]` for the iOS token-rotation - cleanup path (mirror of the auth/me variant) -- [x] Ownership-boundary 404 on cross-user attempts +--- -### F8 — Coolify auto-deploy fix for real +## Next milestone — v1.10.0 -- [x] `COOLIFY_WEBHOOK` + `COOLIFY_TOKEN` GitHub repo secrets - documented (maintainer action; see - `.planning/coolify-auto-deploy-howto.md` for the verbatim - recipe) -- [x] Coolify "Watch image registry for new digests" UI toggle - documented as the load-bearing piece (maintainer action — can't - be flipped from CI) -- [x] Workflow step gains a `::notice::` line so future runs surface - the deploy timestamp + sha without opening the verbose log -- [x] Verification recipe (`curl /api/version | jq .data.version`) + host-side fallback documented inline - -## Wave 5 — Hygiene (H1-H7) - -- [x] H1 sentinel parser malformed-enum hardening - (`SentinelParseResult.malformedEntries[]` + per-line typed - reasons; chat route splits `coach.keyvalues.parse_partial` from - the full-block `coach.keyvalues.parse_failed`) -- [x] H2 analytics-route unbounded `findMany` pagination - (cursor-paged 5 000-row chunks via `fetchBpSeriesChunked`, - `analytics.bp_in_target.row_count` wide-event meta for slow- - query attribution; integration test seeds 6 000 rows across a - chunk boundary) -- [x] H3 `` controlled-prop refactor - (`useResettableValue` hook + pure `nextResettableValue` helper; - `key={prefill}` removed from the parent mount) -- [x] H4 per-user prompt-tuning surface (Coach settings cog return) - (`User.coachPrefsJson` migration `0038_coach_prefs`; new - `GET/PUT /api/auth/me/coach-prefs`; settings cog opens a - right-edge ``; system-prompt prepends a per-user - OVERRIDE; snapshot reads prefs BEFORE measurement queries so - `excludeMetrics` filters before the snapshot lands) -- [x] H5 schema drift on `medication_schedules.days_of_week` - (decision: deploy — column is referenced by 9 source files - across 4 user-visible surfaces; migration - `0039_medication_schedule_days_of_week`, NULL = daily) -- [x] H6 Pearson p-value normal-approx replacement - (raised `MIN_PAIRED_N` from 14 → 20 — conservative patch; - rigorous incomplete-beta queued as a v1.4.24 candidate) -- [x] H7 Coach helpful/unhelpful first-week observation view - (polymorphic `RecommendationFeedback.target_type` migration - `0040_recommendation_feedback_target_type`; new POST - `/api/insights/chat/messages/:id/feedback`; aggregator slice - `buildCoachFeedbackBuckets` by (promptVersion, tone, verbosity); - admin section `/admin/coach-feedback` with the H7 i18n bundle - both EN + DE) - -W5 commits (8): 58ae9bc, fa07748, 9413d29, 3f60c81, 0eda1de, 1faee95, -05c7f14, plus this STATE tick. - -Test deltas: 2191 → 2223 unit (+32). Integration suite added 3 -files: `coach-prefs`, `coach-feedback`, plus the 6000-row chunk -boundary regression in the existing `bp-in-target` test. - -OpenAPI registry coverage: +3 routes (GET / PUT -`/api/auth/me/coach-prefs`, POST -`/api/insights/chat/messages/{id}/feedback`). - -## Wave 6 — Multi-agent QA + Product-Lead review - -- [x] code-reviewer -- [x] security review -- [x] design / UX review -- [x] senior-dev review -- [x] simplify -- [x] Product Lead — v1.5 P1 (iOS first launch) plan refresh with - concrete file paths now that backend contracts exist -- [x] Reconcile — 1 CRITICAL + all 9 HIGH + 4 of 5 simplify + 3 MED - applied; remainder triaged into `.planning/v1423-backlog.md` - -W6 reconcile commits (11): 5486507, 13977bc, d5202e5, a2dfc5e (Session A -— CRIT + HIGH 1-3); 3ee6dab, dfffe6b, d25e50e (Session B — HIGH 4 + -S-02-S-04 simplify + HIGH 6); deadc73 (Session D — HIGH 5); 650f150 -(Session E — HIGH 7); 1a46bfe (Session F — MED cluster); plus this -STATE tick. - -Detailed reconcile report: `.planning/phase-W6-v1423-reconcile-report.md`. -Deferred items: `.planning/v1423-backlog.md` (settings-cog vs -per-message-controls debate, rigorous Pearson incomplete-beta, surplus -MEDs, all LOWs, S-05 simplify, pre-existing `coach-prefs.test.ts` mock -issue, sandbox `git commit` no-op). - -Test deltas: W5 ended at 2223 unit. Session A added the `revoke.test.ts` - -- `apns-dispatch` device tests landing at 2227. Session E ended at 2235. - Session F added the forged-X-Device-Id regression — final at 2236 unit - (+45 across the W5+W6 reconcile arc). - -## Wave 7 — Release v1.4.23 - -- [x] Pre-release verify (typecheck / lint / openapi:check / 2236 - unit / 110 of 112 integration — 2 failures are the pre-existing - `coach-prefs.test.ts` `NextRequest` URL mock carryover from - v1.4.22, documented in `v1423-backlog.md`, non-blocking) -- [x] Format sweep commit (`f1e6630` prettier sweep on `develop`) + - W1 research + W5/W6 review packs commit (`766a9ae`) + - OpenAPI regen (`4183552`) -- [x] Bump `package.json` 1.4.22 → 1.4.23 + CHANGELOG (`d2331d9` - `chore(release): v1.4.23`) -- [x] Release-merge develop → main (`0dc0e16 Release v1.4.23`) -- [x] Tag + push v1.4.23 -- [x] GHCR build green -- [x] Coolify deploy + `/api/version=1.4.23` confirmed -- [x] Production smoke (gated routes 307; `/api/version=1.4.23`) -- [x] GH release published -- [x] Docs site + landing site sync (image pins 1.4.22 → 1.4.23 + - ai-insights v1.4.23 callout; softwareVersion JSON-LD bump) -- [x] `docs/audit/v1423-summary.md` release brief -- [x] v1.5 P1 plan refresh recorded - (`.planning/phase-W6-v1423-product-lead-review.md` section C) +Derived / synthesized wellness metrics, honest on the daily-snapshot data HealthLog +actually stores; full provenance + standards-linking; full docs audit; +discoverability / growth. See `ROADMAP.md`. + +