mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-14 22:50:51 +00:00
Wave 4 closes the v1.4.23 foundation track. F5 (OpenAPI 3.1 drift gate, warn-only for v1.4.23), F6 (Coach schema slot for Apple Health metrics + PROMPT_VERSION 4.23.0), F7 (per-device refresh-token reuse detection + device-management endpoints), and F8 (Coolify auto-deploy runbook) all green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
8.0 KiB
8.0 KiB
v1.4.23 marathon — state log
Status: Wave 4 shipped (OpenAPI gate + Coach schema + native auth + Coolify) Last update: 2026-05-11T01:15+02:00
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.
Wave 1 — Research (single agent, three streams)
- Apple Health
HKQuantityTypeIdentifier→MeasurementTypemapping, with units + canonical aggregation rules - APNs Node library decision (
apnvs@parse/node-apnvs 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
Wave 2 — Apple Health foundation (F1+F2+F3)
F1 — MeasurementType enum extension
- Added
HEART_RATE_VARIABILITY,RESTING_HEART_RATE,ACTIVE_ENERGY_BURNED,FLIGHTS_CLIMBED,WALKING_RUNNING_DISTANCE,VO2_MAX,BODY_TEMPERATURE(W1 recommended reusingACTIVITY_STEPS+SLEEP_DURATIONverbatim; the iOS DTO already shippedBODY_TEMPERATUREso that joined the additive set — net new = 7) - Prisma migration
0036_apple_health_measurement_types - Sleep unit shifted from hours to minutes; new
SleepStageenum + nullableMeasurement.sleepStagecolumn (CHECK constraint scopes it to SLEEP_DURATION rows) - Composite unique index
(user_id, type, source, external_id)— Apple Health batch dedup key - Unit conversions in
src/lib/measurements/apple-health-mapping.ts(16 unit tests)
F2 — MeasurementSource enum expansion
APPLE_HEALTHappended to the enum- UI badge in measurement-list (Dracula-pink chip) + bilingual
measurements.sourceAppleHealthkeys + admin restore-route enum guard sync
F3 — POST /api/measurements/batch
- New route at
src/app/api/measurements/batch/route.ts, idempotent viaIdempotency-Key - Validates batch ≤ 500 entries (returns 422
coach.batch.too_large) - Dedupes via
(userId, type, source, externalId)composite - Returns per-entry status (
inserted/duplicate/skipped) + idempotency-replay-safe - Integration test (
tests/integration/measurements-batch.test.ts, 6 cases including idempotency replay) - Sleep-stage aggregation in
/api/analytics: per-Berlin-day summary +sleepStagesblock (tests/integration/analytics-sleep-stages.test.ts) - Detailed report:
.planning/phase-W2-v1423-report.md
Wave 3 — APNs scaffolding (F4)
- Library install + lock-file (
@parse/node-apn@8.1.0, W1 stream-2 decision) src/lib/notifications/senders/apns.ts—sendApnsPush()one-shot helper plussendViaApns(userId, payload)dispatcher entry mirroring the web-push contract- Env-var contract:
APNS_KEY_ID,APNS_TEAM_ID,APNS_BUNDLE_ID, one ofAPNS_KEY/APNS_KEY_FILE, optionalAPNS_PRODUCTION— documented in.env.example, all-or-none guard with one-shot warning when partially set DevicePrisma model extension via migration0037_apns_device_columns: nullableapnsToken+apnsEnvironment, paired CHECK constraint, single-column index onapns_tokenfor the dispatcher fan-out lookup- Dispatcher wiring:
APNSjoins the cascade as channel-type 4; cascade order is now deterministic (APNs → Telegram → ntfy → Web Push) - Mock provider at
src/lib/notifications/senders/__mocks__/apns.tswith queued per-token responses + recorded calls - Integration test
tests/integration/apns-dispatch.test.ts— round-trip, hard-reject + cleanup, cascade fall-through (3 tests) POST /api/devicesaccepts pairedapnsToken+apnsEnvironment, enforces hex format, applies the cross-user-hijack guard at the APNs-token layer (409apns_token_owned_by_other_user)- Detailed report:
.planning/phase-W3-v1423-report.md
Wave 4 — OpenAPI + Coach schema + native auth + Coolify
F5 — OpenAPI 3.1 generator + CI gate
- Tool wired (W1 decision —
zod-openapi(samchungy) +yaml@^2) pnpm openapi:generatescript emitsdocs/api/openapi.yamlfrom Zod schemas- CI step compares generated vs committed; PR warns on drift
(
continue-on-error: true— flips to hard-fail in v1.4.24+) - Legacy hand-maintained spec preserved at
docs/api/openapi-v1422-legacy.yamlduring the incremental migration
F6 — Coach + Daily Briefing schema slot for new metrics
aiInsightResponseSchema.dailyBriefing.keyFindings[].sourceMetricenum extends to include the 9 Apple Health categories (hrv, sleep, resting_hr, steps, active_energy, flights, distance, vo2_max, body_temp)trendAnnotationsschema mirrors the same additive enumcoach/snapshot.tsqueries the new measurement types when scope toggles them on; web-only accounts pay zero extra SQLCoachProvenance.metrics+countsextended symmetrically- PROMPT_VERSION 4.22.0 → 4.23.0 with new GROUND RULE 12 ("treat Apple Health categories as silent when absent")
- EN + DE prompt bodies, OUTPUT FORMAT block, and i18n strings all updated
F7 — Native API hardening (refresh-token per-device)
- 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)
- New route
GET /api/auth/me/deviceslists active devices with last-seen, label, channels, isCurrent marker - New route
DELETE /api/auth/me/devices/[id]revokes one device (refresh + access tokens + Device row) - Alternate
DELETE /api/devices/[id]for the iOS token-rotation cleanup path (mirror of the auth/me variant) - Ownership-boundary 404 on cross-user attempts
F8 — Coolify auto-deploy fix for real
COOLIFY_WEBHOOK+COOLIFY_TOKENGitHub repo secrets documented (maintainer action; see.planning/coolify-auto-deploy-howto.mdfor the verbatim recipe)- Coolify "Watch image registry for new digests" UI toggle documented as the load-bearing piece (maintainer action — can't be flipped from CI)
- Workflow step gains a
::notice::line so future runs surface the deploy timestamp + sha without opening the verbose log - Verification recipe (
curl /api/version | jq .data.version) + host-side fallback documented inline
Wave 5 — Hygiene (H1-H7)
- H1 sentinel parser malformed-enum hardening
- H2 analytics-route unbounded
findManypagination - H3
<CoachDrawer key={prefill}>controlled-prop refactor - H4 per-user prompt-tuning surface (Coach settings cog return)
- H5 schema drift on
medication_schedules.days_of_week - H6 Pearson p-value normal-approx replacement
- H7 Coach helpful/unhelpful first-week observation view
Wave 6 — Multi-agent QA + Product-Lead review
- code-reviewer
- security review
- design / UX review
- senior-dev review
- simplify
- Product Lead — v1.5 P1 (iOS first launch) plan refresh with concrete file paths now that backend contracts exist
- Reconcile CRITICAL + HIGH; defer MED/LOW
Wave 7 — Release v1.4.23
- Pre-release verify
- Bump
package.json1.4.22 → 1.4.23 + CHANGELOG - Release-merge develop → main
- Tag + push v1.4.23
- GHCR build green
- Coolify deploy (auto, if F8 works; else host-side fallback)
- /api/version=1.4.23 confirmed
- Production smoke + e2e workflow on main passes
- GH release
- Docs site + landing site sync
docs/audit/v1423-summary.md(release brief)- v1.5 P1 plan refresh recorded