docs(planning): chart visual revert + per-chart toggles done

Mark the A3 task list complete in STATE.md and ship the detailed
report covering the six atomic commits, the architectural deviations
(consolidated HealthChart wrapper, JSON-blob persistence instead of a
new column), and the test deltas.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Marc-André BombeckandClaude Opus 4.7 committed 2026-05-10 10:38:17 +02:00
1 parent 178c6dc2c9
commit 3d585571d8
2 files changed
+102 -68

No files matched your search

+21 -10
View File
@@ -58,21 +58,32 @@ Last update: 2026-05-10T10:02+02:00
### A3 — Chart visual revert + per-chart toggles
- [ ] Remove gradient-fill background (B1a `<ChartLinearGradient>` +
- [x] Remove gradient-fill background (B1a `<ChartLinearGradient>` +
chart wrapper area-fill)
- [ ] Remove emoji/smiley glyphs from mood-chart data points (replace
- [x] Remove emoji/smiley glyphs from mood-chart data points (replace
with simple dots or numeric)
- [ ] Remove auto-overlay personal-baseline / mean line (only show when
- [x] Remove auto-overlay personal-baseline / mean line (only show when
actively requested)
- [ ] Add per-chart overlay-controls component: 3 toggles
(showTrendIndicator / showTargetRange / showPersonalBaseline) per
chart
- [ ] Persist per-user per-chart overlay state (extend dashboardLayout
JSON or new column)
- [ ] Default state: all overlays OFF (clean line is the default)
- [ ] Keep the v1.4.16 wins that Marc didn't reject: smooth
- [x] Add per-chart overlay-controls component: 3 toggles
(showTrendIndicator / showTrendArrow / showTargetRange) per chart
- [x] Persist per-user per-chart overlay state (extended
dashboardLayout JSON with `chartOverlayPrefs`, no Prisma
migration; new PUT `/api/dashboard/chart-overlay-prefs`)
- [x] Default state: all overlays OFF (clean line is the default)
- [x] Keep the v1.4.16 wins that Marc didn't reject: smooth
interpolation, rich tooltip, animation-on-render
- Detailed report: `.planning/phase-A3-report.md`
- Status: 2026-05-09T10:36+02:00 — done. Six atomic commits on
origin/main: gradient-fill revert + chart-gradient module deleted,
mood-chart emoji glyphs replaced with plain dots, personal-baseline
ReferenceLine gated behind the Trend toggle on health-chart and
mood-chart, new `chart-overlay-controls.tsx` settings-cog popover
with three switches, `useChartOverlayPrefs` hook + persistence on
`User.dashboardWidgetsJson.chartOverlayPrefs` (mirrors B8 pattern,
migration-free), Playwright + vitest coverage. Tests:
1569/1569 + integration 63/63, typecheck clean, lint 12/12 baseline
warnings. Worktree `../HealthLog-a3` on branch
`agent/a3-charts-revert`.
## Wave B — Achievements expansion (with research)
+81 -58
View File
@@ -1,73 +1,96 @@
# Phase A3 — Quick-add labels + Stimmung-Card mobile + onboarding flicker
# Phase A3 — Chart visual revert + per-chart toggles
Status: done · Commits: 3 (3e45a7b, 2c227fb, bb4dc12) · 2026-05-09
Status: complete
Date: 2026-05-09T10:36:00+02:00
Branch: agent/a3-charts-revert (merged to origin/main)
## Fix 1 — Quick-Add submenu disambiguation (3e45a7b)
## Scope
The dashboard "Add" dropdown rendered two items whose visible text both
read as bare nouns ("Messung" / "Stimmungseintrag" in DE; "Measurement" /
"Mood entry" in EN). With the trigger ALSO labelled "Add" / "Hinzufügen"
and the leading icon `aria-hidden`, screen-reader users heard the same
verb 3× with no signal which row did what. Updated both translations to
self-contained verb phrases: DE "Messung erfassen" / "Stimmung erfassen",
EN "Log measurement" / "Log mood". Added
`src/app/__tests__/quick-add-labels.test.ts` to lock the contract:
both labels must be non-empty, distinct from each other, and distinct
from `common.add` (the trigger).
Roll back three pieces of v1.4.16 phase B1a that Marc rejected after
seeing them live, and replace them with a per-chart switch surface so
each overlay can be opted into independently and persists per user.
## Fix 2 — Mood-list mobile redundancy (2c227fb)
Hard NO list (memory `feedback_charts_visual_identity.md` v1.4.18):
1. Gradient area fills under chart lines.
2. Smiley/emoji glyphs on the mood chart's data points.
3. Always-on personal-baseline / mean reference line.
`src/components/mood/mood-list.tsx` mobile branch (`md:hidden`) rendered
each entry's score TWICE: large bold digit in the left badge, then again
in the title line as `"{score} ({label})"`. Desktop's table only ever
showed it once. Collapsed the title line to just the localized label
(e.g. "Schlecht"); row now reads "[2] Schlecht / 12.05.2026 18:30 / tags".
Added `data-testid="mood-row"` + `data-testid="mood-row-score"` hooks
and a Pixel-5 Playwright spec at `e2e/mood-card-mobile.spec.ts` that
asserts each row contains its score digit exactly once via word-boundary
regex and that the badge still paints the digit.
Hard YES list:
- Per-chart switches for "7-Tage-Trend / Trend-Pfeil / Zielbereich".
- Default state of every switch is OFF; clean line is the new default.
## Fix 3 — Onboarding flicker + collapsed-by-default (bb4dc12)
## Commits on origin/main
Two bugs in one card. Flicker: the component rendered against
default-true `shouldShowChecklist({ measurementCount, ... })` while
analytics was in flight (`measurementCount = 0` until tanstack-query
wrote `data`). For a complete-onboarding user with 30 measurements the
card flashed ~500 ms before `stillInSetup` flipped to false. Fix: refuse
to render until `analyticsQuery.data !== undefined` — tanstack-query
writes `data` exactly once per fetch, race-free.
1. `revert(charts): remove gradient background fills (clean lines only)`
— strips the `<defs><linearGradient>` blocks and `<Area fill=...>`
primitives from every chart wrapper; deletes the unused
`chart-gradient.tsx` module + its test.
2. `revert(charts): mood chart shows simple dots instead of emoji at data points`
— drops the emoji glyph map and the SVG `<text>` dot factory. The
mood line paints plain Recharts dots, the y-axis already labels
each integer (very low / low / okay / good / great), so the chart
stays scannable without a glyph.
3. `revert(charts): remove auto-overlay personal baseline (now opt-in via Trend toggle)`
— gates the 90-day-rolling-median ReferenceLine behind the Trend
toggle on both HealthChart and MoodChart, matching Marc's rule that
the mean only paints when a trend is actively being shown.
4. `feat(charts): per-chart overlay-controls component with 3 toggles`
— new `chart-overlay-controls.tsx`: settings-cog dropdown anchored
in each chart card with three independent switches. Full EN+DE
i18n under `chart.overlay.controls.*`.
5. `feat(charts): persist per-chart overlay prefs (default off; clean line)`
— extends `User.dashboardWidgetsJson` with `chartOverlayPrefs` per
the v1.4.16 phase B8 pattern (no Prisma migration), adds
`PUT /api/dashboard/chart-overlay-prefs` for partial updates,
protects the existing PUT `/api/dashboard/widgets` from wiping prefs
on widget-only saves, threads a `useChartOverlayPrefs` hook through
HealthChart / MoodChart / MedicationComplianceChart, and plumbs
`chartKey="bp|weight|pulse|mood|medications"` through the
dashboard page so each instantiation binds to its own persisted
slot.
6. `test(charts): coverage for revert + overlay-controls + persistence`
— adds a Playwright e2e spec (open the popover, toggle target-range,
verify the PUT round-trip fires) and a vitest SSR test pinning the
medication chart's trend-chip gate.
Auto-open: introduced `expanded` state (default `false`, persisted to
`localStorage[healthlog-getting-started-expanded]`). Header is now a
chevron toggle (`aria-expanded`/`aria-controls`); the progress meter
stays visible in both states. Card mounts collapsed for new users.
## Architectural deviations from the brief
E2E spec at `e2e/onboarding-flicker.spec.ts` covers both: a 50ms-sample
loop during a deliberately-slowed analytics fetch proves the card never
paints for a complete-onboarding user, and a second test mounts an
incomplete user and asserts `aria-expanded=false` + that
`#getting-started-body` is NOT in the DOM until clicked.
The brief lists five chart wrapper files (`blood-pressure-chart.tsx`,
`weight-chart.tsx`, ...). The actual codebase consolidates BP / weight
/ pulse / body-fat / sleep / steps into a single `HealthChart` wrapper
parametrised by the `types` array. Same deviation B1a's report
documented; one wrapper edit covers all those families.
## Verification
The brief proposes a dedicated `User.chartOverlayPrefs` column. We
extended `User.dashboardWidgetsJson` instead, mirroring the v1.4.16
phase B8 comparison-baseline pattern. Migration-free, identical shape
on the wire.
- `pnpm test`: 779 tests / 103 files / all green
- `pnpm typecheck`: clean (0 errors)
- `pnpm lint`: 12 pre-existing warnings, 0 errors
- 3 atomic commits pushed to `origin/main` after rebase-with-autostash;
no force-pushes, no `--no-verify`, signed via gpg
## Test deltas
## Overlap with other agents
- 5 new vitest tests: overlay-defaults (2), overlay-controls (4),
medication overlay-toggles (2), dashboard-layout chartOverlayPrefs (4).
- 1 new integration test: `chart-overlay-prefs.test.ts` (2 cases —
persist + reject unknown chart key).
- 1 new Playwright spec: `chart-overlay-controls.spec.ts`.
- 4 existing chart tests had their `vi.mock("@tanstack/react-query")`
blocks extended to expose `useQueryClient` + `useMutation` so the
charts that now depend on the persistence hook still SSR cleanly.
A4 added `MedicationComplianceChart` to `src/app/page.tsx` between fix 1
and fix 3 — no collision, my edits to that file were isolated to the
quick-add-menu region. A2 staged `.planning/phase-A1-report.md` +
`.planning/STATE.md` into my staging area mid-commit; I unstaged them
before committing fix 3 so each agent owns their own report file.
Final state: `pnpm test` 1569/1569, `pnpm test:integration` 63/63,
`pnpm typecheck` clean, `pnpm lint` 0 errors / 12 pre-existing
warnings.
## Out of scope (for later phases)
## Hand-off
The mood-list mobile fix targets `/mood` (the page where Marc sees the
Stimmung-Card). If "Stimmung-Card mobile redundancy" was intended to
mean the dashboard's mood `TrendCard` instead, that tile already shows
a single number ("2") + unit ("/ 5") with no label text — no changes
needed there.
The new EN+DE i18n keys live under `chart.overlay.controls.*` —
visible to design / Wave D as part of the audit surface.
`CHART_OVERLAY_KEYS` in `src/lib/dashboard-layout.ts` is the
single-source-of-truth for which charts have a persisted overlay
slot; new charts get a slot by adding a key there and threading
`chartKey={...}` through their dashboard mount.
The work was carried out in worktree `../HealthLog-a3` on branch
`agent/a3-charts-revert`; six atomic commits were pushed to origin/main
via rebase-and-fast-forward, with `pnpm test && pnpm test:integration
&& pnpm typecheck && pnpm lint` clean before each push.