Files
HealthLog/src/components
Marc-André Bombeck 6f2f43bb49 Say what the AI surfaces actually compute
Three places where the copy promised more than the handler delivers.

The hero's personal-baseline line rendered unconditionally while both its
siblings in the same meta row gate on their own data. It claims the subtitle
above it was drawn from the reader's own last 90 days, but with no briefing the
subtitle is fixed fallback copy computed from nothing — so an account with no
briefing at all was told its generic sentence rested on a personal baseline.
Gate it on the briefing, like the rest of the row.

The pulse sub-page promised a personalised Karvonen target band. Karvonen is
not computed anywhere: the band comes from CDC/NCHS population percentiles by
age and sex, and falls back to a fixed 60-100 for a reader with no age on file.
The copy now says that in all six locales, and the fallback's own source label
says it is a general adult range rather than a personal one, because that arm
is the same band for everyone. Karvonen itself stays unimplemented; whether to
build it is a product decision, not a copy fix.

The Coach's `allTime` window returns 365 days, identical to `lastYear`, and it
is the default. "year so far" was wrong too — a rolling 365 days is not
year-to-date. Both labels now say what the reads do. The two options remain
functionally identical and one of them should probably go, but removing a
default is a product decision.
2026-08-22 16:14:54 +02:00
..

src/components/

React components. The UI primitives are shadcn/ui (new-york style, zinc base) over Radix + Tailwind 4 + Lucide; everything above the primitives is feature-grouped by surface. Components are server components unless they need a hook, state, or browser API, in which case they open with "use client". Charts use Recharts 3 — replacing the chart library requires explicit approval.

Primitives and shell

  • ui/ — shadcn/ui primitives (button, dialog, sheet, table, …). Generated by the shadcn CLI; keep edits minimal and on-style.
  • layout/ — the app shell: sidebar, topbar, bottom nav.
  • providers.tsx, version-poller.tsx — top-level context providers and the self-healing stale-shell poller.
  • i18n/ — translation context + locale switcher.

Feature groups

  • insights/ — insight status, assessment cards, Coach surface, advisor cards (the largest group).
  • medications/ — medication cards, the schedule wizard, intake timeline, detail history.
  • settings/ — the section components behind each settings page.
  • measurements/, mood/, dashboard/ — entry forms, lists, dashboard tiles.
  • charts/ — Recharts wrappers.
  • monitoring/ — Umami / GlitchTip client bootstrap.
  • gamification/, targets/, comparison/, doctor-report/, clinician/, onboarding/, admin/ — the remaining per-surface groups.

Conventions

Kebab-case filenames; React component exports stay PascalCase regardless. (A handful of PascalCase-filename outliers under medications/ + onboarding/ are pre-existing drift, noted in ../../CLAUDE.md.) Every t() call needs a matching key in messages/en.json — guarded by i18n-call-site-coverage.test.ts. Data reads go through TanStack Query with keys from @/lib/query-keys and unwrap (await res.json()).data. Tests live in __tests__/.