diff --git a/.planning/STATE.md b/.planning/STATE.md index 0af5f916a..9a040d3fa 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -1,7 +1,7 @@ # v1.5 marathon — state log -Status: phase-7-done -Last update: 2026-05-09T18:15:00+02:00 +Status: finished +Last update: 2026-05-09T18:35:00+02:00 > Previous milestone: see `docs/audit/v146-summary.md` (v1.4.6 marathon). > Codex-OAuth iteration v1.4.7 → v1.4.13 landed in CHANGELOG between @@ -130,6 +130,22 @@ Last update: 2026-05-09T18:15:00+02:00 - [ ] prod smoke screenshots saved - Detailed report: `.planning/phase-8-report.md` +### Phase 8 — Release v1.4.14 (rebrand patch deploy 2026-05-09) + +- [x] package.json bumped to 1.4.14 (commit `e5fae9b`) +- [x] CHANGELOG v1.4.14 section written +- [x] tag v1.4.14 pushed +- [x] GHCR tag-build green (run 25605648606, finished 16:29Z, pushed 1.4.14 + 1.4 + sha-e5fae9b + latest) +- [x] main-branch GHCR build cancelled (hung >45min on same SHA — harmless, tag build already published :latest) +- [x] Coolify deploy via host-side retag of `:1.4.14` → `:latest` (no compose-file edit) + `docker compose up -d app` +- [x] /api/version=1.4.14 confirmed (live in 0s after recreate) +- [x] image digest changed: `791c2cd2…` → `0ced46004a54…` +- [x] prod smoke (curl with session cookie): /, /auth/login, /settings/integrations, /admin all 200 +- [x] GitHub release v1.4.14 published: https://github.com/MBombeck/HealthLog/releases/tag/v1.4.14 +- Note: GHCR OCI tag is `:1.4.14` (no `v` prefix) — git tag is `v1.4.14`. Hard-rule's `:v1.4.14` slug needs a docs fix. +- Result: ok / no new commits (planning-only deploy) +- Detailed report: `.planning/phase-8-report.md` + ## Phase 9 — Docs + landing sync - [x] healthlog-docs updated to v1.5 — Codex device-code rewrite, new @@ -152,5 +168,12 @@ Last update: 2026-05-09T18:15:00+02:00 ## Phase 11 — Final summary doc -- [ ] docs/audit/v15-summary.md with Marc-Brief -- Detailed report: `.planning/phase-11-report.md` +- [x] `docs/audit/v1414-summary.md` written with Marc-Brief (DE, + ≤200 words at top), commit history table, deferred items, CI + status, prod state, Codex-OAuth resolution, v1.4.15 backlog seed +- [x] STATE.md status flipped to `finished` +- Result: ok / commit `` (single + `docs(audit): v1.4.14 release summary` commit, push to origin/main) +- Marathon completed 2026-05-09T18:35+02:00 — v1.4.14 LIVE in prod, + /api/version=1.4.14, image digest 0ced46004a54… +- Detailed report: this file diff --git a/docs/audit/v1414-summary.md b/docs/audit/v1414-summary.md new file mode 100644 index 000000000..47666d308 --- /dev/null +++ b/docs/audit/v1414-summary.md @@ -0,0 +1,337 @@ +# HealthLog v1.4.14 — Release Summary + +## Marc-Brief (DE, ≤ 200 Wörter) + +✅ **v1.4.14 ist live** auf `https://healthlog.bombeck.io` — Image-Digest +`sha256:0ced46004a54…` (vorher v1.4.12: `791c2cd2…`), `/api/version` +meldet `1.4.14`. + +🆕 **Was ist neu** + +- **Codex/ChatGPT-Modell-Slug korrigiert** auf `gpt-5.3-codex` — KI- + Insights laufen jetzt direkt mit deinem ChatGPT-Login durch, kein + API-Key nötig. Operator-Override per `CODEX_MODEL`-Env-Var möglich. +- **Admin-Bereich auf Unterseiten aufgeteilt** (`/admin/users`, + `/admin/backups`, `/admin/system-status`, `/admin/integrations`, …) — + bessere Übersicht, schnelleres Laden, Status-Cards verlinken direkt. +- **Neue Backups-Sektion** mit Tabelle aller bisherigen Sicherungen und + „Backup jetzt erstellen“-Knopf. +- **Neue User-Verwaltung** mit Rollen-Filter und „Force-Logout"-Aktion + (eigene Session ist gesperrt). +- **„Gespeicherten KI-Schlüssel entfernen"** als eigener Knopf in + Settings → KI. +- **Trend-Pfeile sind jetzt metrik-bewusst** — Blutdruck ↑ orange, + Stimmung ↑ grün, Puls ↑ neutral. + +🔧 **Was ist gefixt** + +- Notification-Channels + Push-Subscriptions werden jetzt vom „Alle + Daten löschen“ tatsächlich entfernt. +- DST-Wechsel verschiebt keine Tageswerte mehr in Cross-Metric-Joins + (war zwei Tage/Jahr falsch). +- KI-Provider-Fehler werden korrekt klassifiziert (422/503/429 statt + pauschal 500). +- Logging-Redactor verschluckt keine harmlosen Wörter wie `task-force` + oder `risk-management` mehr. + +⚡ **Performance** + +- `/insights` initiales JS −108 KiB (Recharts deferred geladen). +- Dashboard-Checklist Netzwerk −950 ms für Bestandsnutzer. + +⚠️ **Hard-Reload** (`Cmd+Shift+R`) für den einmaligen Service-Worker- +Reset einplanen. + +📚 **Docs** auf `docs.healthlog.dev` und Landing aktualisiert. +🎯 **v1.4.15 Backlog**: `.planning/v1415-backlog.md`. + +--- + +## Was gelandet ist + +53 Commits seit `v1.4.13` (`5df74f7..e5fae9b`). Severity-geordnet. + +### Release + +| SHA | Summary | +| --------- | ------------------------------------ | +| `e5fae9b` | chore(release): v1.4.14 | +| `f0d53fb` | chore(release): rebrand artifacts as v1.4.14 (patch, not minor) | + +### Codex-OAuth verification (Phase 1) + +| SHA | Summary | +| --------- | ---------------------------------------------------------------------- | +| `5df74f7` | fix(ai): default Codex model to `gpt-5.3-codex` for ChatGPT-account auth | + +### v1.4.6 deferred bugfix backlog (Phase 2) + +| SHA | Summary | +| --------- | -------------------------------------------------------------------- | +| `512a6a6` | fix(admin): wipe-all-data clears notification channels, push subs, telegram deletions (T2.1) | +| `cb6a59a` | fix(insights): correct DST handling in cross-metric daily bucket pairing (T2.2) | +| `5403821` | fix(insights): map AI provider errors to 422/503 instead of 500 (T2.3) | +| `d6696cf` | fix(logging): redactSecrets regex requires non-alphanumeric prefix (T2.5) | + +### Admin Panel refactor (Phase 4b — folds T2.6 + T2.7) + +| SHA | Summary | +| --------- | ------------------------------------------------------------------------ | +| `d8b71b3` | feat(admin): scaffold per-section dynamic routes (admin-shell + [section]/page.tsx) | +| `12b280b` | refactor(admin): move sections to dynamic-route pattern + reduce overview | +| `69c5225` | feat(admin): backups view + manual backup trigger (T2.6 deferred) | +| `5957e18` | feat(admin): users management with filters + force-logout action (T2.7 deferred) | +| `a34cd8c` | refactor(i18n): namespace admin keys under `admin.section..*` | +| `73965cd` | feat(admin): expandable sidebar nav for admin sections | +| `961e2a9` | fix(admin): status-card CTAs use real routes (not `#anchor`) | +| `7a47532` | feat(admin): redirect legacy section-anchor paths to dynamic routes | +| `1a7e3d6` | test(admin): tighten status-card-grid + add per-section render smoke | + +### UX polish (Phase 5) + +| SHA | Summary | +| --------- | ------------------------------------------------------------------------ | +| `987ce0d` | fix(a11y): clear axe-core violations on `/admin` and key sub-routes | +| `38f12df` | feat(ui): trend arrow color reflects metric-specific direction sentiment | +| `788c8ad` | feat(settings): allow removing saved AI provider key | +| `569300e` | style(ui): use semantic tokens for mood and feedback indicators | +| `e3a6899` | fix(ui): disambiguate dashboard quick-add menu items | +| `65cfb27` | fix(a11y): label `/admin` overview quick-jump as a navigation landmark | + +### Multi-agent QA reconcile (Phase 6) + +| SHA | Summary | +| --------- | ------------------------------------------------------------------------ | +| `88c8db1` | refactor: apply simplify-review safe-to-apply suggestions (11 of 11) | +| `b3f282a` | fix(security): block force-logout from targeting the admin's own session | +| `8e17f22` | fix(admin): rate-limit `/api/admin/backups/run` to 3/min per admin | +| `f0cfd26` | fix(security): redact standalone `hlk_` / `hlr_` native API tokens in logs | +| `bd24f13` | fix(a11y): drop duplicate h2 inside single-section `/admin/` routes | +| `499cfad` | fix(a11y): bump `/admin/users` + `/admin/login-overview` tap targets to WCAG 2.5.5 | +| `ef96e87` | fix(admin): default api-tokens + login-overview routes to expanded | + +### End-to-end test coverage (Phase 3) + +| SHA | Summary | +| --------- | -------------------------------------------------------- | +| `535465c` | test(e2e): seeded test user + auth storageState fixture | +| `3999ea7` | test(e2e): authenticated dashboard + add-measurement flow | +| `2b6f959` | test(e2e): mocked Codex device-flow + insights regenerate specs | +| `a106547` | test(e2e): doctor-report PDF + mobile-viewport smoke | +| `ca3c599` | test(e2e): extend axe-core to authenticated surfaces; fix login regex | +| `7af1f59` | fix(a11y): close violations the new e2e axe-core sweep surfaced | + +### Performance (Phase 4) + +| SHA | Summary | +| --------- | -------------------------------------------------------- | +| `bb2b1de` | perf(insights): defer Recharts ScatterChart imports via `next/dynamic` | +| `519e36e` | perf(dashboard): skip checklist API fetches once onboarding is complete | +| `1a85da0` | fix(insights): preserve chart visual parity in deferred bundle | +| `41fa203` | docs(audit): v1.4.14 performance audit report | + +### CI / housekeeping + +| SHA | Summary | +| --------- | -------------------------------------------------------- | +| `3cacdf2` | fix(tests): share next/headers cookieJar across integration suite | +| `c847b80` | chore(format): trend-card test file prettier sweep | +| `badd380` | style(admin): apply prettier to phase-6 reconcile changes | +| `6b88e56` | chore(format): prettier sweep over phase-2 touched files | + +--- + +## Was deferred wurde + Warum + +### v1.4.14-Marathon "Apply autonomously? no" simplify findings (8) + +Aus `phase-6-simplify-findings.md`: + +- **F5** Defensive `notFound()` hinter `dynamicParams = false` — Marc + soll zwischen (a) Kommentar trimmen vs. (b) Guard droppen + casten + entscheiden. +- **F9** `` in `renderer.tsx` switch — die Repetition ist + echt, aber das Tabellen-Refactor wäre schlechter (asymmetrische + `currentUserId`-Prop). Recommend: keep as-is. +- **F10** `if (!user || user.role !== "ADMIN") return null` doppelt — + zwei Sites, unter dem 4-uses-Threshold. Recommend: keep. +- **F12** Historische Anker-Kommentare (`v1.4.6 T2.6`, `P15`, + `v1.4.7.1`, …) — judgement-call sweep; ein Teil enthält echtes + WHY-Wissen, ein Teil ist Archäologie. +- **F13** ~270 LOC duplication in den drei Status-Generatoren + (mood/weight/blood-pressure) — `_status-helpers.ts`-Extraktion ist + medium-risk, braucht fokussierten Pass + Tests. +- **F14** `formatBytes(fmt: ReturnType)` — + cosmetic. +- **F18** `getApiErrorMessage` doppelter Fallback-Branch — cosmetic. +- **F19** `eslint-disable-next-line react-hooks/exhaustive-deps` auf + Device-Code-Polling — verifizieren, ob `t`/`queryClient`-deps eine + Re-poll-Loop auslösen. + +### v1.4.6 P4+ Items (nicht aufgenommen) + +`useAdminSettings` / `useSystemStatus` Test-Coverage für die +`isError`-UI aus P19 ist weiter manuell-only — nicht in v1.4.14 +gepflegt, kein Regressionsrisiko. Trägt sich in den v1.4.15-Backlog. + +### 4 HIGH findings → v1.4.15 + +Aus `phase-6-reconcile-report.md`: + +- **H4d/H5d design — StatusCardGrid i18n** (Englisch-only + Severity-Labels, Card-Titel/-CTAs, `fmtRelative`/`fmtUptime`, + StatusBadge-aria-label). ~15 Keys × 2 Locales + Test-Rewrite — zu + breit für sicheren Overnight-Apply. +- **H2 code-review — Admin-Page server-side `requireAdmin()`**. Heute + ist die Rolle nur client-seitig geprüft; das Shell flackert kurz. + Braucht eine server-rendered `requireAdmin()`-HOC, präzisiert für + Marcs Auth-Stack. +- **H-1 security — "Wipe all data"-Scope-Drift**. v1.4.14 hat + Notification-Channels, Push-Subs und Telegram-Scheduled-Deletions + ergänzt. Was weiter überlebt: `MoodEntry`, `RefreshToken`, + `DataBackup`, `Device`, `UserAchievement`, `IdempotencyKey`, plus + einige verschlüsselte Spalten. Entscheidung pending: (a) Scope + nochmal weiten oder (b) Operation umbenennen ("Reset health data"). + +--- + +## CI / Test status + +- `pnpm typecheck` — clean +- `pnpm lint` — 0 errors / 12 pre-existing warnings (none introduced) +- `pnpm format:check` — clean nach `c847b80` (trend-card test file + sweep) +- `pnpm test` — **97 files / 754 tests** green +- `pnpm test:integration` — 5 files / 11 tests green; mock-leak flake + zwischen `admin-data-wipe.test.ts` und `idempotency-replay.test.ts` + via `tests/integration/mock-next-headers.ts` shared cookieJar + behoben (10/10 consecutive runs grün) +- `pnpm build` — fails lokal auf Node 25 (`Reflect.get` private-member + bug); CI Docker (Node 22) ist canonical +- `pnpm e2e` — gleicher Node-25-Bug betrifft auch `next dev`; CI runs + green auf Node 22 (Phase-3 Report: 41/41 specs green) + +--- + +## Production state + +- **URL**: `https://healthlog.bombeck.io` +- **`/api/version`**: `1.4.14` ✓ +- **Image digest**: `sha256:0ced46004a544a311627b7036f2f2aed75861b0c62576214a1303a17d20c3d22` + (vorher v1.4.12: `sha256:791c2cd2a8eae5ec0a6fd666074c9f646c17414e3521d526267131c2a3b7edab`) +- **Smoke** (curl mit Session-Cookie): `/`, `/auth/login`, + `/settings/integrations`, `/admin` — alle 200 +- **Deploy-Methode**: `:1.4.14` von GHCR auf den Host gepullt, dort als + `:latest` retagged (kein Compose-Edit), dann `docker compose up -d +app` in `/data/coolify/applications/pg8wggwogo8c4gc4ks0kk4ss/`. Der + parallele `main`-Branch-GHCR-Run war auf demselben SHA hängengeblieben + (>45 min), wurde gecancelt — harmlos, weil der Tag-Build `:latest` + bereits gepusht hatte. Retag-on-host war defensiv aber sicher. +- **GitHub Release**: https://github.com/MBombeck/HealthLog/releases/tag/v1.4.14 +- **Tag-Naming**: GHCR-OCI-Tag ist `:1.4.14` (kein `v`-Prefix); + git-Tag ist `v1.4.14`. Hard-Rule's `:v1.4.14`-Slug needs a docs fix. + +--- + +## Codex-OAuth Status (das v1.4.7–v1.4.13 Saga-Ende) + +- **Resolution**: ChatGPT-Account-Auth verlangt das Modell-Slug + `gpt-5.3-codex`. Das ist canonical, gepflegt aus + `openai/codex` → `codex-rs/models-manager/models.json`. Sowohl + `gpt-5-codex` als auch das v1.4.13-Fallback `gpt-5` werden vom + Codex-Backend mit ChatGPT-Subscription explizit abgelehnt + (`The 'gpt-5' model is not supported when using Codex with a ChatGPT +account.`). +- **Spec extension**: `docs/codex-protocol-spec.md` §7a dokumentiert + jetzt die ChatGPT-Account-Auth-Allow-List + die Lehre, dass die Slugs + in `model_migration.rs` Migration-_Prompts_ sind, keine Wire-Slugs. +- **Operator-Override**: `CODEX_MODEL`-Env-Var auf apps-01 lässt + alternative Slugs ohne Rebuild testen — als Sicherheitsnetz für + andere Plan-Tarife oder zukünftige OpenAI-Slug-Wechsel sinnvoll. +- **Live-Probe verifiziert**: `/api/ai/test` und + `/api/insights/generate` laufen beide gegen Marcs ChatGPT-Plus-Abo + durch. `/tmp/v15-codex-working.png` zeigt das grüne "ChatGPT + connected"-Badge in `/settings/ai`. + +--- + +## Docs / Landing + +- **healthlog-docs** (Starlight) — 7 Files aktualisiert: AI-Insights + (Codex device-code-Pfad neu), Admin-Settings (Backups + Users + Sektionen), Environment-Variables (`CODEX_MODEL`), Updates (Backups- + View), Introduction (One-Click Codex-Flow), Troubleshooting + (Codex-Failure-Modes), Dashboard-Customization (Perf-Note). + Commit `06bc616`. Coolify auto-redeploys docs.healthlog.dev. +- **healthlog-landing** (Next.js) — `softwareVersion 1.4.6 → 1.4.14` + in JSON-LD; AI-Providers-Copy auf "one-click device-code Codex + flow, no API plan needed" angepasst. Commit `92c6588`. + +--- + +## GitHub releases + +`v1.4.7` … `v1.4.13` waren bereits real-time während des +Codex-OAuth-Iterationstags veröffentlicht; nur `v1.4.13` war pending +und wurde nachgezogen. `v1.4.14` selbst ist jetzt als Latest geflagged. + +--- + +## Empfohlener v1.4.15 Backlog + +Aus `.planning/v1415-backlog.md` (severity-geordnet, Datei:Zeile, ein +Satz Recommendation pro Item). Top-Hits: + +### HIGH + +- **H4d+H5d** — `StatusCardGrid` i18n: Severity-Labels, Card-Titel, + CTAs, `fmtRelative`, `fmtUptime`, StatusBadge-aria-label nach + `admin.statusGrid.*` migrieren (EN+DE Parität, ~15 Keys × 2 Locales). +- **H2** — `requireAdmin()` server-side auf `/admin/[section]/page.tsx` + und `/admin/page.tsx` ziehen, damit Non-Admins 403 sehen, bevor das + Shell paint-flickert. +- **H-1** — "Wipe all data" Entscheidung: (a) Scope auf `MoodEntry`, + `RefreshToken`, `DataBackup`, `Device`, `UserAchievement`, + `IdempotencyKey` + verschlüsselte Codex/AI/moodLog-Spalten weiten, + oder (b) Operation umbenennen ("Reset health data") und "preserved"- + Liste explizit zeigen. Recommend (a) für GDPR-Art-17-Alignment. + +### MEDIUM (Highlights) + +- **M-2 security** `/api/admin/users/[id]/force-logout` ohne Rate-Limit + und ohne Last-Admin-Guard. +- **M-3 security** Wide-Event-`meta`-Strings nicht durch + `redactSecrets()` gezogen — `addMeta()` braucht den Filter. +- **M-5 security** Wipe-Rate-Limit BEFORE auth — unauth'd Traffic + mutiert `rate_limits`. Reorder: `requireAdmin()` zuerst, dann key by + `user.id`. +- **M1 code-review** `/insights` TrendCard-Tile-Strip noch ohne + `directionSentiment` verdrahtet (war v1.4.14 nur Dashboard). +- **M2 code-review** Legacy-Admin-Anchor-301s leaken Slug-Existenz an + unauth'd Hits — Redirect-Block muss NACH dem Session-Check. +- **M3 code-review** `BackupsSection` 2-Sek-Timeout für Refetch ist ein + Guess — auf 5–8s mit Double-Invalidate, oder Job-State pollen. + +### LOW + +- **L-1 security** `/api/auth/codex/callback` als PUBLIC_PATH gelistet, + aber kein Route-File existiert — Eintrag aus `proxy.ts` löschen. +- **L-2 security** Codex `codex_device`-Cookie ohne Per-User-Binding + — `userId` in den encrypted Blob einbetten, Mismatch rejecten. +- **L7 design** `/insights` Sticky-`