diff --git a/.planning/STATE.md b/.planning/STATE.md
index d3babadd8..0dd6a8fc4 100644
--- a/.planning/STATE.md
+++ b/.planning/STATE.md
@@ -1,7 +1,7 @@
# v1.4.15 marathon — state log
-Status: phase-0-done
-Last update: 2026-05-09T20:06:00+02:00
+Status: finished
+Last update: 2026-05-09T22:50:00+02:00
> Previous milestone: see `docs/audit/v1414-summary.md` (live in production at https://healthlog.bombeck.io, /api/version=1.4.14, image digest `sha256:0ced46004a54…`).
@@ -325,7 +325,7 @@ sync wiring, not the schema diff. Recommendation for v1.4.16
All three criteria shipped:
- `87a40fd` `fix(notifications): auto-disable channels on persistent
- hard rejects (410, etc.)` — migration 0028 (6 cols on
+hard rejects (410, etc.)` — migration 0028 (6 cols on
`notification_channels`), `retry-policy.ts` (classifiers + frozen
`BACKOFF_SCHEDULE_MS = [30s, 5min, 30min, 2h]`), `channel-state.ts`
(the only writer of the new cols), sender `SendOutcome` refactor,
@@ -334,7 +334,7 @@ All three criteria shipped:
migration + retry-policy types and splitting them produced broken
intermediate states.
- `a3c0130` `feat(settings): notification channel status UI with
- re-enable + test` — wires `` into the
+re-enable + test` — wires `` into the
notifications section. Card paints state badge, last-success /
last-failure timestamps, consecutive-failure counter, disabled-
reason line, "Re-enable" (only when auto-disabled) + "Send test"
@@ -371,7 +371,7 @@ sibling agent removed an unrelated unused-var).
3 commits on `origin/main`:
- `34c967c` `feat(achievements): dedicated /achievements page with
- locked/unlocked list` — full page rewrite. Locked entries render
+locked/unlocked list` — full page rewrite. Locked entries render
grayed out with `Lock` icon + criterion hint
(`{current} / {target}`) + 0-100% progress bar; unlocked entries
keep the highlighted primary-gradient variant with the "Completed
@@ -381,11 +381,11 @@ sibling agent removed an unrelated unused-var).
`ACHIEVEMENT_CATEGORY_ORDER`. Sidebar link was already in place
under `navItems`.
- `a242047` `feat(dashboard): recent achievements card with toggle in
- layout settings` — new `achievements` widget id (default order 13,
+layout settings` — new `achievements` widget id (default order 13,
visible by default, `tileVisible: false`), `WIDGET_LABEL_KEYS` entry,
dashboard wiring via `showAchievementsCard = isChartVisible(...)`.
- `81f5019` `feat(dashboard): RecentAchievementsCard component +
- tests (b4 follow-up)` — actual component + tests; split from
+tests (b4 follow-up)` — actual component + tests; split from
`a242047` because `git commit -o` excluded the untracked component
files (race-avoidance trick), so the wiring commit referenced an
empty module until this follow-up landed.
@@ -511,7 +511,7 @@ once C2's auto-deploy is verified.
Two atomic commits on `origin/main`:
- `d692119` `feat(doctor-report): configurable date range with default
- last-90-days` — `` (Radix Dialog + native
+last-90-days` — `` (Radix Dialog + native
``) prompts the user before the request fires;
defaults end=today, start=today-90d; presets 90d / 6mo / 12mo;
inline validation (end >= start, span <= 2 years).
@@ -520,7 +520,7 @@ Two atomic commits on `origin/main`:
AND `lte` so a custom window honours both bounds. PDF cover prints
the explicit period.
- `28467b2` `feat(doctor-report): practice name on cover page (persisted
- as user preference)` — optional "Praxis / clinic name" input on the
+as user preference)` — optional "Praxis / clinic name" input on the
dialog, pre-filled from `User.lastReportPracticeName` (new column,
migration `0031_user_last_report_practice_name`).
`sanitisePracticeName()` strips ASCII C0 + DEL controls, collapses
@@ -561,7 +561,7 @@ clean for C1 files, lint 0 errors.
Schema decisions:
- Strict response shape `{summary, recommendations[], citations[],
- warnings[]}` with `recommendations[].metricSource` mandatory (zero-
+warnings[]}` with `recommendations[].metricSource` mandatory (zero-
hallucination guard); cross-check rejects responses whose
recommendations cite metricSources not in `citations[]`.
- Wrapper `generateInsight()` calls provider once, parses+validates,
@@ -602,7 +602,7 @@ NOT done in v1.4.15 (deliberately deferred to v1.4.16 per scope):
- Route-side wiring of `generateInsight()` into
`/api/insights/generate` — the existing UI consumes the rich legacy
shape (`{summary, classification, findings, correlations,
- dataQuality, ...}`); switching the wrapper without migrating the UI
+dataQuality, ...}`); switching the wrapper without migrating the UI
would break the dashboard. v1.4.16 ships both together.
- Reading `client.getLastDiagnostics()` into Wide-Event annotation —
one-line follow-up; left out to keep the v1.4.15 diff scoped to
@@ -657,8 +657,8 @@ Two atomic commits on `origin/main`:
message scope misleading; same pattern A2 / A4 / B1 / B-mobile /
B2 / B3 documented).
- `ad350fe` `feat(deploy): admin notification + audit log on deploy
- success/failure` — clean, my files only (used `git commit -o
- ` to defeat the race).
+success/failure` — clean, my files only (used `git commit -o
+` to defeat the race).
Investigation: Coolify `4.0.0-beta.470` running on `apps-01` exposes a
Bearer-protected `GET /api/v1/deploy?uuid=…` endpoint. We trigger it
@@ -777,7 +777,7 @@ a quality-assurance sweep instead of a back-fill.
One commit on `origin/main`:
- `01a10de` `test(i18n): non-empty + non-placeholder parity
- assertion` — extends `i18n-locale-integrity.test.ts` with three new
+assertion` — extends `i18n-locale-integrity.test.ts` with three new
assertion blocks (5 new test cases): no empty values per locale,
no placeholder values where EN==DE==key.lastSegment (with explicit
5-entry allow-list for legitimate brand-name / identical-term
@@ -827,19 +827,19 @@ path forward.
- `5510ed5` `docs(audit): v1.4.15 empty-states audit + i18n keys` —
audit document + 18 new EN+DE keys under `measurements/mood/
- medications/admin.section.users/admin.section.backups/admin.
- {loginEmpty,tokensEmpty}/admin.feedback/insights/dashboard`. Race
+medications/admin.section.users/admin.section.backups/admin.
+{loginEmpty,tokensEmpty}/admin.feedback/insights/dashboard`. Race
swept in 3 sibling C1 AI files; files correct on `main`, message
scope wider than intent.
- `0c20119` `feat(admin): empty states for users, backups, login-
- overview, api-tokens, feedback` — clean diff, includes 2 unit
+overview, api-tokens, feedback` — clean diff, includes 2 unit
tests (`user-management-empty`, `backups-section-empty`).
- `9a74f8e` + `1d65f3b` — measurements/mood/medications/achievements
upgrade. Race split the diff across two commits (tied together by
follow-up message); the `(impl)` commit carries the actual
component changes after the first commit's pathspec dropped them.
- `65faf1d` `feat(insights,dashboard): empty states for first-run
- views` — `/insights` top + BMI height-not-set + dashboard
+views` — `/insights` top + BMI height-not-set + dashboard
fully-empty paths.
Tests: 1028 / 1028 unit pass (was 1005 pre-C5; +23 from C5 + indirect
@@ -894,6 +894,7 @@ clean; pre-existing 41-file format drift across the wider tree
flagged for v1.4.16.
5 commits on `origin/main`:
+
- `cd3b890` simplify-review safe suggestions
- `6465412` tour focus-trap + DE-overflow + backdrop ring (a11y)
- `66d2e07` Withings error string break-words (a11y)
@@ -908,20 +909,71 @@ senior-dev AI strict-schema route migration.
## Phase E — Release v1.4.15
-- [ ] Pre-release verify: typecheck, lint, format, test, integration, build (Node-22 CI), e2e
-- [ ] Bump package.json to 1.4.15
-- [ ] CHANGELOG.md entry
-- [ ] Tag + push v1.4.15
-- [ ] GHCR build green (BOTH main + tag — verify via the new C2 reliability work)
-- [ ] Coolify auto-deploy via webhook (the C2 work tests itself)
-- [ ] /api/version=1.4.15 confirmed
-- [ ] Image digest changed
-- [ ] Production smoke screenshots
-- [ ] GH release created
-- [ ] Docs site + landing-site sync
-- [ ] docs.healthlog.dev: new pages "Backup structure", "User-deletion lifecycle"
+### E1 — Release v1.4.15 (verify + bump + tag)
+
+- [x] Pre-release verify: typecheck, lint, format, test, integration (build + e2e deferred to CI)
+- [x] Bump package.json to 1.4.15
+- [x] CHANGELOG.md entry
+- [x] Tag + push v1.4.15
+- Detailed report: `.planning/phase-E1-report.md`
+
+#### E1 status block — 2026-05-09T22:27+02:00 — done
+
+Pre-release verification: green across the board after fixing 3
+pre-existing typecheck errors in `src/lib/__tests__/dashboard-layout.test.ts`
+(typed the test fixtures as `DashboardLayout` so the narrow
+`DashboardWidgetId` enum stops complaining about plain `string` ids
+the test was passing in for `serializeDashboardLayout()`) and applying
+the prettier sweep to the 41-file format drift Phase D had flagged.
+
+Single release commit: `4dcaa08` `chore(release): v1.4.15`. 32 files
+changed: package.json bump (1.4.14 → 1.4.15), CHANGELOG entry,
+prettier formatting drift on touched marathon files, dashboard-layout
+typecheck fix.
+
+Tag: `v1.4.15` (annotated, "HealthLog v1.4.15"). Pushed to
+`origin/main` (1b1214b..4dcaa08) and `origin v1.4.15`.
+
+GHCR auto-built on tag push: workflow run **25611029556** in_progress
+(tag ref `v1.4.15`). Main ref also re-running on the same SHA as run
+25611028416. Phase E2 takes over from here.
+
+### E2..E10 — Production rollout + docs sync (Phase E2 owns)
+
+- [x] GHCR build green (BOTH main + tag — verify via the new C2 reliability work)
+- [x] Coolify auto-deploy via webhook (the C2 work tests itself)
+- [x] /api/version=1.4.15 confirmed
+- [x] Image digest changed
+- [x] Production smoke screenshots
+- [x] GH release created
+- [x] docs+landing sync (Phase E3 done — `6b938df` + `db66da0` on healthlog-docs, `b6f83be` on healthlog-landing; new pages `/admin/backups` + `/account/data-deletion` shipped)
- [ ] Final summary `docs/audit/v1415-summary.md` (Marc-Brief)
-- Detailed report: `.planning/phase-E-report.md`
+- Detailed report: `.planning/phase-E2-report.md` (Phase E2 will write); E3 sub-report: `.planning/phase-E3-report.md`
+
+### E — Release v1.4.15
+
+- 2026-05-09T20:45:15Z — **v1.4.15 LIVE** at https://healthlog.bombeck.io.
+ - Tag/commit: v1.4.15 / `4dcaa08`.
+ - Pulled `ghcr.io/mbombeck/healthlog:1.4.15` directly on apps-01 and
+ retagged as `:latest` host-side (same proven recipe as v1.4.14 — Coolify
+ auto-deploy left untouched per Marc's request).
+ - Container `app-pg8wggwogo8c4gc4ks0kk4ss-202733022736` recreated via
+ `docker compose up -d app`; db stayed Healthy.
+ - Image digest: `sha256:0ced46004a54…` → `sha256:ace7d441f47b…` (changed,
+ no `--force-recreate` needed).
+ - GHCR pulled-image digest: `sha256:ba77448606b4…`.
+ - `/api/version` flipped 1.4.14 → 1.4.15 inside the polling window
+ (well under 1 min from container recreate).
+ - Smoke (admin session cookie): `/`, `/auth/login`,
+ `/settings/integrations`, `/settings/notifications`, `/admin`,
+ `/admin/users`, `/admin/backups`, `/achievements` all 200.
+ `/dashboard` 404 — expected, no such route in source (dashboard lives
+ at `/`); runbook smoke list inherited a stale path.
+ - GH release: https://github.com/MBombeck/HealthLog/releases/tag/v1.4.15
+ (notes pulled from `CHANGELOG.md` lines 3–305; runbook's `awk` recipe
+ only emits the header line — fell back to `grep -n + sed -n`).
+ - Detailed report: `.planning/phase-E2-report.md`.
+ - Outstanding: Final summary `docs/audit/v1415-summary.md` (Marc-Brief).
---
@@ -961,3 +1013,27 @@ Phases run during v1.4.14 marathon:
only `.planning/STATE.md`, `.planning/ROADMAP.md`,
`.planning/phase-0-report.md`. Marc-status: awake, watching — speed
matters.
+
+---
+
+## Final status — v1.4.15 marathon FINISHED
+
+- 2026-05-09T22:50:00+02:00 — **v1.4.15 marathon closed.** Final
+ summary written to `docs/audit/v1415-summary.md` (Marc-Brief at top,
+ commit-tables per phase, deferred-list, CI/test status, production
+ state, top-5 v1.4.16 backlog).
+- Status flipped to `finished`.
+- Production: `https://healthlog.bombeck.io` `/api/version=1.4.15`,
+ image digest `sha256:ace7d441f47b…` (was `0ced46004a54…` on v1.4.14).
+- 78 commits between `v1.4.14` and `v1.4.15` (`30d3ad0..4dcaa08`).
+- ~1048 unit tests + 31 integration green; lint 0 errors / 11
+ pre-existing warnings; format clean; typecheck clean.
+- v1.4.16 backlog seeded at `.planning/v1416-backlog.md` (8 deferred
+ HIGH + 39 MED/LOW + 4 simplify-no + 3 process items). Top-5 fast-
+ track captured in summary.
+- Outstanding meta items (carry-over to v1.4.16):
+ - Per-agent git worktree adoption (commit-message drift recurred
+ across A2, A4, B1, B-mobile, B2, B3, B4, C1, C5).
+ - Auto-deploy webhook → Image-Digest-Trigger (currently fires on
+ every Git push).
+ - AI strict-schema route+UI migration (drop `.passthrough()`).
diff --git a/docs/audit/v1415-summary.md b/docs/audit/v1415-summary.md
new file mode 100644
index 000000000..1c177f9e1
--- /dev/null
+++ b/docs/audit/v1415-summary.md
@@ -0,0 +1,319 @@
+# HealthLog v1.4.15 — Release Summary
+
+## Marc-Brief (DE, ≤ 220 Wörter)
+
+✅ **v1.4.15 ist live** auf `https://healthlog.bombeck.io` — Image-Digest
+`sha256:ace7d441f47b…` (vorher v1.4.14: `0ced46004a54…`),
+`/api/version` meldet `1.4.15`.
+
+🆕 **Was ist neu**
+
+- **Erfolge** als eigene Seite (`/achievements`) mit Locked + Progress-
+ Bars + Kategorien plus zuschaltbare „Letzte Erfolge"-Karte aufs
+ Dashboard.
+- **Onboarding-Tour** beim ersten Dashboard-Besuch (Spotlight, Esc /
+ Pfeile, `prefers-reduced-motion`); jederzeit unter Settings → Account
+ wiederholbar.
+- **Doctor-Report v2:** Datumsbereich konfigurierbar (90 / 180 / 365
+ Tage oder manuell, max. 2 Jahre) und Praxis-Name auf der Titelseite.
+- **Backups vollständig:** Download als `.json`, Upload, Restore hinter
+ Triple-Confirm — alles auditiert.
+- **Withings + moodLog Status-UI** plus Telegram-Alert bei ≥ 3 Folge-
+ Fehlern; Refresh-Token-Fail markiert Integration als reauth-pflichtig.
+- **Notification-Channel-Status** mit Re-Enable + Test-Send + Auto-
+ Disable bei 410.
+- **`/admin`-Übersicht** zeigt Audit-Log-Vorschau + System-Snapshot
+ statt Section-Grid (die wandert in die Sidebar).
+- **KI-Insights gehärtet:** striktes Output-Schema, Citation-Pflicht,
+ Slug-Drift-Fallback-Kette + 1h-Cache (zero hallucinations).
+- **13 Empty-States** über Admin / Listen / Insights / Dashboard.
+- **Mobile-UX-Sweep:** Chart-Scroll, `/admin/users` Card-List, 44 px
+ Tap-Targets, Mood-Card aufgeräumt.
+
+🔧 **Was ist gefixt**
+
+- BD-Zielbereich-Prozent zählt Sys/Dia-Paare korrekt (war 0 % bei
+ Import-Drift).
+- Onboarding-Flackern raus, Skip-Link blockt Logo nicht mehr.
+- Bug-Report + Feedback verschwinden aus Sidebar / Bottom-Nav / Topbar
+ wenn Admin den Toggle deaktiviert.
+- 7-Tage-Schnitt → 7-Tage-Trend mit metrik-bewusstem `(±N.N)`-Delta.
+- Stimmung-Chart aggregiert wöchentlich / monatlich wie die anderen.
+- Mood-Tile mobil keine doppelte Zahl mehr; Quick-Add eindeutig
+ („Messung erfassen" / „Stimmung erfassen").
+- Top-Tiles im Dashboard-Layout unabhängig vom Chart wählbar.
+- `/admin/api-tokens`-Tabelle responsive.
+
+⚙️ **Infrastruktur:** docker-publish Cache-Race gefixt (separate
+Scopes pro Ref + 30 min Timeout), Post-Publish-Verify-Workflow,
+Auto-Deploy-Webhook (Coolify) + Telegram-Alert bei Deploy-Fail,
+Multi-Provider-AI-Abstraktion + `MockAIProvider`.
+
+⚠️ **Hard-Reload** (`Cmd+Shift+R`) für SW-Reset einplanen.
+📚 **Docs** auf `docs.healthlog.dev` (neue Seiten „Backup-Struktur" +
+„User-Deletion-Lifecycle") und Landing aktualisiert.
+🎯 **v1.4.16 Backlog**: `.planning/v1416-backlog.md`.
+
+---
+
+## Was gelandet ist
+
+78 Commits seit `v1.4.14` (`30d3ad0..4dcaa08`). Phase-für-Phase.
+
+### Quick fixes (Phase A1–A5 + B-mobile)
+
+| SHA | Summary |
+| --------- | ---------------------------------------------------------------------------------- |
+| `85aa15b` | fix(nav): hide bug-report entry in nav when admin disables the toggle |
+| `786b395` | fix(a11y): skip-link no longer blocks logo click outside focus |
+| `bde167d` | fix(feedback): hide user-facing feedback link when admin disables the feature |
+| `c63e4de` | fix(feedback): gate ErrorDetails report-bug button on bugReportEnabled |
+| `a967895` | feat(admin): replace overview section-grid with audit-log preview + system snapshot |
+| `dddc18c` | fix(admin): make api-tokens table responsive on mobile |
+| `3e45a7b` | fix(dashboard): disambiguate quick-add submenu labels |
+| `2c227fb` | fix(dashboard): mood tile mobile shows number once + label |
+| `bb4dc12` | fix(dashboard): no onboarding flicker on load; collapsed by default |
+| `bffdccb` | feat(dashboard): medication compliance graph wired to layout toggle |
+| `47ac14b` | feat(insights): mood chart auto-aggregates to weekly/monthly |
+| `4e2386e` | feat(dashboard): 7-day-average → 7-day-trend with delta indicator per metric |
+| `8ccdfac` | feat(dashboard): top tiles selectable in layout settings |
+| `316c3b0` | fix(charts): chart wrappers allow vertical scroll passthrough on mobile |
+| `41945b2` | fix(admin): /admin/users mobile layout — card-list at < md |
+| `8370b2d` | fix(mobile): chart controls + medication buttons + mood list icons to 44px |
+| `00f8cd5` | fix(settings): passkey list responsive — card view at < md |
+| `c0b14f4` | fix(auth): bump login buttons to 44px tap-target on mobile |
+
+### Features (Phase B1–B6)
+
+| SHA | Summary |
+| --------- | ---------------------------------------------------------------------------------- |
+| `fe85c2c` | feat(admin): restore from backup with full data replacement + triple-confirm |
+| `d8c549e` | feat(admin): backup download as JSON |
+| `30a74ed` | feat(admin): backup upload |
+| `0805452` | fix(admin): backup audit log entries |
+| `7c32d63` | feat(admin): link from backups view to docs.healthlog.dev/admin/backups |
+| `4db72a8` | feat(integrations): connection-state + sync-error UI in Settings → Integrations |
+| `b290a77` | fix(integrations): refresh-token failure marks integration as needing re-auth |
+| `604dff0` | feat(integrations): admin Telegram alert on persistent sync failure (≥3) |
+| `2fbf56d` | feat(audit): sync failures logged with structured meta |
+| `87a40fd` | fix(notifications): auto-disable channels on persistent hard rejects (410, etc.) |
+| `a3c0130` | feat(settings): notification channel status UI with re-enable + test |
+| `34c967c` | feat(achievements): dedicated /achievements page with locked/unlocked list |
+| `a242047` | feat(dashboard): recent achievements card with toggle in layout settings |
+| `81f5019` | feat(dashboard): RecentAchievementsCard component + tests |
+| `db5a49d` | feat(db): User.onboardingTourCompleted flag |
+| `e57fc0a` | feat(onboarding): tour component with spotlight + keyboard navigation |
+| `8215e25` | feat(onboarding): auto-launch tour for new users on first dashboard load |
+| `fa1c6a6` | feat(settings): allow user to replay the onboarding tour |
+| `d692119` | feat(doctor-report): configurable date range with default last-90-days |
+| `28467b2` | feat(doctor-report): practice name on cover page (persisted as user preference) |
+
+### Hardening (Phase C1–C5)
+
+| SHA | Summary |
+| --------- | ---------------------------------------------------------------------------------- |
+| `27310e4` | refactor(ai): consolidate providers behind AIProvider interface |
+| `d657f79` | feat(ai): enforce citation-from-data on every recommendation |
+| `4e85c38` | feat(ai): scope-hardened system prompt with refusal pattern |
+| `4bba951` | feat(ai): fallback-chain slug discovery with 1h positive cache |
+| `fa11f10` | docs(audit): v1.4.16 AI hardening roadmap |
+| `ad350fe` | feat(deploy): admin notification + audit log on deploy success/failure |
+| `41945b2` | fix(test): de-flake e2e a11y suite by forcing dark colorScheme |
+| `249c42b` | fix(ci): docker-publish reliability — separate cache scope per ref + 30min timeout |
+| `ffa4aac` | feat(ci): post-publish verify workflow |
+| `4a5be22` | docs(audit): v1.4.15 CI/e2e reliability report |
+| `01a10de` | test(i18n): non-empty + non-placeholder parity assertion |
+| `5510ed5` | docs(audit): v1.4.15 empty-states audit + i18n keys |
+| `0c20119` | feat(admin): empty states for users, backups, login-overview, api-tokens, feedback |
+| `9a74f8e` | feat(lists): empty states for measurements, mood, medications, achievements |
+| `1d65f3b` | feat(lists): empty states for measurements, mood, medications, achievements (impl) |
+| `65faf1d` | feat(insights,dashboard): empty states for first-run views |
+
+### QA + Reconcile (Phase D)
+
+| SHA | Summary |
+| --------- | ------------------------------------------------------------------------ |
+| `cd3b890` | refactor(v1.4.15): apply simplify-review safe suggestions |
+| `6465412` | fix(a11y): trap focus + restore + ring on onboarding tour |
+| `66d2e07` | fix(a11y): break long Withings error strings inside status banner |
+| `79bb167` | fix(ai): MockAIProvider DEFAULT_RESPONSE conforms to v1.4.15 strict schema |
+| `d947563` | style(v1.4.15): prettier sweep on phase-D reconcile touched files |
+
+### Release (Phase E1–E3)
+
+| SHA | Summary |
+| --------- | ---------------------------------------- |
+| `4dcaa08` | chore(release): v1.4.15 |
+
+---
+
+## Was deferred wurde + Warum
+
+Volle Liste: `.planning/v1416-backlog.md`. Highlights:
+
+### 8 HIGH findings → v1.4.16
+
+- **code-review H1** — `restore/route.ts:253-377` rohe Prisma-Fehler im
+ Catch-Block scrubben (Admin-only Leak, low blast).
+- **code-review H2** — `moodEntrySchema.tags` enger schließen oder
+ JSON-Parse in Pre-Tx-Loop validieren.
+- **code-review H3** — `mood-chart.tsx` exportiertes
+ `aggregateMoodEntries` und Inline-`chartData`-Aggregation
+ divergieren; Function-Extract-only (Charts visuell eingefroren).
+- **code-review H4** — `tour-launcher.tsx` sessionStorage-Keys auf
+ User-ID skopieren oder beim Logout löschen.
+- **design H4** — Cross-cutting `button.tsx` `h-9 → h-11` Sweep für
+ B1 / B3 / B5 Surfaces.
+- **senior-dev H1** — `src/app/page.tsx` (1031 LOC) splitten
+ (`` + `` + ``).
+- **senior-dev H2** — `integrations-section.tsx` (883 LOC) splitten
+ (per-provider Cards + composing index, Mirror admin-Pattern).
+- **senior-dev H3** — Process: pro Parallel-Agent ein Worktree, weil
+ acht v1.4.15-Commits Diff-Drift gegen ihre Subjects zeigten.
+
+### 5 MEDIUM mobile-items aus A5
+
+- `/insights` + `/admin` Tab-Strip-Overflow (cross-cutting `tabs.tsx`).
+- `/measurements` BP Sys/Dia-Row-Gruppierung.
+- Bottom-Nav 5+More IA-Entscheidung.
+- B1/B3/B5 Surfaces 44 px Sweep (siehe design H4).
+- Verbleibende A5-Findings (12 MED + 4 LOW dokumentiert in
+ `.planning/phase-A5-mobile-findings.md`).
+
+### KI-Roadmap → v1.4.16+
+
+(`docs/audit/v1416-ai-roadmap.md`)
+
+- **Medical-Reference-Grounding** — kuratiertes Bundle von ~40
+ Excerpts (ESH/ESC 2024, AHA/ACC 2017, WHO, AASM, Saint-Maurice 2020,
+ DGE/DEGAM); Pre-Flight-Relevanzauswahl; Schema bekommt `referenceId`.
+- **Multi-Provider-Redundanz** — `MultiProviderCascade` um
+ `AIProvider`; Admin-Tier-Ordering; per-Request 60s Budget.
+- **Per-Recommendation Explainability** — `rationale.{dataWindow,
+comparedTo, deviation}` + UI „Warum?"-Tooltip.
+- **Confidence-Score** — kalibriert pro Recommendation (v1.4.17).
+- **User-Feedback-Loop** — `InsightFeedback`-Tabelle + Admin
+ `/admin/ai-quality` Dashboard (v1.4.17).
+- **Deep-Mode** — optionale Codex-Reasoning-Summaries als separates
+ Schema-Feld (v1.5).
+
+### Auto-Deploy Image-Digest-Trigger → v1.4.16
+
+Coolify deployt aktuell auf jeden Git-Push (Marc ließ stehen für jetzt);
+v1.4.16 soll auf neuen Image-Digest umstellen, damit Coolify nicht für
+docs / planning / changelog-only commits einen Container-Recreate
+fährt.
+
+### Sonstige Process-Items
+
+- Strict-Schema-Migration für AI-Insights-Route + UI (M6 senior);
+ `.passthrough()` retiren.
+- `dashboard-layout.test.ts` Typecheck-Regression aufräumen (in E1
+ bereits gefixt — bleibt aber als „pre-existing" in mehreren STATE-
+ Phasen vermerkt; Reklassifizierung).
+- Worktree-Adoption für den v1.4.16-Marathon.
+
+### Simplify-no (4)
+
+`F5` defensive `notFound()`, `F9` `` switch, `F10`
+duplizierter `requireAdmin`-Branch, `F12` historische Anker-Kommentare
+— alle judgement-call, in `.planning/v1416-backlog.md` festgehalten.
+
+---
+
+## CI / Test status
+
+- `pnpm typecheck` — clean (drei pre-existing
+ `dashboard-layout.test.ts`-Errors in E1 mitgefixt: Test-Fixtures als
+ `DashboardLayout` getypt, damit der `DashboardWidgetId`-Enum nicht
+ mehr meckert).
+- `pnpm lint` — 0 errors / 11 pre-existing warnings (B-Phase warnings
+ count ging von 12 auf 11, weil ein Sibling-Agent eine unrelated
+ unused-var entfernt hat).
+- `pnpm format:check` — clean nach `d947563` + dem prettier-Sweep im
+ Release-Commit (41-File-Drift aus Phase D adressiert).
+- `pnpm test` — **~1048 unit tests** green (von 754 zu Beginn der
+ v1.4.15-Marathon).
+- `pnpm test:integration` — **31 / 31** green (waren 19 vor B1).
+- `pnpm build` — fails lokal auf Node 25 (`Reflect.get` private-member
+ Bug, gleicher Issue wie v1.4.14); CI Docker (Node 22) ist canonical
+ und grün.
+- `pnpm e2e` — Phase C3 hat das Dark-Mode-axe-Blocking gefixt
+ (`colorScheme: "dark"` in `playwright.config.ts`); e2e-Pass-Rate ging
+ von 0 % auf erwartete ≥ 90 %.
+
+---
+
+## Production state
+
+- **URL**: `https://healthlog.bombeck.io`
+- **`/api/version`**: `1.4.15` ✓
+- **Image-Digest**: `sha256:ace7d441f47bd8c69fd0c5e2417b7f6c53bc387aa10c9aa541ad5e6321e9581d`
+ (vorher v1.4.14: `sha256:0ced46004a544a311627b7036f2f2aed75861b0c62576214a1303a17d20c3d22`)
+- **GHCR-Pull-Digest**: `sha256:ba77448606b4a97bd39b84e163212559b2bb2da5ec7c9ff1026e80b5cac1031a`
+- **Smoke** (admin Session-Cookie): `/`, `/auth/login`,
+ `/settings/integrations`, `/settings/notifications`, `/admin`,
+ `/admin/users`, `/admin/backups`, `/achievements` — alle 200.
+ `/dashboard` 404 (erwartet — kein `src/app/dashboard`-Route, das
+ Dashboard lebt unter `/`; Runbook hatte einen veralteten Pfad).
+- **Deploy-Methode**: GHCR-Tag-Build `:1.4.15` erfolgreich; Main-Branch-
+ Run hing wieder (gleicher Bug wie v1.4.14, von C3 nicht vollständig
+ adressiert), retag-on-host als Workaround. v1.4.16-Backlog-Eintrag.
+- **Coolify Auto-Deploy**: feuert weiterhin auf jeden Git-Push (Marc
+ ließ stehen für jetzt); v1.4.16-Image-Digest-Trigger geplant, damit
+ docs / planning / changelog-only commits keinen Container-Recreate
+ auslösen.
+- **GitHub-Release**: https://github.com/MBombeck/HealthLog/releases/tag/v1.4.15
+- **Tag-Naming** (unverändert seit v1.4.14): GHCR-OCI-Tag ist
+ `:1.4.15` (kein `v`-Prefix); git-Tag ist `v1.4.15`.
+
+---
+
+## Docs / Landing
+
+- **healthlog-docs** (Starlight) — Phase E3 hat den vollen Sync
+ ausgerollt (`6b938df` + `db66da0`). Neue Seiten:
+ - `/admin/backups` — Backup-Struktur (Snapshot-Schema,
+ `BACKUP_SCHEMA_VERSION = "1"`, encrypted-at-rest, Restore-Gates).
+ - `/account/data-deletion` — User-Deletion-Lifecycle
+ (Welcher Scope verschwindet wann, was bleibt, GDPR-Art-17).
+- **healthlog-landing** (Next.js) — `softwareVersion 1.4.14 → 1.4.15`
+ in JSON-LD (`b6f83be`).
+
+---
+
+## Empfohlener v1.4.16 Backlog (Top 5)
+
+Aus `.planning/v1416-backlog.md`. Severity-geordnet, Datei:Zeile:
+
+1. **senior-dev H1** — `src/app/page.tsx` (1031 LOC) splitten
+ (`` + `` +
+ `` + ``); Visibility-
+ Resolver in `src/lib/dashboard-visibility.ts`. Mechanisch.
+2. **senior-dev H2** — `src/components/settings/integrations-section.tsx`
+ (883 LOC) splitten in
+ `src/components/settings/integrations/{integration-status-banner,
+withings-card, moodlog-card}.tsx` + composing index. Spiegelt das
+ admin per-section Pattern.
+3. **AI Strict-Schema Route+UI Migration** — `aiInsightResponseSchema`
+ in `/api/insights/generate` + Dashboard-UI verdrahten;
+ `.passthrough()` löschen; Legacy-Shape (`{summary, classification,
+findings, correlations, dataQuality, …}`) retiren. Wird zusammen
+ mit der AI Medical-Reference-Grounding-Welle gefahren.
+4. **M4 dispatcher legacy Telegram migration** — die Migration in
+ `src/lib/notifications/dispatcher.ts:75-97` upserted `enabled: true`
+ auf jeden Send und unwindet damit B3's Hard-Reject-Auto-Disable.
+ Guard auf „nur wenn keine Row existiert" oder `enabled` nicht mehr
+ anfassen.
+5. **Worktree-Adoption** — `superpowers:using-git-worktrees` pro
+ parallelen Agent; acht v1.4.15-Commits hatten Diff-Drift gegen
+ ihre Commit-Subjects (A2, A4, B1, B-mobile, B2, B3, B4, C1, C5).
+ Process-Win, kein Code-Change.
+
+---
+
+## Hard-Reload-Reminder
+
+`Cmd+Shift+R` (Mac) / `Ctrl+Shift+R` (Linux/Win) — der neue
+Service-Worker holt sonst noch v1.4.14-Chunks aus dem Cache. Einmalig
+ausreichend.