Commit Graph
973 Commits
Author SHA1 Message Date
Marc-André Bombeck 68033b2d66 refactor(onboarding): point consumers at the kebab-case component files
Update the onboarding step page, baseline form, and the anamnesis-card
spec to import from the renamed kebab-case files. Export identifiers stay
unchanged.
2026-06-19 22:17:34 +02:00
Marc-André Bombeck 922f770b41 refactor(medications): rename PascalCase component files to kebab-case
Bring the medication card, scheduling, wizard, and detail component
files in line with the kebab-case file-naming convention. Component
export identifiers are unchanged; only filenames and the import paths
that point at them move.
2026-06-19 22:17:13 +02:00
Marc-André Bombeck d75a538614 Show the QR, passphrase, and protected badge in the owner UI
On a successful create the Sharing section now renders the QR code (from
the #k= deep link), the passphrase as copyable text, and the link, with a
clear shown-once notice. The active-link list carries a small passphrase
indicator. Add the new strings (QR label, passphrase label, copy buttons,
hints, protected badge, and the public unlock prompt) across all six
locale bundles.
2026-06-19 22:03:53 +02:00
Marc-André Bombeck 5783acacbb Gate the public share view behind the passphrase
A protected share link no longer renders the record until the passphrase
is verified. The public page checks the gate state first (without bumping
access counters), and for a link with a passphrase hash it serves a gate
island unless a valid, token-scoped unlock cookie is present. A legacy
link with a null passphrase hash renders exactly as before.

The unlock route verifies the submitted passphrase with a constant-time
compare against the stored hash, is rate-limited by share-unlock token
and IP before any compare, and on success sets a short-lived (30 min)
httpOnly, SameSite=Strict, Secure cookie scoped to that one token's view
path. Every failure class answers one blunt 401; no-store and the flat
404 for unknown links are preserved. The gate island auto-submits the
#k= fragment (scrubbing it from history first) or prompts for input.
2026-06-19 22:03:46 +02:00
Marc-André Bombeck 0518b26d08 feat(settings): restore the clinician share-link section
Bring back the Settings → Sharing ("Freigabe") section: the owner mints
a time-boxed, revocable, read-only share link to their health record at
the public /c/[token] view. The backing model, the /api/share-links
lifecycle routes, and the public clinician view were left in place; this
restores the owner Settings surface and re-wires it.

Place the slug directly after gesundheitsakte and before export — sharing
the health record belongs next to the health-record export. The entry is
always available (no module gate), like account and export.

Render the card through the shared SettingsCard primitive so it matches
every sibling section; drop the section's own page title (the shell
supplies the heading and subtitle). Route the list, create, and revoke
calls through the api-fetch helper instead of raw fetch, and align the
touch targets with the mobile sizing contract.
2026-06-19 21:38:40 +02:00
Marc-André Bombeck 4daa5a428f Merge wave-mobile-settings: SettingsCard primitive + phone tap targets
Replace the hand-rolled Settings card divs across every section with a
shared SettingsCard wrapping the Card primitive, eliminating the sm-vs-md
padding split and the primitive bypass, and raise the Settings touch
controls to a 44px floor that condenses at sm+.
2026-06-19 21:30:35 +02:00
Marc-André Bombeck e0c1601a36 fix(settings): raise account form CTAs to the 44px touch floor
The profile save, add-passkey, change-password trigger, and password
dialog submit ran at 40 px on phones; apply min-h-11 sm:min-h-9.
2026-06-19 21:28:34 +02:00
Marc-André Bombeck d9393a2148 fix(settings): raise primary controls to the 44px touch floor
Apply the canonical min-h-11 sm:min-h-9 (and min-w-11 for icon-only
controls) to the primary Settings controls that sat at 32-40 px on
phones: the AI fallback-chain reorder/remove/save/add icons, provider
form save/test/connect actions, coach-memory forget, avatar replace and
remove, section save/cancel/reset CTAs, the export and import action
rows, the About external links, and the thresholds editor row. Collapse
the injection-sites checkbox grid to one column on phones and stack the
password-change grid below lg.
2026-06-19 21:27:05 +02:00
Marc-André Bombeck a371678460 test(coach): guard composer controls against the sub-44px floor
Assert the send and stop controls render the `size-11 sm:size-9` tap-
target pattern so a future restyle cannot quietly drop them back to the
36px size the audit flagged. Renders the real component and matches the
emitted class string, the same model as the bottom-nav size test.
2026-06-19 21:18:27 +02:00
Marc-André Bombeck e3071d4f0a fix(mobile): raise primary touch controls to the 44px floor
Sweep the primary touch controls that sat below the 44px tap-target
floor on phones onto the canonical `min-h-11 sm:min-h-9` (text) /
`size-11 sm:size-9` (icon) pattern, condensing back at `sm:` upward:

- Coach composer mic / stop / send icon buttons (were `size-9`).
- Dashboard hero CTA, link and action variants (were `size="sm"`).
- Vorsorge list-view "mark done" button (was `min-h-9`) and its kebab,
  which now uses `size="icon-lg"` so the rendered control is 44px
  rather than the icon variant's 40px.
- Illness list-view "log day" button (was `min-h-9`).
- Medication wizard Step 3 injection-sites disclosure (was `h-9`).

The Vorsorge dashboard-card capture action was raised alongside the
ListRow migration.
2026-06-19 21:18:19 +02:00
Marc-André Bombeck 54a2d19833 feat(ui): add shared ListRow primitive and adopt it for mini-cards
The bordered list-row "mini-card" appeared three times with three
shapes: the Vorsorge dashboard row (`rounded-md p-2.5`), the daily-
briefing rows (`rounded-md p-3`), and the measurement-list mobile row
(bespoke `rounded-lg p-3` div). Introduce `ListRow` (`rounded-lg border
p-3`, `asChild` per the shadcn convention) and migrate all three to it.
The primitive owns only the box shape; each caller keeps its layout,
colour, and interaction classes, so this is structural normalization
with no content or behaviour change.
2026-06-19 21:18:11 +02:00
Marc-André Bombeck d2be72d57a feat(mobile): add scroll-touch momentum utility for horizontal strips
Add a `.scroll-touch` utility that restores iOS WebKit momentum
scrolling (`-webkit-overflow-scrolling: touch`) and contains the
overscroll chain so a flick at the end of a horizontal row does not
rubber-band the whole page. Apply it to the insights tab strip and the
cycle tab list — the two in-app horizontal scrollers that lost inertial
flick under the default `overflow-x-auto`.
2026-06-19 21:18:05 +02:00
Marc-André Bombeck 76bc0f2e1f refactor(settings): compose import/export card shells from SettingsCard
Migrate the ImportCardShell and ExportCardShell containers to
SettingsCard, threading their dynamic outerClassName through cn. The
layout hub-link row keeps its element (a full-row Link, not a content
card).
2026-06-19 21:17:35 +02:00
Marc-André Bombeck 96f2b47545 refactor(settings): compose multi-card sections from SettingsCard
Migrate the remaining hand-rolled card containers in the account,
about, medications, api, mood, notification-status, and advanced
sections to SettingsCard, preserving each card's heading, body, and
test hooks. Leaves the passkey list-row (rounded-lg) for the list-row
token track.
2026-06-19 21:16:10 +02:00
Marc-André Bombeck e31f9690e2 refactor(settings): compose single-card sections from SettingsCard
Swap the hand-rolled bg-card border-border rounded-xl border p-4 sm:p-6
container for SettingsCard across the single-card sections (integration
cards, notification channel cards, coach prefs, cycle, modules, mood
reminder, thresholds, dashboard-layout, about-me, low-stock, and the
health-record export panel). Drops the sm: padding split and the
primitive bypass; landmark sections keep their element via as="section".
2026-06-19 21:14:57 +02:00
Marc-André Bombeck 9182b60dc8 feat(settings): add SettingsCard primitive for the standard card shape
Wrap the ui Card so every Settings section composes from one bordered
container with the shared p-4 md:p-6 padding contract, replacing the
hand-rolled bg-card border-border rounded-xl border p-4 sm:p-6 div that
bypassed the primitive and stepped padding at sm: instead of md:.
2026-06-19 21:10:21 +02:00
Marc-André Bombeck 876e94b5c4 Merge wave-med-staleness: reflect supply changes on the next read
The medication card and table render dose-derived stock from the cached
medications list, but the inventory write routes evicted no server cache
and the client invalidated only the per-item inventory key, so a new
container's stock kept serving the pre-write value for the stale window.
Hard-evict the user's medication caches on every supply write and
invalidate the list key alongside the inventory key on the client.
2026-06-19 21:09:08 +02:00
Marc-André Bombeck 6609ce0dc7 fix(medications): evict supply caches so the card reflects stock at once
The /medications card and table render the dose-derived stock
(stockUnitsRemaining / stockDosesRemaining) straight from the
GET /api/medications list payload, which reads through cachedSwr on the
60s-fresh + 10-min-stale medications bucket. Registering, adjusting, or
deleting an inventory container changes that stock, but the inventory
routes never invalidated any cache — so the list served the pre-write
stock for the rest of the stale window. On the client the add / adjust /
delete supply mutations only invalidated the per-medication inventory
query, never the medications-list query that the card reads, so a mounted
list never refetched even once the server caught up.

Hard-evict the per-user medications + compliance buckets from every
supply-affecting write (inventory POST, the per-item PATCH / DELETE, and
the deprecated glp1 POST dose-change + ledger branches) so the next read
reflects the change rather than a stale SWR value. On the client,
centralise the supply mutations on a shared invalidateSupplyQueries helper
that drops both the medications-list key and the per-medication inventory
key. The card's neutral styling is unchanged.
2026-06-19 21:08:35 +02:00
Marc-André Bombeck eedfd9bff1 Merge wave-settings-ia: Labs, Vorsorge, and Illness as Settings sections
Fold the three standalone module settings pages into the Settings shell so
they open in-context with the same left-nav, heading, and chrome as every
other section. Remove the standalone pages and the now-unused
ModuleSettingsFrame, and drop the orphaned settings i18n blocks.
2026-06-19 21:06:54 +02:00
Marc-André Bombeck 43d9610f03 refactor(settings): fold Labs, Vorsorge, and Illness into the shell
Promote the three per-module customise surfaces from standalone
ModuleSettingsFrame pages to first-class Settings sections. They now
render inside the Settings shell — same left nav, heading, and chrome as
account / ai / integrations / notifications — instead of their own
back-button-and-title frame outside it.

Add labs, illness, and vorsorge to the slug registry (after mood) and to
SETTINGS_SECTIONS with FlaskConical / Thermometer / CalendarCheck icons.
labs and illness gate on their toggleable modules; vorsorge has no
module, so its entry is always shown. Three thin section components wrap
the existing LabsSettings / IllnessSettings / VorsorgeSettings content,
mirroring MedicationsSection / CoachSection.

Delete the three standalone /settings/{labs,vorsorge,illness} routes so
the wrench deep links resolve through the dynamic [section] route, and
drop ModuleSettingsFrame now that nothing renders it. Add the section
title / subtitle / description keys across all six locales and remove the
dead per-module *.settings.* blocks the old pages consumed.
2026-06-19 21:06:25 +02:00
Marc-André Bombeck bda06c9ec4 refactor(query-keys): route remaining bare arrays through the factory
The target editor invalidated a bare ["insights"] array on save and reset.
That literal sat outside the centralised factory, so the broad insights
fan-out it intended never matched the reads, which key through
insightsTargets/insightsRoot. Route the editor's reads and invalidations
through userThresholds(), insightsRoot(), insightsTargets() and analytics()
so a saved target actually refreshes every insights surface.

Migrate the other call sites the lint rule does not reach onto the factory:
the Coach conversation rail + thread reads, the per-metric personal-records
badge, the per-day measurement drill-down, the dashboard intake
compliance-chart fan-out, the per-medication side-effects list, the
onboarding auth invalidations, the notification-preferences read, and the
PWA persister's auth-me lookup.

Add the matching factory keys: coachConversations, coachConversation,
personalRecordsByMetric, measurementDrilldown, complianceChartInline and
medicationSideEffects. Each new key reuses the prefix its reads already use
so no invalidation shape drifts.
2026-06-19 20:57:18 +02:00
Marc-André Bombeck 3e04035de8 fix(coach): paint the launcher glyph white on the gradient
The floating Coach launcher inherited the button's dark foreground token,
which left the sparkle glyph as a dark outline on the purple-pink
gradient. The glyph is decorative and the button carries its own
accessible name, so the white mark reads cleaner without affecting the
control's non-text contrast, which the offset focus ring already
provides.
2026-06-19 20:48:02 +02:00
Marc-André Bombeck 2e27c3c441 refactor(insights): share the briefing row layout
KeyFindingRow and SignalRow rendered an identical tone bar + metric icon
+ headline/body/delta and the same link-when-routed behaviour, differing
only in their data-slot and body copy. Extract a single BriefingRow and
have both delegate to it.
2026-06-19 20:35:25 +02:00
Marc-André Bombeck a3b274171c fix(a11y): announce coach history state and Vorsorge trend
Add aria-expanded to the coach drawer's history-collapse control so its
expanded state is exposed, matching the expand toggle. Give the Vorsorge
trend strip an sr-only summary of the latest value and seven-day
direction, and key the bars on measuredAt rather than the array index.
2026-06-19 20:31:58 +02:00
Marc-André Bombeck aa092df9f0 refactor(settings): unify the integration card skeleton
Every Settings → Integrations block now paints one consistent shape:
heading (icon + name + status pill) → a white primary description → a
grey secondary description that ends with the setup-guide link rendered
inline, instead of a standalone bottom-of-card element.

OAuth-only (WHOOP/Fitbit), BYO-credential (Withings/Oura/Polar) and
manual-key (Nightscout) cards share the same skeleton via the new
IntegrationCardDescription helper; the credential form stays as an extra
block where it applies. The "where to find these credentials" hint moves
above the Save button instead of sitting below it.

Rewrite the per-provider description strings across all six locales into a
parallel two-part shape with even length, and drop the now-orphaned
overlap/experimental sub-notes and the standalone setup-guide link.
2026-06-19 19:58:48 +02:00
Marc-André Bombeck 5fca70524d Merge wave-sleep: drop last-night card, big chronotype, fix AI-hint 2026-06-19 19:48:50 +02:00
Marc-André Bombeck 43388eabbf Merge wave-coach: Claude/ChatGPT-style Coach frontend redesign 2026-06-19 19:48:33 +02:00
Marc-André Bombeck 4bda26f47c fix(insights): rework the Sleep view — drop the redundant last-night card, promote chronotype, fix the assessment slot
Remove the single-night "Last night" hypnogram from the sleep overview: its
per-stage breakdown (time + %) duplicated the phase-distribution stacked bar
directly below it. The /api/sleep/night route stays (the dashboard reads it);
only the redundant surface is gone.

Promote the chronotype to the prominent bottom block of the view. Split it out
of the rhythm section (now the sleep-debt headline alone) into its own section:
a large band label with the natural sleep-midpoint clock beneath it and an
expandable disclosure for social jetlag + MSFsc. It reads the same
["sleep-rhythm"] cache, so it adds no round-trip, and keeps the calm
"still learning your rhythm — N of M nights" state.

Fix the sleep-quality assessment slot. It disabled the status fetch whenever the
AI narrative was absent, so the card could not read hasProvider and fell back to
its no-provider default — surfacing the "connect an AI provider" CTA even for
accounts that have a provider connected, stacked under the grounded note. The
card now stays enabled and reports the truthful state: no provider shows its
clean AI-settings CTA alone; a connected provider with no text yet shows the
grounded note; warm or preparing AI text wins. Exactly one block fills the slot.
2026-06-19 19:48:10 +02:00
Marc-André Bombeck 36adedad58 feat(coach): premium chat surface — narrower column, collapsible rail, voice dictation
Redesign the Coach frontend toward a calm, prompt-first reading
experience:

- Narrow the reading column to a centred max-w-2xl with a roomier
  vertical rhythm so the conversation reads like a document rather than
  a packed log.
- Make the page-surface conversation rail collapsible and collapsed by
  default. A single labelled toggle in the rail strip opens it (lg+),
  the rail heading carries a matching close control, and the column
  folds to zero width with a smooth grid transition. Below lg the
  bottom tray is unchanged. The fullscreen header keeps only the
  minimize control.
- Replace the boxy default scrollbar on the thread, history list, and
  composer with a thin, rounded, subtle bar across WebKit and Firefox,
  scoped to the components.
- Polish the pre-stream beat: the Thinking indicator now pairs bouncing
  dots with the label, and the assistant turn fades in so the hand-off
  to streamed tokens reads as one motion.
- Return voice dictation to the composer via the Web Speech API. The
  mic mounts only where the browser supports recognition, dictates into
  the textarea, and is keyboard- and screen-reader-accessible.

New labels land in all six locale bundles.
2026-06-19 19:48:03 +02:00
Marc-André Bombeck 0a4be95aba Merge wave-rings: flatten the health-score rings to the chart style 2026-06-19 19:45:44 +02:00
Marc-André Bombeck d92b3b9efd style(insights): calm and flatten the health-score rings
The score dials wore a token-tinted drop-shadow bloom, a conic specular
sheen, a breathing pulse on the green ring, and a dark-to-neon two-stop
arc gradient. Against the flat 2-D Recharts charts that read as a glowing
3-D gauge and made the overview restless.

Make the calm treatment the default everywhere, not only behind the `flat`
prop:

- Drop the bloom, the sheen, and the pulse for every ring. `.wellness-ring-arc`
  is now a plain flat stroke; the sheen overlay paints nothing. The shared
  cycle ring inherits the same quiet.
- Mute the arc colours toward the chart palette: the two gradient stops sit a
  hair apart for a whisper of depth instead of a neon sweep, pulled down and
  desaturated per hue in both the Dracula and Alucard sets. Band semantics
  (green/yellow/red thresholds) are unchanged.
- `flat` now only drops the entrance sweep + count-up, so the dashboard hero
  ring paints its value at once. The /insights strip keeps the subtle spring
  fill; prefers-reduced-motion still zeroes it.

Score and band logic, thresholds, and the data-band/aria contract are
untouched.
2026-06-19 19:45:23 +02:00
Marc-André Bombeck c7425ca426 feat(vorsorge): add 7-day trend strip + measurements deep link to reminder cards
Enrich the Vorsorge cards with a discreet 7-day trend strip and a path
into the underlying readings.

- A quiet seven-bar strip of the reminder metric's last seven readings
  sits under the metric context on both the dashboard summary card and
  the full-grid cards, mirroring how a dashboard tile carries a small
  trend. Neutral muted bars, no status colour. A free-text reminder or a
  metric with fewer than two readings shows nothing, so card height stays
  stable. The strip reads a bounded last-7 window per type through the
  existing measurements endpoint, cached by type under the measurements
  invalidation prefix.
- The card kebab gains a 'Show measurements' item for measurement-linked
  reminders that opens /measurements pre-filtered to that type.
- The measurements list accepts a ?type=<MEASUREMENT_TYPE> deep link that
  seeds the existing client-side type filter while leaving the rail
  interactive; unknown tokens are dropped. The ?add= behaviour is
  unchanged.
- New labels added across all six locales.
2026-06-19 19:45:14 +02:00
Marc-André Bombeck f931f2f5c2 feat(insights): render signals of the day and remove the overview ask-coach block
Render the new signalsOfDay list at the top of the daily-briefing card — a
present-focused row (headline + concrete nudge) sharing the tone bar, metric
icon, and sub-page routing of the key-finding row, with matching typography
(text-sm headline, text-xs muted body) so the card reads consistently with the
rest of the insight surfaces. Add the signalsTitle string across all six
locales.

Remove the "Ask the coach" action button and the guided-questions chip strip
from the overview hero band: the Coach stays the bottom-right drawer mounted by
the insights layout shell. The hero is now greeting + subtitle + baseline meta
+ the optional Health Score panel, and no longer reads the coach flags or the
launch context. Update the coach-cascade / disable-cascade fixtures and the
hero-strip slot tests to pin the affordances absent.
2026-06-19 19:37:01 +02:00
Marc-André Bombeck dae7138fc6 fix(settings): keep the health-record entry reachable regardless of the doctorReport opt-out
The health-record section (PDF + FHIR R4 export) was the only entry-point
gated on the doctorReport module's nav toggle, so flipping that opt-out in
the Modules hub made the whole section vanish from Settings with no
in-context way back. Drop the nav gate: the entry-point now always shows.
The doctorReport module still governs the data layer — the server-side
/api/export/health-record route stays the hard enforcement (403
module.disabled over Bearer when opted out). Assert the entry shows for a
default, empty, and opted-out modules map.
2026-06-19 00:03:22 +02:00
Marc-André Bombeck 6f866ff1c6 fix(coach): bound the conversation scroll region so the composer stays pinned
The message thread used h-full inside a plain-block wrapper, so its height
resolved against an auto-height parent: the scroll container grew with its
content instead of scrolling, pushing the composer down and leaving a stray
scrollbar on the page.

Make the thread wrapper a flex column and switch the thread (and its empty
state) from h-full to min-h-0 flex-1, so the scroll region takes a bounded
track from the flex parent. The conversation now scrolls cleanly inside the
card while the composer stays pinned to the bottom.
2026-06-18 23:58:43 +02:00
Marc-André Bombeck 8234427a94 fix(vorsorge): match the medication-card grammar on the reminder card
Mirror the medication card's name + cadence + status layout:
- the cadence ("alle 7 Tage") renders as a chip directly to the right of the
  metric name via a new MedicationCardHeader nameChip slot, instead of on the
  state-badge row below the category;
- the due / overdue status renders as plain text, not a chip;
- the "zuletzt erledigt" line always renders, falling back to an em dash when
  there is no last-done value, instead of being hidden.

The green action button is unchanged. Also drop the per-module tour trigger
from this surface (the tour is first-time-only now).
2026-06-18 23:58:35 +02:00
Marc-André Bombeck 3ba542f797 fix(onboarding): make the guided tour first-time-only, drop every re-entry trigger
The guided tour now exists only as the first-time auto-start after onboarding.
Remove every in-app trigger that re-opened it: the per-module "show this tour"
button on the dashboard, measurements, mood, medications, labs, illness, cycle,
achievements, insights, and coach surfaces; and the Settings replay card.

Delete the now-orphaned ModuleTourTrigger component, the tour-restart worker,
the healthlog:module-tour and healthlog:tour-restart event listeners, the
single-stop overlay path, and the force-launch session marker. The first-time
auto-launch gate and the tour overlay itself are unchanged. Prune the orphaned
i18n keys across all locales and update the affected tests.
2026-06-18 23:58:27 +02:00
Marc-André Bombeck f67542d29e fix(settings): align section nav with the first card via the grid, not a spacer
The settings and admin shells reserved the page-heading height in the left
nav with a hidden replica block. The replica wrapped differently in the 220px
nav column than the real heading in the wide content column, so the first nav
item sat too low and drifted across locales.

Hoist the heading into the shell and place it in its own grid row spanning only
the content column: row 1 holds the heading, row 2 holds the nav and the cards.
The nav's first item and the first card now start the same grid row, so they
align by construction regardless of how the title or subtitle wraps. Drop the
spacer component.
2026-06-18 23:58:10 +02:00
Marc-André Bombeck 8ff3b51ba3 refactor: remove dead exports and an unused prop
Drop the health-score card's inert onAskCoach prop and its now-dead
pass-through from the hero strip, the buildDashboardBands re-export that no
caller reached through the snapshot module, an unused tour-progress status
type, and an orphan service-worker cache helper.
2026-06-18 22:42:27 +02:00
Marc-André Bombeck 22f588b34d refactor(ui): correct stale comments and steady the settings-nav spacer
Drop the overstated claim that the due-reminder green button mirrors the
medication card (the med take button is always the default tone), fix the
module-tour anchor attribute named in a doc comment, and feed the active
section title into the settings nav spacer so its heading line wraps the same
way a long localized title does.
2026-06-18 22:42:22 +02:00
Marc-André Bombeck 9014203d8a fix(a11y): label per-reminder toggles and wire disclosure controls
The diabetes PATCH parsed its body without a size cap; bound it through
safeJson like the sibling routes. Label each reminder's enable/disable switch
by its own name span so screen readers hear the reminder rather than one
generic label repeated per row. Point the chronotype and illness disclosure
triggers at the regions they reveal via aria-controls.
2026-06-18 22:42:04 +02:00
Marc-André Bombeck 547a7f8904 fix(a11y): give the due-reminder action a readable foreground
The Vorsorge "Jetzt messen" / mark-done button hard-coded white text on a
solid green fill. In the dark theme the fill is the bright Dracula green, so
white-on-green reads about 1.37:1 — below the WCAG AA floor.

Add a theme-aware `--success-foreground` token (near-black glyph on the dark
fill, white on the darker light-mode green) mirroring the existing
`--primary-foreground` pattern, and use `text-success-foreground` on both the
card and list variants. Green stays only on the action button; the card
surface remains neutral.
2026-06-18 22:41:31 +02:00
Marc-André Bombeck 04a50b2702 refactor(insights): drop the per-page generic medical disclaimers
Remove the page-level Insights disclaimer footer and the health-score and
correlation card disclaimers now that the not-a-diagnosis acknowledgment
is shown once at onboarding and the legal text stays on the privacy page.
Device-provenance, contraception-safety, statistical-method and
shared-report notes stay where they convey specific information.
2026-06-18 22:11:45 +02:00
Marc-André Bombeck bfba92cb83 refactor(settings): share one heading frame across all settings pages
Teach SettingsSectionFrame an explicit title/subtitle mode alongside the
slug-driven mode, and have the per-module settings pages (Vorsorge,
Illness, Labs) delegate to it so every settings surface renders the same
heading frame.
2026-06-18 22:06:40 +02:00
Marc-André Bombeck 6614e0646f merge: Coach v1.18.6 nudge and conversation continuity
Add the Coach proactive nudge-status surface and last-seen tracking
(migration renumbered to 0176) plus the seen endpoint.
2026-06-18 22:04:31 +02:00
Marc-André Bombeck d1355a2999 merge: sleep, insights and recovery surfacing
Suppress the synthesized sleep timeline for non-measured nights while
keeping measured-night detail, and refine the insights and recovery
surfacing.
2026-06-18 22:04:06 +02:00
Marc-André Bombeck 3d3ad8d070 merge: per-module settings pages and disclaimer preference
Add the P1 module settings surfaces and the one-time medical-disclaimer
acknowledgment preference (migration 0175).
2026-06-18 22:03:42 +02:00
Marc-André Bombeck 0a8ccaa30c feat(onboarding): one-time medical-disclaimer acknowledgment
Replace the per-page and per-chart disclaimer banners with a single
acknowledgment at the start of onboarding: HealthLog is a private tracking
tool, not a clinical assessment or diagnosis; talk to a doctor if worried.

- record the acknowledgment per user (disclaimer_acknowledged_at/_version,
  migration 0175) mirroring the research-mode acknowledgment precedent
- gate the welcome "Get started" on the checkbox; expose the timestamp on
  /api/auth/me so a returning user is never re-asked
- keep the full legal text reachable on the public privacy page
2026-06-18 21:37:13 +02:00
Marc-André Bombeck 267dcad13d feat(modules): unify Vorsorge, Illness and Labs with the medication pattern
- add a wrench beside each module's add button linking to the module's own
  settings page; rename every add button to a plain "hinzufügen"
- give each module a settings page: view (cards/list) + manual reorder; Labs
  also gets a sort-order choice (by last reading) and biomarker CRUD/reorder
- collapse the Illness "abgeschlossen" list by default
- rebuild the Vorsorge card on the medication card's building blocks: a green
  "Jetzt messen" action, the interval as a chip beside the name, and an
  in-interval progress signal; drop the kebab "anpassen" and stray actions
- persist per-module view/order/sort client-side; add reverse-coverage-clean
  strings across all six locales
2026-06-18 21:36:58 +02:00
Marc-André Bombeck 33d7d103da feat(settings): standardize settings and admin section framing
Introduce a shared SettingsSectionFrame (the settings twin of the admin
renderer's SectionFrame) that emits the canonical visible heading +
subheading, and route all 19 settings sections through it. Every settings
page now shows a real h1 + subtitle in the reference Übersicht style
instead of an invisible sr-only title; the section bodies drop their own
headings and off-style intro paragraphs (the explanatory copy folds into
the frame subtitle).

- Route the admin About page through SectionFrame so it carries the same
  visible heading as every other admin section.
- Rename the AI settings section from KI-Auswertung to KI-Anbieter across
  six locales: the page configures the provider and key, not an analysis.
- Add a heading-block spacer to the settings and admin sidebars so the
  first menu item lines up with the top of the first card.
- Remove the always-on core-domains card from Module: a tracking area that
  can't be turned off doesn't need listing.
- Move the proactive-coach control out of Benachrichtigungen into Coach.
- Move admin module availability out of the Coach section into its own
  page: it gates every module, not just the coach.
- Give the Layout Insights editor a proper Insights heading.

Adds settings.sections.<slug>.subtitle and the new admin keys across all
six locales; removes the now-unused module core-domain strings.
2026-06-18 21:28:33 +02:00