From f1e6630958bbd697f2eae2016b597e1d3e7d50ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Mon, 11 May 2026 08:27:51 +0200 Subject: [PATCH] chore(format): prettier sweep across develop Mostly table column normalisation under docs/audit/ + planning, object- literal expansion in src/lib/ai/coach/snapshot.ts after the W4 F6 Apple Health metric block landed, and small wrap/unwrap line adjustments in the device + APNs routes / tests touched across W3/W4/W5 sessions. No behavioural change. Co-Authored-By: Claude Opus 4.7 (1M context) --- .planning/ROADMAP.md | 93 ++++++++++--------- .planning/phase-A3-report.md | 32 +++---- .planning/phase-A5-report.md | 10 +- .planning/phase-A6-report.md | 10 +- .planning/phase-A7-report.md | 5 + .planning/phase-B-quality-report.md | 70 +++++++------- .planning/phase-B1-v1420-report.md | 37 ++++---- .planning/phase-B2a-report.md | 26 +++--- .planning/phase-B2b-report.md | 24 ++--- .planning/phase-B3-report.md | 4 +- .planning/phase-B5-report.md | 8 +- .planning/phase-D-code-review-findings.md | 7 +- .planning/phase-D-design-findings.md | 19 ++-- .planning/phase-D-reconcile-report.md | 24 ++--- .planning/phase-D-security-findings.md | 26 ++++-- .planning/phase-D-senior-dev-findings.md | 46 ++++----- .planning/phase-D-simplify-findings.md | 11 ++- .../phase-D-v1419-product-lead-review.md | 20 ++-- .planning/phase-D-v1420-code-review.md | 25 ++++- .planning/phase-D-v1420-design-review.md | 23 ++++- .../phase-D-v1420-product-lead-review.md | 73 ++++++++------- .planning/phase-D-v1420-reconcile-report.md | 55 +++++------ .planning/phase-D-v1420-security-review.md | 36 ++++--- .planning/phase-D-v1420-simplify-review.md | 79 ++++++++++++---- .planning/phase-E1-report.md | 16 ++-- .planning/phase-E2-report.md | 6 +- .planning/phase-F2-report.md | 14 +-- .planning/phase-F5-report.md | 28 +++--- .planning/phase-F6-report.md | 12 +-- .planning/phase-FX-report.md | 10 +- .planning/phase-W1a-report.md | 46 +++++---- .planning/phase-W2-report.md | 8 +- .planning/phase-W2-v1423-report.md | 40 ++++---- .planning/phase-W3-report.md | 4 +- .planning/phase-W3-v1423-report.md | 36 +++---- .planning/phase-W4-report.md | 16 ++-- .planning/phase-W4-v1423-report.md | 29 +++--- .planning/phase-W5-v1422-reconcile-report.md | 27 +++--- .planning/phase-W5-v1423-report.md | 14 +-- .planning/v1420-backlog.md | 15 +-- .planning/v1420-marathon-handoff.md | 9 +- .planning/v1421-backlog.md | 13 ++- .planning/v1422-backlog.md | 2 +- .planning/v15-backlog.md | 27 +++--- CHANGELOG.md | 18 ++-- CODE_OF_CONDUCT.md | 22 ++--- docs/api/openapi.yaml | 30 ++++-- docs/audit/v1420-summary.md | 54 +++++------ docs/audit/v1421-summary.md | 16 ++-- .../me/devices/[id]/__tests__/route.test.ts | 35 +++++-- src/app/api/auth/me/devices/[id]/route.ts | 6 +- .../api/devices/[id]/__tests__/route.test.ts | 20 +++- src/app/api/devices/[id]/route.ts | 6 +- src/app/api/devices/route.ts | 5 +- src/app/api/measurements/batch/route.ts | 15 +-- .../admin/__tests__/admin-shell.test.tsx | 9 +- .../insights/coach-panel/coach-drawer.tsx | 4 +- .../coach-panel/coach-settings-sheet.tsx | 16 +--- .../insights/coach-panel/message-thread.tsx | 5 +- ...asurement-list-apple-health-badge.test.tsx | 4 +- .../ai/__tests__/coach-prompt-v423.test.ts | 8 +- src/lib/ai/coach/snapshot.ts | 63 +++++++++++-- src/lib/devices/__tests__/revoke.test.ts | 6 +- .../__tests__/apple-health-mapping.test.ts | 3 +- src/lib/measurements/apple-health-mapping.ts | 5 +- .../senders/__tests__/apns.test.ts | 22 +++-- src/lib/notifications/senders/apns.ts | 4 +- src/lib/openapi/routes.ts | 17 ++-- tests/integration/apns-dispatch.test.ts | 15 ++- tests/integration/device-register.test.ts | 16 +++- 70 files changed, 899 insertions(+), 660 deletions(-) diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 39dbb8154..d746d64e4 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -44,14 +44,14 @@ Reserved next strategic milestones: ## Previous milestone — v1.4.22 (completed 2026-05-10T22:43:50+02:00) -| 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 | +| 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 | +| 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 | Milestone completed 2026-05-10T22:43:50+02:00 — v1.4.22 LIVE in prod. Release brief: `docs/audit/v1422-summary.md`. @@ -64,8 +64,8 @@ Backlog seeded to `.planning/v1422-backlog.md`. v1.5 strategic plan at ## Previous patch — v1.4.21 (completed 2026-05-10T17:46+00:00) -| Phase | Goal | State | -| ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | ----- | +| 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 | @@ -78,21 +78,21 @@ Image digest: ## 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 | +| 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 | +| 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 @@ -103,20 +103,20 @@ Release brief: `docs/audit/v1420-summary.md`. Backlog seeded to ## 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 | +| 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 @@ -127,20 +127,21 @@ Release brief: `docs/audit/v1419-summary.md`. Backlog seeded to ## 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 | +| 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 | +| 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). + +- `.planning/phase-D-v1418-product-lead-review.md` (strategic). --- diff --git a/.planning/phase-A3-report.md b/.planning/phase-A3-report.md index 6120bfce4..9b5aec3bb 100644 --- a/.planning/phase-A3-report.md +++ b/.planning/phase-A3-report.md @@ -13,15 +13,15 @@ Status: complete · 2026-05-09T13:18+02:00 ## Commits on origin/main -| SHA | Message | Concern | -| -------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | -| b5e9a95 | (A4 sweep) — `` removal in `src/app/page.tsx` was swept into A4's AI-prompt commit when our edits raced. Effectively covered. | 1 | -| 60a91af | feat(insights): comparison toggle on-surface in hero meta band — adds `metaSlot` prop to ``, mounts toggle inline. | 5 | -| 98a3d10 | refactor(insights): single page-level refresh and drop orphan subtitle — drops `onRegenerate` from the page's `` mount + the `aiOverviewTitle` placeholder. | 2 + 3 | -| 335f288 | refactor(insights): drop duplicate metric tile strip — removes 5-tile grid + dead helpers + `fmt`/`bf` locals. Net `-157` / `+20` lines. | 4 | -| fa91a73 | fix(insights): strip lowercase chart tokens from AI prose — splits `STRIP_TOKEN_REGEX` (`[A-Za-z0-9_]+`) from `PARSE_TOKEN_REGEX` (`[A-Z_]+`). | 6 | -| 5360d3c | test(insights): coverage for v1.4.19 polish changes — commit message landed but the test file was missing because a parallel agent's index race captured only the planning files. | -| f2b21a4 | test(insights): add insights-polish.test.ts (followup to 5360d3c) — actual test file (9 tests), pinning all of the above. | 7 | +| SHA | Message | Concern | +| ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | +| b5e9a95 | (A4 sweep) — `` removal in `src/app/page.tsx` was swept into A4's AI-prompt commit when our edits raced. Effectively covered. | 1 | +| 60a91af | feat(insights): comparison toggle on-surface in hero meta band — adds `metaSlot` prop to ``, mounts toggle inline. | 5 | +| 98a3d10 | refactor(insights): single page-level refresh and drop orphan subtitle — drops `onRegenerate` from the page's `` mount + the `aiOverviewTitle` placeholder. | 2 + 3 | +| 335f288 | refactor(insights): drop duplicate metric tile strip — removes 5-tile grid + dead helpers + `fmt`/`bf` locals. Net `-157` / `+20` lines. | 4 | +| fa91a73 | fix(insights): strip lowercase chart tokens from AI prose — splits `STRIP_TOKEN_REGEX` (`[A-Za-z0-9_]+`) from `PARSE_TOKEN_REGEX` (`[A-Z_]+`). | 6 | +| 5360d3c | test(insights): coverage for v1.4.19 polish changes — commit message landed but the test file was missing because a parallel agent's index race captured only the planning files. | +| f2b21a4 | test(insights): add insights-polish.test.ts (followup to 5360d3c) — actual test file (9 tests), pinning all of the above. | 7 | ## Verification @@ -40,13 +40,13 @@ Status: complete · 2026-05-09T13:18+02:00 ## File deltas -| File | Lines added | Lines removed | -| ----------------------------------------------------- | ----------- | ------------- | -| `src/app/insights/page.tsx` | +43 | -181 | -| `src/components/insights/insights-page-hero.tsx` | +22 | 0 | -| `src/components/insights/insight-advisor-card.tsx` | +12 | -5 | -| `src/lib/insights/chart-tokens.ts` | +16 | -7 | -| `src/app/__tests__/insights-polish.test.ts` | +140 | 0 | +| File | Lines added | Lines removed | +| -------------------------------------------------- | ----------- | ------------- | +| `src/app/insights/page.tsx` | +43 | -181 | +| `src/components/insights/insights-page-hero.tsx` | +22 | 0 | +| `src/components/insights/insight-advisor-card.tsx` | +12 | -5 | +| `src/lib/insights/chart-tokens.ts` | +16 | -7 | +| `src/app/__tests__/insights-polish.test.ts` | +140 | 0 | Net `-200` lines on the page itself, `+140` lines of guards; `/insights` is significantly leaner without losing any value. diff --git a/.planning/phase-A5-report.md b/.planning/phase-A5-report.md index 4457357ff..d96bf39bf 100644 --- a/.planning/phase-A5-report.md +++ b/.planning/phase-A5-report.md @@ -3,11 +3,11 @@ Completed 2026-05-10 ~13:05 CEST. Three atomic TDD-first commits on `origin/main`: -| # | SHA | What it ships | -| --- | --------- | ------------------------------------------------------------------------------ | -| 1 | `ba0d6b8` | `feat(integrations): IntegrationStatusPill component (single tag, mobile-safe)`| -| 2 | `0dcc91a` | `refactor(integrations): single status pill, drop redundant containers` | -| 3 | `47a8fc7` | `test(integrations): Pixel-5 e2e for consolidated status pill` | +| # | SHA | What it ships | +| --- | --------- | ------------------------------------------------------------------------------- | +| 1 | `ba0d6b8` | `feat(integrations): IntegrationStatusPill component (single tag, mobile-safe)` | +| 2 | `0dcc91a` | `refactor(integrations): single status pill, drop redundant containers` | +| 3 | `47a8fc7` | `test(integrations): Pixel-5 e2e for consolidated status pill` | Commit #2 absorbed Marc's planned commits #2 (Withings) and #3 (Mood Log) — the refactor was inherently atomic because both cards diff --git a/.planning/phase-A6-report.md b/.planning/phase-A6-report.md index ad9170f2f..a56bc57e5 100644 --- a/.planning/phase-A6-report.md +++ b/.planning/phase-A6-report.md @@ -36,11 +36,11 @@ human eye missed. ## What was fixed (5 commits) 1. `957f8e9` — `fix(settings): equalize input heights across all - settings sections`. AI active-provider select `h-10` → `h-9`, AI +settings sections`. AI active-provider select `h-10` → `h-9`, AI add-provider select `h-8` → `h-9`, Dashboard "Compare to" trigger loses `min-h-11` so the default `h-9` applies. 2. `9fda634` — `fix(settings): action-button placement consistent - across sections (right-side desktop, stacked mobile)`. Account → +across sections (right-side desktop, stacked mobile)`. Account → Password, Account → Restart onboarding tour and Dashboard → Reset to defaults all use `flex-col` on `=sm`, so the button stacks below the title on mobile (full-width) and @@ -48,21 +48,21 @@ human eye missed. pulled into the title cluster on the two account cards so each row is a clean `` flex pair. 3. `1075784` — `fix(settings): Sprache select position + width - consistent`. Language lifted out of the dob/language pair into +consistent`. Language lifted out of the dob/language pair into its own row at the bottom of the Profile card. `max-w-xs` on `>=sm` so it doesn't render heavier than other half-width fields. Drive-by: pulled the duplicated native-select class string into a single `NATIVE_SELECT_CLASS` constant so gender + language render identically. 4. `737b533` — `style(settings): uniform vertical spacing across all - sections`. Dashboard layout card `space-y-5` → `space-y-4`. AI +sections`. Dashboard layout card `space-y-5` → `space-y-4`. AI provider config forms `space-y-3` → `space-y-4`. Section roots keep `space-y-6` so distinct cards still read as distinct surfaces. Note: `.planning/STATE.md` got bundled into this commit accidentally via index race with A5; STATE content is correct, no semantic harm. 5. `78f1f3f` — `test(settings): mobile e2e snapshot verifies - consistency`. Pixel-5 Playwright spec +consistency`. Pixel-5 Playwright spec (`e2e/settings-mobile-consistency.spec.ts`) locks in five invariants: every form input on /settings/account is 36 px, neither password nor tour buttons overflow the card right edge, diff --git a/.planning/phase-A7-report.md b/.planning/phase-A7-report.md index cde2aedac..a1bedca64 100644 --- a/.planning/phase-A7-report.md +++ b/.planning/phase-A7-report.md @@ -16,6 +16,7 @@ Commits on `origin/main`: ## What landed ### 1. Feedback tab strip mini-scrollbar — fixed + Marc's "mini Scroll-Button rechts" on the admin feedback inbox tabs came from a CSS overflow-axis coupling: `tabsListVariants` set `overflow-x: auto` without `overflow-y`, so the browser silently @@ -27,6 +28,7 @@ short strips. Added `overflow-y-hidden` (with the matching component test that locks both axes in. ### 2. /admin/api-tokens 4th-attempt scrollbar — fixed + Three previous fixes (column-hide v1.4.15, mobile card-list v1.4.16, admin-shell mobile-strip `no-scrollbar` v1.4.18) cleared the obvious culprits but Marc still saw a residual painted bar. @@ -49,6 +51,7 @@ Added an e2e regression that walks every element inside the mobile card-list and asserts `scrollWidth <= clientWidth + 1` for each. ### 3. /admin/api-tokens "Einklappen" button — removed + Inherited from the v1.4 shared-admin page where 13 sections lived together. On the v1.5 dedicated `/admin/api-tokens` route the toggle hides the only card on the page. Marc called it "sinnlos". @@ -57,10 +60,12 @@ Dropped the `expanded` state + button. The shared `settings.collapse` `` still uses them. ### 4. Zielwerte page whitespace — tightened + Outer wrapper changed from `space-y-8` (32 px) to `space-y-6` (24 px), matching the admin / settings rhythm. ### 5. Zielwerte status labels translated + Added two new i18n key blocks under `targets.*`: - `targets.label.` (11 entries, EN + DE) — used by diff --git a/.planning/phase-B-quality-report.md b/.planning/phase-B-quality-report.md index 17857f2fa..803918f1e 100644 --- a/.planning/phase-B-quality-report.md +++ b/.planning/phase-B-quality-report.md @@ -6,44 +6,44 @@ defer the rest to v1.4.20. ## CRITICAL — 6 / 6 fixed -| Finding | Status | Commit | Notes | -| ------- | ------ | ------ | ----- | -| F-01 `formatTimeWindowRange` mixed-language `bis ... Uhr` | fixed | `180f46c` | Locale param threaded through medication card + form. TDD: 6 cases. | -| F-02 `/admin/login-overview` shows insights events | fixed | `dc75fe8` | Section now sets `filter=auth`; action dropdown filtered to `auth.*`. TDD: URL assertion. | -| F-03 Achievements `Idiot` / `Lazy Boy` titles | fixed | `7a6bc81` | Renamed in EN + DE; banned-word regression suite. | -| F-04 Date inputs render mm/dd/yyyy on DE | fixed | `ff6e184` | `lang={locale}` on every native `` in the app. | -| F-05 Admin "Pick a section from the sidebar" wrong on mobile | fixed | `4feacad` | Dropped sidebar reference in EN + DE welcome subtitle. | -| F-06 Insights legacy CTA verb mismatch | fixed | `d263125` | Legacy-payload button now says "Regenerate" in EN/DE; empty-state "Start analysis" untouched. | +| Finding | Status | Commit | Notes | +| ------------------------------------------------------------ | ------ | --------- | --------------------------------------------------------------------------------------------- | ----------------------------- | +| F-01 `formatTimeWindowRange` mixed-language `bis ... Uhr` | fixed | `180f46c` | Locale param threaded through medication card + form. TDD: 6 cases. | +| F-02 `/admin/login-overview` shows insights events | fixed | `dc75fe8` | Section now sets `filter=auth`; action dropdown filtered to `auth.*`. TDD: URL assertion. | +| F-03 Achievements `Idiot` / `Lazy Boy` titles | fixed | `7a6bc81` | Renamed in EN + DE; banned-word regression suite. | +| F-04 Date inputs render mm/dd/yyyy on DE | fixed | `ff6e184` | `lang={locale}` on every native `` in the app. | +| F-05 Admin "Pick a section from the sidebar" wrong on mobile | fixed | `4feacad` | Dropped sidebar reference in EN + DE welcome subtitle. | +| F-06 Insights legacy CTA verb mismatch | fixed | `d263125` | Legacy-payload button now says "Regenerate" in EN/DE; empty-state "Start analysis" untouched. | ## HIGH — 21 fixed / 4 deferred (target: 15) -| Finding | Status | Commit / reason | -| ------- | ------ | --------------- | -| F-07 thresholds three names | fixed | `1f4d6a2` | -| F-08 page+card title duplicate | fixed (partial) | `70ebe32` (danger-zone, feedback). Other affected pages deferred. | -| F-09 backup type raw enum | fixed | `1ae9b9d` | -| F-10 `WITHINGS` rendered ALL CAPS | fixed | `1ae9b9d` | -| F-11 `→ User` / `→ Admin` no label | fixed | `42b0f11` | -| F-12 mobile user cards no aria-labels | deferred | spot-check showed every icon button already has `aria-label` + `title`. *not-an-issue*; see backlog. | -| F-13 mobile sys/dia same heart icon | fixed | `876e074` | -| F-14 settings/integrations status duplicated | deferred | already shipped in v1.4.19 A5. | -| F-15 ntfy in subtitle, missing on board | fixed | `3f6e670` | -| F-16 "Configured" + "Enabled" double badge | fixed | `876e074` | -| F-17 raw `auth.token.autoissue.native` event-key | fixed | `bc81fd7` | -| F-18 ISO timestamp in token name | fixed | `713b494` | -| F-19 raw `*` permission badge | fixed | `3f6e670` | -| F-20 admin/feedback dupe subtitle | fixed | `3f6e670` | -| F-21 "system-wide" suffix repeated 4× | fixed | `3f6e670` | -| F-22 services subtitle misses API toggle | fixed | `3f6e670` | -| F-23 mood/achievements DE strings | deferred | spot-check showed every label already translated. *not-an-issue*; see backlog. | -| F-24 admin/integrations duplicate toggle label | fixed | `98cd13c` | -| F-25 `Glitchtip` casing | fixed | `3f6e670` | -| F-26 insights regenerate banner+button conflict | deferred | partial overlap with A3 + F-06; per-tile spinner removal owns by v1.4.20 Insights redesign. | -| F-27 awkward achievements subtitle | fixed | `3f6e670` | -| F-28 plural bug "for 1 consecutive days" | fixed | `98cd13c` | -| F-29 jargon "(severity x provider)" | fixed | `3f6e670` | -| F-30 "Inbox zero" empty-state idiom | fixed | `3f6e670` | -| F-31 audit-preview row no link | fixed | `bc81fd7` | +| Finding | Status | Commit / reason | +| ------------------------------------------------ | --------------- | ---------------------------------------------------------------------------------------------------- | +| F-07 thresholds three names | fixed | `1f4d6a2` | +| F-08 page+card title duplicate | fixed (partial) | `70ebe32` (danger-zone, feedback). Other affected pages deferred. | +| F-09 backup type raw enum | fixed | `1ae9b9d` | +| F-10 `WITHINGS` rendered ALL CAPS | fixed | `1ae9b9d` | +| F-11 `→ User` / `→ Admin` no label | fixed | `42b0f11` | +| F-12 mobile user cards no aria-labels | deferred | spot-check showed every icon button already has `aria-label` + `title`. _not-an-issue_; see backlog. | +| F-13 mobile sys/dia same heart icon | fixed | `876e074` | +| F-14 settings/integrations status duplicated | deferred | already shipped in v1.4.19 A5. | +| F-15 ntfy in subtitle, missing on board | fixed | `3f6e670` | +| F-16 "Configured" + "Enabled" double badge | fixed | `876e074` | +| F-17 raw `auth.token.autoissue.native` event-key | fixed | `bc81fd7` | +| F-18 ISO timestamp in token name | fixed | `713b494` | +| F-19 raw `*` permission badge | fixed | `3f6e670` | +| F-20 admin/feedback dupe subtitle | fixed | `3f6e670` | +| F-21 "system-wide" suffix repeated 4× | fixed | `3f6e670` | +| F-22 services subtitle misses API toggle | fixed | `3f6e670` | +| F-23 mood/achievements DE strings | deferred | spot-check showed every label already translated. _not-an-issue_; see backlog. | +| F-24 admin/integrations duplicate toggle label | fixed | `98cd13c` | +| F-25 `Glitchtip` casing | fixed | `3f6e670` | +| F-26 insights regenerate banner+button conflict | deferred | partial overlap with A3 + F-06; per-tile spinner removal owns by v1.4.20 Insights redesign. | +| F-27 awkward achievements subtitle | fixed | `3f6e670` | +| F-28 plural bug "for 1 consecutive days" | fixed | `98cd13c` | +| F-29 jargon "(severity x provider)" | fixed | `3f6e670` | +| F-30 "Inbox zero" empty-state idiom | fixed | `3f6e670` | +| F-31 audit-preview row no link | fixed | `bc81fd7` | ## MED + LOW — 31 + 16 deferred to v1.4.20 diff --git a/.planning/phase-B1-v1420-report.md b/.planning/phase-B1-v1420-report.md index d94aa6e31..0346e0ffc 100644 --- a/.planning/phase-B1-v1420-report.md +++ b/.planning/phase-B1-v1420-report.md @@ -13,28 +13,29 @@ full-width Daily Briefing card, and extend the AI insight pipeline with a `dailyBriefing` payload block (paragraph + 0-5 keyFindings). The 5 prior commits land each sub-deliverable atomically; this report -+ STATE.md tick complete in commit 6. + +- STATE.md tick complete in commit 6. ## What shipped (5 commits, all on `origin/develop`) -| # | SHA | Sub-deliverable | -|---|-----|------| -| 1 | `9873363` | Schema + prompt — `dailyBriefingSchema` (`paragraph`, `keyFindings[0..5]`, tone enum, sourceWindow / sourceMetric enums); PROMPT_VERSION bump 4.19.0 → 4.20.0; GROUND RULE 8 added in EN + DE prompts; new `daily-briefing-schema.test.ts` (+31 specs). | -| 2 | `9713bf1` | `` chip-strip component — 5-chip default ("Try asking" row), lucide `Quote` icon, Dracula purple chip styling, mobile-wrap; EN + DE keys (`insights.suggestedPrompts.*`); +9 specs. | -| 3 | `92f332e` | `` card — narrative paragraph, 0-5 finding rows with tone-coloured left bar (green/orange/cyan), metric-icon prefix, optional delta badge, empty-state CTA, `animate-pulse` skeleton, optional metaSlot; EN + DE keys (`insights.dailyBriefing.*`); +18 specs. | -| 4 | `59e63a0` | `` — locale-aware time-of-day greeting (4 buckets), briefing-paragraph subtitle with fallback, 3-button action row (weekly-report + ask-coach disabled with `title="Coming soon"`, regenerate wired), suggested-prompt strip below; old `` JSDoc-deprecated; new `globals.css` utilities `.hero-gradient`, `.glow-purple`, `pulseDot` keyframes; +22 specs. | -| 5 | `7d29596` | `/insights` page wire-up — `` + `` mounted above the existing Status / Advisor / Recommendations blocks; `useInsightsAdvisorQuery` lifts `dailyBriefing` off the cached payload via `dailyBriefingSchema.safeParse`; CompareToggle migrated from hero meta band into briefing metaSlot; v1.4.19 A3 polish-test loosened from string-count to JSX-block check (load-bearing "advisor card carries no onRegenerate" stays). | +| # | SHA | Sub-deliverable | +| --- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 1 | `9873363` | Schema + prompt — `dailyBriefingSchema` (`paragraph`, `keyFindings[0..5]`, tone enum, sourceWindow / sourceMetric enums); PROMPT_VERSION bump 4.19.0 → 4.20.0; GROUND RULE 8 added in EN + DE prompts; new `daily-briefing-schema.test.ts` (+31 specs). | +| 2 | `9713bf1` | `` chip-strip component — 5-chip default ("Try asking" row), lucide `Quote` icon, Dracula purple chip styling, mobile-wrap; EN + DE keys (`insights.suggestedPrompts.*`); +9 specs. | +| 3 | `92f332e` | `` card — narrative paragraph, 0-5 finding rows with tone-coloured left bar (green/orange/cyan), metric-icon prefix, optional delta badge, empty-state CTA, `animate-pulse` skeleton, optional metaSlot; EN + DE keys (`insights.dailyBriefing.*`); +18 specs. | +| 4 | `59e63a0` | `` — locale-aware time-of-day greeting (4 buckets), briefing-paragraph subtitle with fallback, 3-button action row (weekly-report + ask-coach disabled with `title="Coming soon"`, regenerate wired), suggested-prompt strip below; old `` JSDoc-deprecated; new `globals.css` utilities `.hero-gradient`, `.glow-purple`, `pulseDot` keyframes; +22 specs. | +| 5 | `7d29596` | `/insights` page wire-up — `` + `` mounted above the existing Status / Advisor / Recommendations blocks; `useInsightsAdvisorQuery` lifts `dailyBriefing` off the cached payload via `dailyBriefingSchema.safeParse`; CompareToggle migrated from hero meta band into briefing metaSlot; v1.4.19 A3 polish-test loosened from string-count to JSX-block check (load-bearing "advisor card carries no onRegenerate" stays). | ## Test count -| Snapshot | Files | Tests | -|----|----|----| -| Baseline (start of B1) | 210 | 1672 | -| After commit 1 (schema) | 211 | 1703 (+31) | -| After commit 2 (suggested-prompts) | 212 | 1712 (+9) | -| After commit 3 (daily-briefing) | 213 | 1730 (+18) | -| After commit 4 (hero-strip) | 214 | 1752 (+22) | -| After commit 5 (page wire-up) | 214 | 1753 (+1 polish guard) | +| Snapshot | Files | Tests | +| ---------------------------------- | ----- | ---------------------- | +| Baseline (start of B1) | 210 | 1672 | +| After commit 1 (schema) | 211 | 1703 (+31) | +| After commit 2 (suggested-prompts) | 212 | 1712 (+9) | +| After commit 3 (daily-briefing) | 213 | 1730 (+18) | +| After commit 4 (hero-strip) | 214 | 1752 (+22) | +| After commit 5 (page wire-up) | 214 | 1753 (+1 polish guard) | Net delta: **+4 test files, +81 tests**, all green. `pnpm typecheck` clean across the chain. `pnpm lint` baseline preserved (12 pre- @@ -118,7 +119,7 @@ defer rather than a block — see above for the reasoning. 5. **5 default suggested prompts.** Pinned in i18n (`whyMonday / weightVsPulse / weekVsMonth / tellMyDoctor / - medicationWorking`). The list mirrors the artboard verbatim; if +medicationWorking`). The list mirrors the artboard verbatim; if "What should I tell my doctor?" reads too clinical, flipping the EN value is a one-line edit. @@ -134,6 +135,7 @@ i18n-locale-integrity ✓ EN + DE share the same key shape ## Files added / modified **Added:** + - `src/components/insights/hero-strip.tsx` - `src/components/insights/daily-briefing.tsx` - `src/components/insights/suggested-prompts.tsx` @@ -143,6 +145,7 @@ i18n-locale-integrity ✓ EN + DE share the same key shape - `src/lib/ai/__tests__/daily-briefing-schema.test.ts` **Modified:** + - `src/lib/ai/schema.ts` — `dailyBriefing` block added to response schema - `src/lib/ai/prompts/insight-generator.ts` — PROMPT_VERSION 4.20.0, GROUND RULE 8, JSON-shape examples in EN + DE - `src/components/insights/use-insights-advisor.ts` — `dailyBriefing` lifted off cached payload diff --git a/.planning/phase-B2a-report.md b/.planning/phase-B2a-report.md index aac58f0ce..bf0f5da37 100644 --- a/.planning/phase-B2a-report.md +++ b/.planning/phase-B2a-report.md @@ -11,13 +11,13 @@ endpoints. The drawer UI (B2b) dispatches separately. ## Commit timeline (five atomic commits on `develop`) -| SHA | Subject | -| --- | --- | +| SHA | Subject | +| --------- | --------------------------------------------------------------------- | | `5527001` | `feat(coach): add CoachConversation, CoachMessage, CoachUsage models` | -| `a68557d` | `feat(coach): types, persistence, budget, and refusal helpers` | -| `16f3ece` | `feat(coach): add POST /api/insights/chat SSE streaming endpoint` | -| `3168ba8` | `feat(coach): GET list, GET single, DELETE conversation endpoints` | -| _(this)_ | `docs(planning): tick B2a complete, record phase-B2a report` | +| `a68557d` | `feat(coach): types, persistence, budget, and refusal helpers` | +| `16f3ece` | `feat(coach): add POST /api/insights/chat SSE streaming endpoint` | +| `3168ba8` | `feat(coach): GET list, GET single, DELETE conversation endpoints` | +| _(this)_ | `docs(planning): tick B2a complete, record phase-B2a report` | ## Schema + migration @@ -49,9 +49,9 @@ every Coach row. read helpers, `summariseTitle()` for the rail, cursor-paginated `listConversations()`, `deleteConversation()` with ownership check. - `src/lib/ai/coach/budget.ts` — `MAX_TOKENS_PER_USER_PER_DAY = 25 - 000`. UTC `dateKey` so the meter aligns with the LLM provider's +000`. UTC `dateKey` so the meter aligns with the LLM provider's billing boundary. `enforceBudget()` throws `HttpError(429, - "coach.budget.exceeded")`. `recordSpend()` clamps non-finite token +"coach.budget.exceeded")`. `recordSpend()` clamps non-finite token figures to 0 so a misbehaving provider can't poison the ledger. - `src/lib/ai/coach/refusal.ts` — pattern-based detector for prompt injection (EN + DE wording, jailbreak variants, "reveal your @@ -87,10 +87,10 @@ every Coach row. ## Test coverage -| Suite | Before | After | Δ | -| --- | --- | --- | --- | -| Unit (vitest) | 1753 | 1781 | +28 | -| Integration | 67 | 78 | +11 | +| Suite | Before | After | Δ | +| ------------- | ------ | ----- | --- | +| Unit (vitest) | 1753 | 1781 | +28 | +| Integration | 67 | 78 | +11 | Unit tests cover refusal patterns (13 cases), title summarisation (6), and budget guard semantics (9). Integration tests pin five chat-route @@ -131,7 +131,7 @@ without the encryption key for future analytics. - The "summarise older half" pass is currently a placeholder (the history-window builder injects a synthetic `[summary placeholder - — N earlier turns elided]` line rather than calling a provider to +— N earlier turns elided]` line rather than calling a provider to produce a real summary). Cheap and deterministic; an opt-in real- summarisation pass can land alongside B2b once the drawer UI shows whether users actually push past 20 turns. diff --git a/.planning/phase-B2b-report.md b/.planning/phase-B2b-report.md index 479563073..0efe27f86 100644 --- a/.planning/phase-B2b-report.md +++ b/.planning/phase-B2b-report.md @@ -12,13 +12,13 @@ strip's "Ask the coach" button + suggested-prompt chips. ## Commit timeline (four atomic commits + this report on `develop`) -| SHA | Subject | -| --- | --- | -| `c42c0a5` | `feat(coach): TanStack Query hooks + SSE streaming client` | -| `195448a` | `feat(coach): drawer shell, message thread, source chips` | -| `8dac389` | `feat(coach): composer, history rail, sources rail` | +| SHA | Subject | +| --------- | ----------------------------------------------------------------- | +| `c42c0a5` | `feat(coach): TanStack Query hooks + SSE streaming client` | +| `195448a` | `feat(coach): drawer shell, message thread, source chips` | +| `8dac389` | `feat(coach): composer, history rail, sources rail` | | `e541799` | `feat(insights): wire Coach drawer into /insights via hero strip` | -| _(this)_ | `docs(planning): tick B2b complete, record phase-B2b report` | +| _(this)_ | `docs(planning): tick B2b complete, record phase-B2b report` | ## Streaming implementation @@ -88,10 +88,10 @@ the defaults so callers only need to pass `open` + `onOpenChange` + ## Test coverage -| Suite | Before | After | Δ | -| --- | --- | --- | --- | -| Unit (vitest) | 1781 | 1833 | +52 | -| Integration | 78 | 78 | 0 | +| Suite | Before | After | Δ | +| ------------- | ------ | ----- | --- | +| Unit (vitest) | 1781 | 1833 | +52 | +| Integration | 78 | 78 | 0 | Six new test files cover the streaming parser, every drawer column, the message thread state machine, locale-aware labels, and the @@ -110,8 +110,8 @@ New strings under `insights.coach.*`: - Sources rail: `sourcesTitle`, `sourcesFresh`, `sourcesStale`, `sourcesFooter` - Provenance chip namespaces: `metric.{bp,weight,pulse,mood, - compliance,general}` and `window.{last7days,last30days,last90days, - allTime}` +compliance,general}` and `window.{last7days,last30days,last90days, +allTime}` Both `messages/en.json` and `messages/de.json` updated; `i18n-locale-integrity.test.ts` keeps passing. diff --git a/.planning/phase-B3-report.md b/.planning/phase-B3-report.md index 5eaf38c1a..47a96a2c0 100644 --- a/.planning/phase-B3-report.md +++ b/.planning/phase-B3-report.md @@ -48,7 +48,7 @@ near-zero scatter that would imply a pattern that isn't there. `` wrapper), confidence chip, source-chip ("based on N paired readings · last 30 days"), interpretation prose, disabled "Try a 7-day experiment" CTA with `title="Coming - soon"`. Row mounts the three cards in 2-up grid on `>=md` and +soon"`. Row mounts the three cards in 2-up grid on `>=md` and single column on `` plus a native `title=` attribute. Neither surfaces @@ -117,6 +118,7 @@ Pages audited: truncated api-tokens cells works on touch (long-press on mobile, hover on desktop)". The hover path works; the touch path does not. + - **Recommendation:** On the mobile card-list (`md:hidden`, line 232), drop `truncate` and let long values wrap to two lines — vertical space is cheap on a card and reading is more important @@ -133,7 +135,7 @@ Pages audited: - **Issue:** When the comparison toggle (`metaSlot`) is mounted AND the regenerate button is wired (the live `/insights` config), the outer flex `flex-col gap-4 sm:flex-row sm:items-start - sm:justify-between` puts the regenerate button in a 2nd column on +sm:justify-between` puts the regenerate button in a 2nd column on desktop; on mobile (`` (3 buttons, each `min-h-11 px-3`). @@ -149,6 +151,7 @@ Pages audited: before any card body. Marc's A3 concern was "three stacked cards with separate controls" feel; folding the toggle into the hero removed the standalone band but made the hero itself heavy. + - **Recommendation:** On `>=sm`, inline the CompareToggle next to the Regenerate button (both in the right-side column) instead of inside the title block. On `API Tokens` (renderer line 184) AND `` body renders `
API Tokens
` (section @@ -190,7 +193,7 @@ Pages audited: is 1-column (correct), but on desktop the right cell renders empty without a placeholder — visually fine, semantically odd. - **Recommendation:** Replace the grid with a plain `
` so the DOB input still caps at half-card +class="sm:max-w-md">` so the DOB input still caps at half-card width on desktop. Drops one DOM node + one CSS class. - **Ship-blocker?** No. @@ -273,7 +276,7 @@ Pages audited: - **Severity:** LOW - **File:** `src/components/admin/api-token-overview-section.tsx:135-142, - 213-220` +213-220` - **Issue:** The colgroup widths sum to `18+28+24+10+12+8 = 100 %`. `lastUsedAt` cell is `whitespace-nowrap` rendering `formatDateTime(...)` (e.g. "10.05.2026, 13:18:42" — 19 chars + diff --git a/.planning/phase-D-reconcile-report.md b/.planning/phase-D-reconcile-report.md index 1ef4a344d..a410ffe8a 100644 --- a/.planning/phase-D-reconcile-report.md +++ b/.planning/phase-D-reconcile-report.md @@ -16,18 +16,18 @@ Agent: Phase D RECONCILE ## HIGH triage -| ID | Source | Decision | Commit / Backlog ref | -|---|---|---|---| -| H-01 (code) | UTC clock breaks Berlin convention | **fixed** | `1258b24` | -| H-02 (code) | useViewportWidth setState in effect | **fixed** | `5a8ad3d` | -| H-03 (code) | Orphan icon wrapper after card-title removal | **fixed via simplify F4** | `6b35cad` | -| H-04 (code) | Tabs ring clip on focus-visible | **fixed** | `977f124` | -| H-05 (code) | `/insights` `data?.` post-narrowing | deferred (D-CR-H-05) | v1.4.20 backlog | -| H-01 (design) | api-tokens truncate-tooltip on touch | deferred (D-DSGN-H-01) | v1.4.20 backlog | -| H-02 (design) | Insights hero density on Pixel-5 | deferred (D-DSGN-H-02) | folded into v1.4.20 redesign | -| H-1 (senior-dev) | DateInput wrapper | **fixed via simplify F3** | `6b35cad` | -| H-2 (senior-dev) | useAuthActionLabels lift-out | **fixed via simplify F1** | `6b35cad` | -| H-3 (senior-dev) | Withings/MoodLog card chrome | deferred (D-SR-H-3) | v1.4.20 backlog | +| ID | Source | Decision | Commit / Backlog ref | +| ---------------- | -------------------------------------------- | ------------------------- | ---------------------------- | +| H-01 (code) | UTC clock breaks Berlin convention | **fixed** | `1258b24` | +| H-02 (code) | useViewportWidth setState in effect | **fixed** | `5a8ad3d` | +| H-03 (code) | Orphan icon wrapper after card-title removal | **fixed via simplify F4** | `6b35cad` | +| H-04 (code) | Tabs ring clip on focus-visible | **fixed** | `977f124` | +| H-05 (code) | `/insights` `data?.` post-narrowing | deferred (D-CR-H-05) | v1.4.20 backlog | +| H-01 (design) | api-tokens truncate-tooltip on touch | deferred (D-DSGN-H-01) | v1.4.20 backlog | +| H-02 (design) | Insights hero density on Pixel-5 | deferred (D-DSGN-H-02) | folded into v1.4.20 redesign | +| H-1 (senior-dev) | DateInput wrapper | **fixed via simplify F3** | `6b35cad` | +| H-2 (senior-dev) | useAuthActionLabels lift-out | **fixed via simplify F1** | `6b35cad` | +| H-3 (senior-dev) | Withings/MoodLog card chrome | deferred (D-SR-H-3) | v1.4.20 backlog | Tally: **7 HIGH fixed, 3 HIGH deferred**. diff --git a/.planning/phase-D-security-findings.md b/.planning/phase-D-security-findings.md index 3c993b99b..fc0484898 100644 --- a/.planning/phase-D-security-findings.md +++ b/.planning/phase-D-security-findings.md @@ -7,12 +7,13 @@ Method: Read CLAUDE.md, .planning/STATE.md, full diff via `git log --oneline v1.4.18...HEAD` + targeted `git diff` per file, plus reads of every changed source file in the focus list, plus cross-checks of: - - the prompt revision against the existing server-side n<3 - confidence clamp (`src/lib/ai/confidence.ts`) - - the integration error decryption path (unchanged from v1.4.18) - - the admin tokens API selector (no `tokenHash`) - - new audit-log labels' semantics - - i18n placeholder interpolation (`{count}`, integer-only) + +- the prompt revision against the existing server-side n<3 + confidence clamp (`src/lib/ai/confidence.ts`) +- the integration error decryption path (unchanged from v1.4.18) +- the admin tokens API selector (no `tokenHash`) +- new audit-log labels' semantics +- i18n placeholder interpolation (`{count}`, integer-only) (Previous v1.4.18 review at `phase-D-v1418-security-findings.md` was overwritten — the v1.4.18 release shipped, those findings already @@ -97,11 +98,11 @@ filed in `.planning/v1419-backlog.md` / `.planning/v15-backlog.md`.) - **Severity**: LOW (existing v1.4.18 behaviour, surfaced by A5 refactor) - **File**: `src/components/settings/integrations-section.tsx:332-333, - 354, 630-631, 663` (``) +354, 630-631, 663` (``) - **Issue**: A5 consolidated the status UI but kept the inline actionable error message under the pill. `viewModel.lastError` is decrypted by the API in `src/lib/integrations/status.ts:112, - 376-383` from the `IntegrationStatus.lastError` ciphertext. The +376-383` from the `IntegrationStatus.lastError` ciphertext. The message is bounded to 1024 chars at encrypt time (`status.ts:367`) and originates from controlled callsites in `src/lib/withings/sync.ts` + `src/lib/moodlog/sync.ts` — neither @@ -118,7 +119,7 @@ filed in `.planning/v1419-backlog.md` / `.planning/v15-backlog.md`.) a token, never an Authorization header. Withings/moodLog OAuth error responses do not contain refresh tokens. - Pill viewer is the message owner only — `/api/integrations/ - status` is `requireAuth`-gated and returns the calling user's +status` is `requireAuth`-gated and returns the calling user's own row. - **Recommendation**: None for v1.4.19. If a future v1.5 sync helper passes raw HTTP body into `recordSyncFailure`, that's the @@ -172,6 +173,7 @@ purely Tailwind class swaps on `` / `` callsite carries it (verified via `grep -c - 'type="date(time-local)?"`). Future date inputs added without +'type="date(time-local)?"`). Future date inputs added without the prop will silently regress. - **Recommendation:** Introduce a thin wrapper `src/components/ui/date-input.tsx` (or `localized-date-input.tsx`) that wraps `` + reads `useTranslations()` internally to set `lang`. Replaces every `` with `` and `` with ``. Eliminates the +lang={locale} … />` with ``. Eliminates the 14× duplication and the parent-component `locale` import noise. - **Ship-blocker?** No. The pattern works correctly today; the refactor is hygiene. Recommend follow-up commit before v1.5 @@ -96,14 +96,14 @@ noted but is not v1.4.19's regression. - **File:** `src/components/settings/integrations-section.tsx` (`WithingsCard` lines 199-531, `MoodLogCard` lines 533-831) - **Issue:** A5 successfully introduced `IntegrationStatusPill` for - the status chip, but the *card chrome* itself + the status chip, but the _card chrome_ itself (`
` → header row with icon + title + pill → `

` muted description → `


` → `
` body) is duplicated verbatim between WithingsCard +className="border-border/60 mt-4">` → `
` body) is duplicated verbatim between WithingsCard and MoodLogCard. The Phase A5 report explicitly mentions - *"Reusable for v1.4.20 Apple Health card on iOS"* — but the + _"Reusable for v1.4.20 Apple Health card on iOS"_ — but the reusable surface today is only the pill, not the card. Adding Apple Health will paste the same chrome a third time. - **Recommendation:** Extract `` co-located with @@ -116,9 +116,9 @@ noted but is not v1.4.19's regression. - `errorMessage?: string` - `children` (the unique card body — credentials form, sync button, etc.) - Both existing cards become a thin shell + their unique body - forms. Apple Health card v1.5 ships as ~30 lines of unique - form, not ~200 lines of mostly chrome. + Both existing cards become a thin shell + their unique body + forms. Apple Health card v1.5 ships as ~30 lines of unique + form, not ~200 lines of mostly chrome. - **Ship-blocker?** No. Defer to v1.4.20 or v1.5 (would touch v1.4.19's tested surface, not worth the risk pre-release). @@ -135,7 +135,7 @@ noted but is not v1.4.19's regression. - `src/components/charts/medication-compliance-chart.tsx:269` - **Issue:** A2 introduced an identical mobile-first header layout (`flex flex-col gap-2 sm:flex-row sm:items-center - sm:justify-between`) plus the matching chip-hide rules +sm:justify-between`) plus the matching chip-hide rules (`hidden sm:inline-flex` on bucket chip + comparison chip) in three chart components. The same 4× `