Commit Graph
1714 Commits
Author SHA1 Message Date
Marc-André Bombeck 8447ad90cc merge: settings IA round 2 — top-text removal, integration split, medications toggleable, coach activate-flip, gesundheitsakte de-hero 2026-06-16 21:50:27 +02:00
Marc-André Bombeck 9b191a208d feat(settings): round-2 information-architecture rework
Apply the v1.18.0 walkthrough notes across the settings surface:

- Drop the explanatory top-text block from every settings section so
  content starts at one consistent vertical height (the sr-only heading
  stays for the accessibility tree).
- Move "Restart onboarding tour" out of Account into Advanced.
- Module hub: drop the explanatory line above the first card.
- Split the Integrations page into three left-side entries — the
  Connections content is now the Integrationen page itself, with
  Channels and Sources (source weighting) as their own entries. Drop the
  /settings/sources redirect (it is a real route again); Channels is a
  new entry.
- Notifications: drop the top text, the channels / inbox cross-links,
  and the embedded Vorsorge editor (it has its own page). Keep the mood,
  low-stock, and proactive-coach reminder cards.
- Rename the Layout hub entry to "Layout".
- Flip the Coach toggle to "Activate Coach" (default on, opt-out) over
  the same single disableCoach column — one source of truth.
- Move the AI "About me" context into Account → Profil, before
  cycle tracking.
- Gesundheitsakte: replace the gradient hero with a normal card.

i18n across all six locales for the renamed / added labels; settings
tests updated for the new structure.
2026-06-16 21:47:00 +02:00
Marc-André Bombeck a7b2b61b99 merge: cycle log-day sheet redesign — phase header, field tooltips, goal-aware fertility 2026-06-16 21:42:29 +02:00
Marc-André Bombeck cdf7fa2d41 merge: admin consolidation — unified coach section, backups layout, danger-zone parity 2026-06-16 21:42:29 +02:00
Marc-André Bombeck bc2ce702f1 fix(insights): rebuild the recovery page onto the canonical metric structure
The recovery page rendered a grid of compact device-score tiles plus a
redundant cross-link to the recovery-score anatomy at the top. It now
follows the same structure as every other metric page (blood pressure,
pulse, the HealthKit scaffold): each present device-native signal renders
a block carrying a short explainer, the max / median / mean stat strip,
the shared chart with the identical 7 / 30 / 90 / All toggle, and a
per-chart assessment. Multiple charts now carry multiple matching texts.

Register the seven device-native recovery / strain signals (ANS charge,
day / workout strain, cardio load, whole-day average / max heart rate,
energy expenditure) in the generic metric-status registry so each chart
gets a generated assessment, gate them on the recovery module, and give
each its own chart-overlay slot. Drop the duplicate top score-link block
(this surface is reached from the overview already).

Regenerate the OpenAPI contract for the widened metric-status enum.
2026-06-16 21:35:09 +02:00
Marc-André Bombeck f3388ceb70 feat(cycle): redesign the log-day sheet — phase header, field info, wider dialog
Anchor the capture surface to the ring and lower its cognitive load:

- A hue-tinted phase-context strip (day-of-cycle + phase) at the top of the
  sheet, on the wellness-tile surface, honesty-gated the same way the phase-
  education card is — no phase claim until prediction is on, not raw-chart,
  and at least three cycles observed; otherwise a neutral day header.
- Inline field explainers (FieldInfo) on the clinical fields: BBT, cervical
  mucus, ovulation test, spotting, pregnancy/progesterone test, intercourse,
  protection — factual, descriptive-only, reachable by keyboard and screen
  reader.
- BBT is now the shadcn Input rather than a bare element, with a morning-
  timing hint, so it matches every other control.
- The symptothermal section (Temperature & ovulation) auto-expands for
  fertility goals and for an edited day that already holds a fertility sign,
  so a pre-filled value is never hidden behind a collapsed section.
- Desktop dialog widened to lg so the form breathes.

The payload builders and the form-hydration reconciliation are unchanged, so
the wire contract and their unit tests are untouched.
2026-06-16 21:32:58 +02:00
Marc-André Bombeck eb40f9b46f feat(cycle): field-explainer tooltip + log-sheet i18n scaffold
Add a cycle-scoped FieldInfo affordance (a focusable, SR-reachable info
button with a 44 px touch target, mirroring the mood-explainer precedent)
and the i18n keys the redesigned log-day sheet needs: a cycle.fieldInfo.*
namespace of descriptive-only explainers (BBT, cervical mucus, ovulation
test, spotting, pregnancy/progesterone test, intercourse, protection) plus
cycle.sheet.phaseDayHeader and cycle.sheet.bbtHint, across all six locales.
2026-06-16 21:32:48 +02:00
Marc-André Bombeck 513287d732 feat(admin): hide the Replay-tour card on the admin About page
The onboarding tour is a user-facing affordance with no place in the
admin console. Add a hideTourReplay prop to AboutSection (default off, so
Settings -> About is untouched) and pass it from the admin renderer.
2026-06-16 21:32:23 +02:00
Marc-André Bombeck 804e8f713a fix(admin): align the Danger Zone with the shared card layout
The Danger Zone rendered a lone icon above a left-floating label with
the delete button dropped below, unlike every other admin section. Adopt
the shared SettingsCardHeader shape — icon, title, description, and the
destructive action in the status slot — so the structure matches the
rest of the console while the tint and warning icon keep it flagged as
destructive.
2026-06-16 21:32:18 +02:00
Marc-André Bombeck 1e7b701fa6 fix(admin): give the Backups header room to breathe
The snapshot-count badge now leads (numbers first) and the explainer
plus docs link move into the card header's description slot, which
carries proper spacing and left-aligns under the title. Previously the
description sat in a separate paragraph crammed directly beneath the
"Backup now" button.
2026-06-16 21:32:12 +02:00
Marc-André Bombeck 3a29387393 refactor(admin): consolidate assistant + feedback-quality into one Coach section
The ai-quality, assistant, and coach-feedback admin sections were three
separate navigation entries for one coherent coach-quality concern. Fold
them into a single "Coach" section that stacks the assistant surface
toggles, the server-key + module-availability operator config, and both
feedback-quality tables (Coach + Insights). Drop the three old slugs and
their section copy; add admin.section.coach.* across all six locales.
2026-06-16 21:32:06 +02:00
Marc-André Bombeck 559366e308 feat(settings): make medications a toggleable module
Medications graduated from the always-on core set (weight / blood
pressure / pulse stay core) to an opt-out module. The surface gates
off the resolved module map — the left-nav entry, the dashboard
medication widget, and the dedicated Medikamente settings entry hide
when the account turns the module off. The medication data routes stay
exempt from the gate (same data-layer reasoning as mood / labs): an
importer, a sync, and the user's ability to clean up entries keep
working while the surface is hidden, and re-enabling finds the
schedule and intake history intact.

Wire the module-route gate inventory, the dashboard widget/summary
maps, the PATCH allowlist, and the nav model; regenerate the OpenAPI
contract for the new module key.
2026-06-16 21:31:54 +02:00
Marc-André Bombeck ba8804cce0 merge: coach-cadence suggestions — SUGGEST-REMINDER sentinel, suggestion SSE frame, one-tap reminder 2026-06-16 21:19:36 +02:00
Marc-André Bombeck 12f4bc24e8 feat(coach): evidence-based cadence suggestions with one-tap in-chat reminder
The Coach can append a ---SUGGEST-REMINDER--- sentinel to propose a
measurement cadence (weight daily, the ESH/AHA 7-2-2 home-BP protocol,
structured glucose). The server resolves the cadence from a closed catalog
and emits an additive 'suggestion' SSE frame the chat renders as a one-tap
action card; accepting it creates a MeasurementReminder with origin COACH
through the same engine the Vorsorge surface uses (server-authoritative
schedule, finite course window self-expires via endsOn).

Non-naggy by construction: a frequency-cap cooldown, dismissal memory, a
master opt-out under Coach settings, and an explicit 'I measure enough'
stop path, all in the coach-prefs blob. Triple dedup at suggest, render,
and create so a cadence is never double-suggested or double-created, and
suggestions for a disabled module never surface. RHR/HRV stay passive --
the Coach surfaces the baseline, it never nudges to 'go measure' them.

The reminder DTO now echoes origin and endsOn for the iOS client.
2026-06-16 21:17:51 +02:00
Marc-André Bombeck 6ee0060c8a merge: illness/condition journal P2 MVP — born-gated module, episode CRUD, symptom timeline 2026-06-16 21:17:09 +02:00
Marc-André Bombeck cc32e2adf7 merge: Labs overhaul — biomarker catalog, structured entry, dashboard-style chart, edit/undo, backfill
# Conflicts:
#	src/app/api/labs/route.ts
2026-06-16 21:17:09 +02:00
Marc-André Bombeck b079431a8d feat(illness): add the condition-journal MVP behind a born-gated module
Introduce a retrospective illness/condition journal: episodes with a
lifecycle (acute / chronic-ongoing / recurring / flare) and a daily
symptom timeline forked structurally from the cycle log-day surface. The
journal is a record, not a medical device — no prediction or diagnosis UI.

- Register `illness` as a born-gated (opt-in / default-off) module. The
  gate resolver flips the disabled-allowlist default to off for born-gated
  keys, so the surface stays dark until the account opts in from the
  Modules hub. `isIllnessEnabled` + `requireIllnessEnabled` delegate to the
  module foundation (one source of truth) and re-stamp an illness errorCode.
- Episode CRUD under /api/illness: list / create / get / edit / resolve /
  delete, plus a per-episode-day day-log upsert on (episodeId, date). Every
  route wraps apiHandler, Zod-validates with returnAllZodIssues, narrows
  userId from auth, builds data field-by-field, and gates the module.
  Free-text notes encrypt at rest through the shared Bytes codec.
- Log-day sheet (cycle fork): ~8 Jackson/WURSS symptom chips 0-3 + a
  functional-impact group + fever + an encrypted note, one row per day.
- Episode history page + a born-gated nav entry, neutral palette, status
  via a neutral Badge, retrospective-only copy. i18n across all six locales.
- Cover the new routes in the module-route-gate inventory; unit tests for
  the day-log upsert, the gate enforcement, and the born-gated resolver.

The /api/auth/me module map now projects the `illness` flag (openapi.yaml
regenerated).
2026-06-16 21:09:35 +02:00
Marc-André Bombeck 04c95e5ba1 feat(labs): structured entry, per-biomarker chart, and edit/delete UI
Rework the Labs surface to match the rest of the app:

- Add a biomarker manager on the Labs page (define/edit/delete markers,
  seed from a common panel) — the catalog lives with Labs, not Settings.
- Replace the free-text add form with a structured one: pick a biomarker,
  enter the value against its known unit/range; '+ define new' inline.
- New /labs/[biomarkerId] detail page with a proper dashboard-style chart
  (Recharts line + shaded reference band + dashed bounds, range tabs,
  tooltip) replacing the 72x20 sparkline, plus the reading history with
  full edit/amend/delete and a delete-Undo toast.
- List cards group by linked marker and deep-link to the detail chart.

The reference band uses a muted token fill, never an alarm colour; the
neutral ReferenceRangeBadge is reused for the in/out-of-range verdict.
2026-06-16 21:06:08 +02:00
Marc-André Bombeck a0d864db8c feat(vorsorge): widen the linkable measurement set to the body-comp family
The reminder type allow-list exposed 7 of the full MeasurementType enum.
Widen it to the ~15 active-measurement set: vitals (weight, BP, pulse,
glucose, SpO2, temperature) plus the body-composition family a scale
produces (fat mass, fat-free mass, muscle, lean body mass, bone mass,
body water, visceral fat, BMI). One step on the scale satisfies every
linked reminder at once. Passive scores, cumulative activity, and device
events stay excluded — nudging someone to 'go measure' a passive sample
makes no sense.

App-layer only: the column is the full enum, so no migration. Group the
dropdown (Vitals / Body composition) and add the labels across all six
locales.
2026-06-16 20:59:06 +02:00
Marc-André Bombeck 3bbc0016d9 fix(cycle): restore the wellness-tile entrance so the ring renders
The wheel tile, phase-education card, and dashboard cycle tile each set
both data-revealed and .wellness-tile-rise on the same node. The keyframe
selector is [data-revealed="true"] .wellness-tile-rise (descendant
combinator), so it never matched a same-node pair — the tiles stayed at
the rise rule's opacity: 0, invisible but still boxed. Lift data-revealed
onto a contents wrapper (the documented pattern from the cycle insight
summary card) so the entrance plays and the signature ring paints.
2026-06-16 16:52:03 +02:00
Marc-André Bombeck f0614a8080 fix(a11y): raise inactive tab-trigger contrast on dark theme
The inactive tab text used --muted-foreground (#9aa3b3) on the muted
(#44475a) tab strip, reading 3.6:1 — below the WCAG AA 4.5:1 floor that
axe flags on /settings/integrations. Add a --tab-inactive token (#b3bccd
dark, 4.79:1 on the strip; light mirrors the existing 4.58:1 muted tone)
and point the dark-mode inactive trigger color at it. The active trigger
keeps --foreground.
2026-06-16 16:51:56 +02:00
Marc-André Bombeck 2057cb9d2b fix(dashboard): split module maps into client-safe module to unblock build
The settings dashboard-layout client component imported WIDGET_MODULE_BY_ID
from @/lib/dashboard/snapshot, which transitively pulls the server snapshot
builder -> lib/db -> @prisma/adapter-pg -> pg -> node:dns. Turbopack tried to
bundle pg for the browser and failed (Module not found: Can't resolve 'dns'),
breaking next build and therefore e2e and both Docker arch builds.

Move the two pure data maps (WIDGET_MODULE_BY_ID, SUMMARY_TYPE_MODULE) into
@/lib/dashboard/widget-modules, which imports only the ModuleKey and
MeasurementType types. snapshot.ts re-exports both for the server call sites
and the existing tests; the client component imports from the new module.
2026-06-16 16:34:28 +02:00
Marc-André Bombeck b5f5347944 test(gamification): type the achievements-query mock to drop the unused-param warning 2026-06-16 11:58:06 +02:00
Marc-André Bombeck 68fd659f04 test(settings): align mood + medication section copy assertions with the refreshed i18n
The v1.18.0 IA restructure reworded the mood + medications section descriptions;
update the SSR copy assertions to the new strings (the i18n parity guards stayed
green, but these per-section copy assertions pinned the old text).
2026-06-16 03:06:59 +02:00
Marc-André Bombeck 2f02af4980 merge(reconcile): t3-featurepages audit findings 2026-06-16 03:02:56 +02:00
Marc-André Bombeck 3f3b8cbf0c fix(ui): unify the add-entry pattern across feature pages and add the Vorsorge heading 2026-06-16 02:55:27 +02:00
Marc-André Bombeck 6160320ca9 fix(settings): hide dashboard widget toggles for disabled modules
A widget toggle whose owning module is disabled is a dead control: the
dashboard snapshot gates that tile and chart out server-side regardless
of the switch state, so the row in Settings just confuses. Read the
resolved per-user module map from the session and drop each widget row
whose owning module is off, mapping widget id to module key through the
shared WIDGET_MODULE_BY_ID. Core widgets (no module entry) and any row
whose module key is unset stay visible; the gate fails open when the map
is absent.
2026-06-16 02:54:25 +02:00
Marc-André Bombeck 3be34ceb11 merge(reconcile): b2-insightsai audit findings 2026-06-16 02:46:34 +02:00
Marc-André Bombeck b2684a2e21 feat(nav): gate the Insights destination on the insights module
Mark the top-level `/insights` nav destination `requiresModule: "insights"`
so it drops from both bars when the account has the insights module off,
mirroring mood / labs / coach / achievements. The bottom-nav pinned
`/insights` as a fixed primary slot regardless of the module map; it now
filters that slot through the same per-user map the More hub honours
(fail-open on a missing key / unloaded /me payload). A disabled insights
module is hidden everywhere — the primary-slot filter keeps it out of the
More hub too, so it is hidden, not relocated.

Extend the nav-model + bottom-nav tests with insights on/off coverage.
2026-06-16 02:42:43 +02:00
Marc-André Bombeck f73bc32a72 merge(reconcile): b5-achievements audit findings 2026-06-16 02:20:45 +02:00
Marc-André Bombeck 63901edea7 refactor(doctor-report): remove the orphaned legacy doctor-report surface
The DoctorReportDialog + its /api/doctor-report, /pdf and /availability routes
were referenced only by their own tests — the health-record (Gesundheitsakte)
export is the live surface. Remove the dead dialog, routes, their tests, and
the now-stale docs page; the shared doctor-report-data aggregator stays (the
health-record export uses it). The route-gate inventory exempt list is updated
accordingly.
2026-06-16 02:16:38 +02:00
Marc-André Bombeck ca196f27a6 fix(onboarding): skip the achievements tour stop when the module is off
The dashboard tour launcher now derives includeAchievements from the
per-user module map (modules?.achievements !== false), so an account
that has the achievements module turned off no longer walks the user to
a page it has hidden.

Mention the module on/off concept in the integrations tour stop, where
the tour introduces Settings and customization, so a first-time user
learns whole areas can be turned on or off.
2026-06-16 02:04:20 +02:00
Marc-André Bombeck b6db529dee feat(doctor-report): wire the doctorReport module toggle to the health-record surface
The doctorReport module toggle was inert: turning it off hid nothing and the
server-side export route accepted requests regardless. Gate the live surface
on the module — the Health-record settings entry now hides client-side when
the module is off, and POST /api/export/health-record refuses with a 403
module.disabled envelope, so the doctor-report surface cannot be reached over a
Bearer token either.
2026-06-16 02:00:48 +02:00
Marc-André Bombeck b51c76238a docs(medications): correct the stale dose-status comment to the neutral med-card rule
The compliance number + card already render neutral (no grade tint); only a
stale comment still described a green take-window highlight the implementation
does not do. Reword it to state status drives a discreet line/glyph, never a
card background/border tint.
2026-06-16 01:49:03 +02:00
Marc-André Bombeck 6c9004b055 refactor(settings): route section headers through the shared primitive
mood, medications, Vorsorge, the health-record export panel and the export
section hand-rolled their card headers; route them through the shared settings
card-header primitive so every settings card header is structurally identical.
2026-06-16 01:44:44 +02:00
Marc-André Bombeck 0d963fffa9 fix(dashboard): unify recent-card view-all affordance and neutralise chrome 2026-06-16 01:27:55 +02:00
Marc-André Bombeck 2425832f47 merge(reconcile): r4-logic audit findings 2026-06-16 00:59:31 +02:00
Marc-André Bombeck c2537e2c08 merge(reconcile): r2-labs audit findings 2026-06-16 00:59:31 +02:00
Marc-André Bombeck bf5deb33e2 refactor(labs): one shared reference-range classifier and range formatter
Reference-range classification + low/high range rendering was implemented three
times (validations, PDF core, lab list). Extract a single classifier and a
structure-only range formatter that takes a per-surface number formatter, so
each surface keeps its own number formatting while sharing the canonical
classification. Behaviour is unchanged per surface and now covered by one test.
2026-06-16 00:58:27 +02:00
Marc-André Bombeck 91d01d154a fix(settings): make delegated module rows read-only managed deep-links
The Module hub rendered live switches for the delegated keys cycle and coach,
but the gate resolves those from their own sources (cycle from CycleProfile,
coach from the operator flag + disableCoach), so a toggle wrote an inert entry
to modulePreferencesJson, snapped back, and still fired a success toast. Render
delegated modules as read-only rows that deep-link to their real control, strip
delegated keys from the modules PATCH schema so no inert value is stored, drop
the duplicate cycle control, and surface an operator-disabled state with the
previously orphaned hint string.
2026-06-16 00:51:16 +02:00
Marc-André Bombeck ba7a72f484 fix(labs): confirm destructive deletes on lab results and Vorsorge reminders
The single-row delete on lab results and on preventive-care reminders
fired immediately on click, unlike the measurement and mood lists which
gate the same action behind a confirm dialog. Route both through the
shared DeleteButton so a stray tap can no longer drop a reading or a
reminder, and add the per-surface confirm copy across all locales.
2026-06-16 00:45:19 +02:00
Marc-André BombeckandClaude Opus 4.8 3de53f549c fix(health-score): drop the mood pillar when the mood module is disabled
The Personal Health Score weighted the 0.20 mood-stability pillar
unconditionally — the fast-path read mood entries regardless of the
account's module state, so a user who turned the mood module off was
still scored (and silently penalised or rewarded) by a pillar hidden
everywhere else in the product. The dashboard already blanks the mood
tile and the coach snapshot unions mood out; the score ring and the
insights card pillar list did not.

Thread a default-on `moodEnabled` flag through the fast-path. When the
caller resolves the mood module as disabled the helper skips the mood
read entirely and leaves the series empty, so `moodStability` returns
null and the existing proportional null-redistribution re-scales the
surviving pillars to sum to 100. The analytics route resolves the
module server-side and threads the flag; the insights card hides the
Mood row via a new SSR-safe `useModuleEnabled` accessor so it never
advertises a pillar the account turned off.

Golden fixtures pin mood-on vs mood-off to different, correctly
re-weighted scores and assert the disabled read is never issued.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 00:39:55 +02:00
Marc-André Bombeck 9c5e7a0186 feat(settings): gather Coach settings into a dedicated entry
Move the Coach preference cards (disable toggle, preferences, durable-fact
memory) out of the AI / Assistant section into their own Coach entry,
module-gated on the coach module. The AI entry keeps its name and owns
provider / model / BYOK configuration plus the "about me" context (which
the daily briefing reads too, so it is not Coach-only).

The proactive Coach-nudge card stays in Notifications: it is a reminder
TYPE, already coach-module-gated there alongside the other reminder types,
and belongs with the reminder family rather than the Coach preferences.
2026-06-15 23:28:22 +02:00
Marc-André Bombeck fce9ca8f1a feat(settings): gather medication settings into a Medikamente entry
Promote the Medikamente section from a hidden Layout-hub child to its own
standalone nav entry (always shown — medications is a CORE domain) and
gather the injection-site exclusions card here from the account profile,
so every medication-specific preference lives on one screen. The Layout
hub keeps only the dashboard + insights arrangement editors.

The low-stock card stays whole in Notifications: its runway config and the
low-stock reminder toggle are one tightly-coupled control writing a single
prefs row, so splitting only the config out would break the card.
2026-06-15 23:23:50 +02:00
Marc-André Bombeck 16bd43c08f feat(settings): move mood settings into a dedicated Stimmung entry
Promote the mood-tag management surface from a hidden Layout-hub child to
its own standalone settings nav entry, shown only when the mood module is
enabled. The shell now module-gates per-submodule entries off the resolved
`useAuth().user.modules` map (fail-open: a missing key reads as enabled).
The Layout hub keeps only genuine layout/personalisation editors.
2026-06-15 23:18:54 +02:00
Marc-André Bombeck 59fea72d8b feat(settings): give the health record its own Gesundheitsakte entry
Lift the full health-record export (PDF + FHIR R4 + zip package) out of
Export & Import into a dedicated top-level Gesundheitsakte section. Export
& Import keeps the generic CSV/JSON data-out and import paths only. The
new section is always available (not module-gated).
2026-06-15 23:14:28 +02:00
Marc-André Bombeck 604778f166 feat(settings): make Benachrichtigungen the single module-gated reminder-types home
Consolidate every reminder TYPE onto the Notifications screen and drop the
redundant stacked breadcrumb for one clean heading. Each reminder-type card
is shown only when its module is enabled, read from the resolved
useAuth().user.modules map (mood card on mood, Coach nudge on coach); the
gate fails open so a stale /me payload never blanks a card. Low-stock maps
to the medications CORE domain and Vorsorge (preventive care) is not a
toggleable module, so both stay shown — the Vorsorge editor embeds in place.
The delivery channels keep a single concise pointer to Integrations rather
than a duplicated section. Reword the heading copy and drop the now-unused
settings.sections.reminders.* keys across all six locales.
2026-06-15 23:06:45 +02:00
Marc-André Bombeck fccdcb378e refactor(settings): remove the redundant Erinnerungen hub page
The standalone /settings/reminders page was a link-only hub that merely
deep-linked into the canonical editors — duplicating the Notifications
entry. Drop the section, its slug, and its placeholder/route wiring, and
301-redirect /settings/reminders to /settings/notifications. Reminder
types consolidate onto the Notifications home in a follow-up.
2026-06-15 23:03:52 +02:00
Marc-André Bombeck 7b80a38ea2 refactor(settings): fold Sources into Integrationen as a sub-tab
Source priority decides which connection wins when two report the same
metric, so it belongs with the integrations rather than as a standalone
settings page. Sources renders as the third Integrations sub-tab
(Connections / Channels / Sources); the standalone `sources` slug is
removed from the shell nav, slug registry, and route dispatch, and
`/settings/sources` 301-redirects to `/settings/integrations`.
2026-06-15 22:58:44 +02:00
Marc-André Bombeck d3d8731209 refactor(settings): move notification channels into Integrationen
Channels (Telegram, ntfy, Web Push, Webhook, Email) and the live
per-channel status surface are delivery providers, not notification
preferences, so they now sit under Integrations next to the connected
services. Integrations gains a Connections / Channels sub-tab split;
Notifications keeps the reminder-type content (mood, low-stock, coach
nudge) and cross-links to the relocated channels.
2026-06-15 22:54:19 +02:00