The dose-history purge was the one destructive verb in the intake family that removed rows outright. Both siblings, the single-event DELETE and the bulk delete, stamp `deletedAt` and bump `syncVersion`; the purge called `deleteMany`, so a mis-tap was final and a client offline at purge time kept every row forever, because a row that no longer exists produces no tombstone for the sync feed to carry. It tombstones now, scoped to live rows so a second purge counts zero. No inventory refund: a purge wipes a history as bookkeeping, and refunding every dose ever taken would inflate the current container count instead. The manual water quick-add and the lab-result un-delete both wrote health data and reached only the wide event, which expires. Months later nothing could answer who put a day's total there or who brought a reading back, and with a second person able to act on a shared record that question has a second possible answer. Both write a durable row now, named after the neighbours they sit beside. The refused-delegation audit comment claimed the row was written for the owner's benefit. It is not: it is filed under the caller, it is only written for a header refusal, and a header names an account the caller merely asserts. Filing under that claim would let anyone write rows into any account's activity feed by naming it. The comment says what the row is now, and points at `recordDelegatedAccess`, which is the half the owner does see. Two comments in the biomarker surfaces still claimed the `SetNull` foreign key left the readings behind when a marker is deleted. That stopped being true when delete became a "drop this and its history" action and the confirmation copy was rewritten in six locales to say so. The purge route gains a call-shape assertion rather than a count assertion, because a count comes back identical from a `deleteMany`. The lab restore route had no test at all and now has one.
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__/.