diff --git a/.planning/STATE.md b/.planning/STATE.md index fe3966d4c..e7ea48b0f 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -144,10 +144,23 @@ commit. ### B4 — Weekly Report + Storyboard + Mobile passes (~3-4 days) -- [ ] New `/insights/report/[week]` route + `window.print()` export -- [ ] Storyboard 90-day BP timeline with annotations[] -- [ ] Mobile passes: B1 + B2 mobile equivalents (drawer → - full-screen sheet) +- [x] PROMPT_VERSION 4.20.1 → 4.20.2; aiInsightResponseSchema gains + `weeklyReport` + `storyboardAnnotations`; GROUND RULES 10/11 + across EN + DE prompts +- [x] New `/insights/report/[week]` route — newsletter-style + printable surface with Summary / Going-well / Worth-watching / + Tips / Data-quality sections; `window.print()` export via + Tailwind `print:` variants +- [x] Hero strip banner-card surfaces the fresh weeklyReport with + Read · Share · Export PDF actions; Share uses Web Share API + + clipboard fallback; Export deep-links to `?print=1` +- [x] `` gains an additive `annotations[]` prop; + `resolveAnnotationPositions()` pure helper maps date→pointIndex + with a 7-day snap window and 24-char small-viewport truncation +- [x] Coach drawer rail trays — chevron-button triggers on `` for SSR-test surface - Detailed report: `.planning/phase-B4-report.md` ### B5 — Personal AI Coach Health Score (~2-3 days) diff --git a/.planning/phase-B4-report.md b/.planning/phase-B4-report.md index a0ebd4329..0b386a45c 100644 --- a/.planning/phase-B4-report.md +++ b/.planning/phase-B4-report.md @@ -1,89 +1,166 @@ -# Phase B4 — Admin logs visibility deepening (v1.4.16) +# Phase B4 — Weekly Report + Storyboard + Mobile passes (v1.4.20) Status: complete -Date: 2026-05-10T00:11+02:00 -Commits on origin/main: +Date: 2026-05-10 +Branch: `develop` -- `8ac5602` (audit-log filtering, pagination, CSV export — bundled with - the Wave-A verification-gate planning commit due to the marathon - coordinator's stash race; my code, wrong commit subject) -- `4cc3d8d feat(admin): app-log preview surfaces last 1h of structured events with filter + JSON inspector` -- `6520ae4 feat(admin): sidebar entry for app-logs` +## Scope -## Scope delivered +Continues the Insights redesign with the printable weekly report +route, AI-narrated storyboard annotations on the 90-day BP chart, +and mobile passes for the B1 hero + B2 Coach drawer. Strategic +plan: `.planning/phase-D-v1419-product-lead-review.md` § "Phase B4 — +Weekly Report + Storyboard + Mobile passes". -### 1. Audit-log enhanced filtering, pagination, CSV export +## Commits on `origin/develop` -`` is now the deeper viewer admins asked for. It -keeps the failed-only quick-pill from the v1.4.x UI and stacks the new -filter row on top: actor (matches userId OR `user.username`, -case-insensitive), action (dropdown populated from -`/api/admin/audit-log/actions`'s `groupBy(action)`), target (substring -on the JSON-encoded `details` column), and date-range presets -(24h / 7d / 30d / all). Per-page is 25 / 50 / 100; next/prev pagination -is real, total comes from a `count()` companion query. CSV export uses -the existing `toCSV()` helper and downloads what the active filter -set returns right now. +1. `6d4cba1` feat(insights): weeklyReport + storyboardAnnotations schema + prompt +2. `8f18c7f` feat(insights): /insights/report/[week] printable weekly report +3. `f186845` feat(insights): hero strip weekly-report banner card +4. `ff1e335` feat(charts): storyboard annotations on HealthChart +5. `ebb2bc0` feat(coach): mobile rail trays for the AI Coach drawer +6. (this commit) docs(planning): mark B4 complete + report -`GET /api/admin/audit-log` learned the `actor` / `action` / `target` / -`since` / `until` / `page` / `perPage` query params. Out-of-range -`perPage` falls back to 50 instead of 400-ing so a stale UI never -deadlocks. Legacy `limit` / `offset` / `filter=auth` callers -(``, the failed-only pill) are unchanged. +## What shipped -9 unit tests pin every filter and the pagination contract; 1 covers -the actions endpoint. +### 1 · Schema + prompt (commit 1) -### 2. App-log preview surfaces last 1h of structured wide-events +- `weeklyReportSchema` — ISO week + summary (10..800 chars) + + goingWell / worthWatching / tips arrays (≤5 entries each, every + bullet ≤280 chars) + optional dataQualityNotes (≤280 chars). +- `storyboardAnnotationSchema` — date (YYYY-MM-DD) + label (≤80 + chars) + category (medication / event / milestone / warning) + + detail (≤400 chars). Hard array cap 20. +- Both blocks are `nullable().optional()` on the response root so + legacy 4.20.1 caches round-trip. +- PROMPT_VERSION bumped 4.20.1 → 4.20.2. +- GROUND RULE 10 + 11 added to EN + DE prompts with conservative + phrasing constraints + section-name match. -New `src/lib/logging/in-memory-buffer.ts` — 500-entry FIFO ring -buffer, hooked into `transports.emitEvent()`. Mirrors what would ship -to Loki (sampler-gated). Per-process and volatile — header copy -spells that out so admins know to keep Loki configured for durable -diagnostics. +### 2 · `/insights/report/[week]` (commit 2) -`GET /api/admin/app-logs` reads the buffer with `traceId` / `level` / -`action` / `since` / `until` / `limit` filters, runs every event -through `redactSecrets()` on egress so a stray Bearer / hlk\_ / sk- -token in `error.message` never leaks to the admin UI; storage stays -raw to keep the diagnostic value when shipped to Loki. +- New `src/lib/insights/week-iso.ts` with `parseWeekISO`, + `toWeekISO`, and `weekISOToRange`. Pure helpers, full unit suite. +- New `src/components/insights/weekly-report-view.tsx` split into + `` (consumes advisor query + auth) and + `` (pure layout). The split keeps the + vitest tests free of TanStack Query setup. +- New `src/app/insights/report/[week]/page.tsx` — thin client + wrapper. Malformed slug → 404 via `notFound()`. `?print=1` query + triggers `window.print()` after first paint. +- Print export uses Tailwind `print:` variants: toolbar hidden, + article width unconstrained, padding zeroed. A4 / Letter both + print without margin clipping. +- Empty state with Generate CTA when the cached report's weekISO + doesn't match the route param. +- EN + DE i18n keys under `insights.report.*`. -`` lives at the new `/admin/app-logs` route — -table of recent events (level icon / timestamp / action / duration / -trace short-id), click row → JSON-pretty-print modal, 30s refetch. -Mirrors the per-section pattern v1.4.16 A1 established. +### 3 · Hero banner card (commit 3) -### 3. Sidebar entry +- New `weeklyReportReady?: { weekISO, href }` prop on + ``. When set, the hero paints a slim banner card with + Sparkles icon, "Your Week N report is ready" label, and Read / + Share / Export PDF actions. +- Read → in-app `` to the report URL. +- Share → `navigator.share()` when supported, else + `navigator.clipboard.writeText` + sonner toast acknowledgement + (success or failure). +- Export PDF → deep-links to the report URL with `?print=1` so the + report page auto-fires `window.print()` after first paint. +- The insights page derives `weeklyReportReady` from + `advisor.payload.insights.weeklyReport` so the banner appears + the moment a fresh PROMPT_VERSION 4.20.2 generation lands. +- EN + DE i18n keys under `insights.heroBanner.*`. -`` gains the `app-logs` row with a `FileText` icon. The -global sidebar still surfaces a single `/admin` link per the v1.4.15 -A1 + v1.4.16 A1 conditional pattern — per-section nav stays inside -the shell. +### 4 · Storyboard annotations on `` (commit 4) -### 4. i18n +- Additive `annotations?: Array<{ date, label, color }>` prop on + ``. The chart line + tooltip + comparison overlay + remain untouched — annotations sit between the cartesian grid + and the data lines so they read as orientation, not data. +- New pure helper `resolveAnnotationPositions()` maps annotation + dates onto the bucketed point indices with a 7-day snap window + (so annotations don't stack on monthly buckets) and a 24-char + truncation precomputed for `` does NOT change the existing line/area visuals. -`admin.section.auditLog.*` (filterActor, filterAction, -filterActionAll, filterTarget, filterSeverity, filterDate, perPage, -prev / next / pageOf, export, empty + range24h / 7d / 30d / all) and -`admin.section.app-logs.*` (subtitle, processNote, filterTraceId / -Action / Level / Range, range15m / 1h / 6h / all, table column -labels, empty + emptyDescription, refresh, eventDetails, closeDetails) -land in both EN and DE. Locale-integrity guard stays green. +### 5 · Mobile rail trays (commit 5) -## Coordination friction +- The history rail (left) and sources rail (right) were desktop-only + since B2b. B4 surfaces them on `` that hosts the same + HistoryRail / SourcesRail instance the desktop layout uses. +- Refactored the drawer body into a separate + `` component — pure-presentational shell, + parent owns state. The split lets the SSR test harness pin the + trigger slot markers without rendering the outer Radix Sheet + portal (which is client-only). +- Selecting a conversation from the mobile history tray closes the + tray automatically so the user lands back on the message thread. -The marathon coordinator stashed my work-in-progress 6 times across -the session ("wave-a-gate-stash" through "wave-a-gate-stash-final") -and re-committed parts of it under foreign agents' commit messages — -which is why commit 1's logic landed under `8ac5602 docs(planning): -Wave-A verification gate report + STATE update`. Code is verbatim -what B4 wrote; only the commit subject drifted. Re-recommends the -per-agent worktree adoption already noted as recurring meta in -STATE.md from v1.4.15. +## Verification gates -## Verification +- `pnpm typecheck` — clean. +- `pnpm lint` — 13 pre-existing warnings (none introduced by B4). +- `pnpm test --run` — 1902 → 1975 tests (+73). Test files 230 → 235. +- `pnpm test:integration` — not regressed (no integration coverage + added in B4 scope; lift to v1.4.21 if/when the report route grows + a server endpoint). -- `pnpm vitest run src/lib/logging/ src/app/api/admin/audit-log/ src/app/api/admin/app-logs/ src/components/admin/__tests__/sections.test.tsx` — 51 / 51 green -- `pnpm typecheck` — 0 B4 errors (the typecheck failures present are - sibling B7 broken endpoint paths) -- `pnpm lint` — 0 errors / 12 pre-existing warnings (none on B4 files) +## Print verification + +`window.print()` produces a clean A4 / Letter print. The toolbar +hides via `print:hidden`, the article wrapper drops padding via +`print:px-0 print:py-0` and uses `print:max-w-none` so the report +fills the page without margin clipping. Each section paints as a +borderless block via `print:border-0 print:rounded-none`. JsPDF +parity (matching the doctor-report style) remains v1.5 work as +scoped. + +## Memory-care + +- `feedback_charts_visual_identity.md` — Recharts kept; the + annotation rendering uses Recharts' built-in `` + primitive without touching the existing chart line / area / + tooltip visuals. +- `feedback_marc_voice_english.md` — every commit message + UI + string + report sentence is in Marc's voice; no maintainer-name + references in code or commits. + +## Deferred / not shipped + +- jsPDF parity for the weekly report (matches doctor-report style) + → v1.5 once Apple Health adds richer data per the strategic + plan. +- A weekly cron job that auto-generates the weekly report at the + end of each ISO week — current model: the report is part of the + rolling AI advisor payload, surfaces when a regenerate produces + one. Future work could schedule it via pg-boss. +- Mobile pass for B1 (HeroStrip + DailyBriefing) — the components + already responded to 375 px from B1 ship; no layout regressions + spotted at the B4 review. Banner card on the hero stacks + cleanly inside the existing `flex-wrap` action row. + +## UX decisions worth flagging for review + +1. **Banner card placement** sits between the title block and the + action row, not above the title (which would push the greeting + below the fold on 375 px). Chosen so the banner reads as + "secondary callout" without competing with the greeting. +2. **Share fallback** uses sonner toasts rather than a modal — + matches the rest of the app's lightweight feedback pattern. +3. **Storyboard annotation snap window** is 7 days. Wider snaps + (e.g. 14 days) caused multiple annotations to collapse onto the + same monthly bucket on the 90-day window; 7 days reads cleanly + on every visible bucket type without dropping legitimate events. +4. **Mobile trays use the same rail components** as the desktop + layout. The alternative was to render compact-mobile variants; + keeping a single source of truth means future polish to the + rails lands on both surfaces simultaneously.