mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-07 12:22:03 +00:00
docs(planning): mark Wave-B B4 complete + report
Five-commit Phase B4 lands the printable weekly report route, the hero banner card surfacing fresh weekly reports, additive storyboard annotations on the 90-day BP chart, and mobile rail trays for the AI Coach drawer. PROMPT_VERSION 4.20.1 -> 4.20.2 with new GROUND RULES 10/11 covering both new schema blocks. Tests 1902 -> 1975 (+73). Typecheck + lint clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
ebb2bc0602
commit
54d3e92acc
2 files changed
+163
-73
No files matched your search
+17
-4
@@ -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] `<HealthChart>` 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 `<lg`
|
||||
open side-sheets that host the same HistoryRail / SourcesRail
|
||||
the desktop layout uses; refactored body into
|
||||
`<CoachDrawerBody>` for SSR-test surface
|
||||
- Detailed report: `.planning/phase-B4-report.md`
|
||||
|
||||
### B5 — Personal AI Coach Health Score (~2-3 days)
|
||||
|
||||
+146
-69
@@ -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`
|
||||
|
||||
`<LoginOverviewSection>` 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
|
||||
(`<RecentAuditPreview>`, 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
|
||||
`<WeeklyReportView>` (consumes advisor query + auth) and
|
||||
`<WeeklyReportPresentation>` (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.*`.
|
||||
|
||||
`<AppLogPreviewSection>` 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
|
||||
`<HeroStrip>`. 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 `<Link>` 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.*`.
|
||||
|
||||
`<AdminShell>` 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 `<HealthChart>` (commit 4)
|
||||
|
||||
### 4. i18n
|
||||
- Additive `annotations?: Array<{ date, label, color }>` prop on
|
||||
`<HealthChart>`. 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 `<sm` rendering. Full unit suite.
|
||||
- The `/insights` page wires advisor.payload.insights.
|
||||
storyboardAnnotations into the 90-day BP chart, mapping the four
|
||||
canonical categories to Dracula colours (medication=pink,
|
||||
event=cyan, milestone=green, warning=orange).
|
||||
- Recharts visual identity preserved per
|
||||
`feedback_charts_visual_identity.md` — the additive
|
||||
`<ReferenceLine>` 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 `<lg` via two chevron-button
|
||||
triggers anchored to the inside edges of the message thread.
|
||||
- Tapping a trigger opens a side `<Sheet>` that hosts the same
|
||||
HistoryRail / SourcesRail instance the desktop layout uses.
|
||||
- Refactored the drawer body into a separate
|
||||
`<CoachDrawerBody>` 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 `<ReferenceLine>`
|
||||
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.
|
||||
Reference in new issue
Block a user