mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 12:32:43 +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)
|
### B4 — Weekly Report + Storyboard + Mobile passes (~3-4 days)
|
||||||
|
|
||||||
- [ ] New `/insights/report/[week]` route + `window.print()` export
|
- [x] PROMPT_VERSION 4.20.1 → 4.20.2; aiInsightResponseSchema gains
|
||||||
- [ ] Storyboard 90-day BP timeline with annotations[]
|
`weeklyReport` + `storyboardAnnotations`; GROUND RULES 10/11
|
||||||
- [ ] Mobile passes: B1 + B2 mobile equivalents (drawer →
|
across EN + DE prompts
|
||||||
full-screen sheet)
|
- [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`
|
- Detailed report: `.planning/phase-B4-report.md`
|
||||||
|
|
||||||
### B5 — Personal AI Coach Health Score (~2-3 days)
|
### 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
|
Status: complete
|
||||||
Date: 2026-05-10T00:11+02:00
|
Date: 2026-05-10
|
||||||
Commits on origin/main:
|
Branch: `develop`
|
||||||
|
|
||||||
- `8ac5602` (audit-log filtering, pagination, CSV export — bundled with
|
## Scope
|
||||||
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 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
|
1. `6d4cba1` feat(insights): weeklyReport + storyboardAnnotations schema + prompt
|
||||||
keeps the failed-only quick-pill from the v1.4.x UI and stacks the new
|
2. `8f18c7f` feat(insights): /insights/report/[week] printable weekly report
|
||||||
filter row on top: actor (matches userId OR `user.username`,
|
3. `f186845` feat(insights): hero strip weekly-report banner card
|
||||||
case-insensitive), action (dropdown populated from
|
4. `ff1e335` feat(charts): storyboard annotations on HealthChart
|
||||||
`/api/admin/audit-log/actions`'s `groupBy(action)`), target (substring
|
5. `ebb2bc0` feat(coach): mobile rail trays for the AI Coach drawer
|
||||||
on the JSON-encoded `details` column), and date-range presets
|
6. (this commit) docs(planning): mark B4 complete + report
|
||||||
(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.
|
|
||||||
|
|
||||||
`GET /api/admin/audit-log` learned the `actor` / `action` / `target` /
|
## What shipped
|
||||||
`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.
|
|
||||||
|
|
||||||
9 unit tests pin every filter and the pagination contract; 1 covers
|
### 1 · Schema + prompt (commit 1)
|
||||||
the actions endpoint.
|
|
||||||
|
|
||||||
### 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
|
### 2 · `/insights/report/[week]` (commit 2)
|
||||||
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.
|
|
||||||
|
|
||||||
`GET /api/admin/app-logs` reads the buffer with `traceId` / `level` /
|
- New `src/lib/insights/week-iso.ts` with `parseWeekISO`,
|
||||||
`action` / `since` / `until` / `limit` filters, runs every event
|
`toWeekISO`, and `weekISOToRange`. Pure helpers, full unit suite.
|
||||||
through `redactSecrets()` on egress so a stray Bearer / hlk\_ / sk-
|
- New `src/components/insights/weekly-report-view.tsx` split into
|
||||||
token in `error.message` never leaks to the admin UI; storage stays
|
`<WeeklyReportView>` (consumes advisor query + auth) and
|
||||||
raw to keep the diagnostic value when shipped to Loki.
|
`<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 —
|
### 3 · Hero banner card (commit 3)
|
||||||
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. 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
|
### 4 · Storyboard annotations on `<HealthChart>` (commit 4)
|
||||||
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. 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,
|
### 5 · Mobile rail trays (commit 5)
|
||||||
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.
|
|
||||||
|
|
||||||
## 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
|
## Verification gates
|
||||||
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
|
- `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
|
## Print verification
|
||||||
- `pnpm typecheck` — 0 B4 errors (the typecheck failures present are
|
|
||||||
sibling B7 broken endpoint paths)
|
`window.print()` produces a clean A4 / Letter print. The toolbar
|
||||||
- `pnpm lint` — 0 errors / 12 pre-existing warnings (none on B4 files)
|
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