diff --git a/docs/audit/v1415-summary.md b/docs/audit/v1415-summary.md index 1c177f9e1..fb5d187d2 100644 --- a/docs/audit/v1415-summary.md +++ b/docs/audit/v1415-summary.md @@ -62,51 +62,51 @@ Multi-Provider-AI-Abstraktion + `MockAIProvider`. ### Quick fixes (Phase A1–A5 + B-mobile) -| SHA | Summary | -| --------- | ---------------------------------------------------------------------------------- | -| `85aa15b` | fix(nav): hide bug-report entry in nav when admin disables the toggle | -| `786b395` | fix(a11y): skip-link no longer blocks logo click outside focus | -| `bde167d` | fix(feedback): hide user-facing feedback link when admin disables the feature | -| `c63e4de` | fix(feedback): gate ErrorDetails report-bug button on bugReportEnabled | +| SHA | Summary | +| --------- | ----------------------------------------------------------------------------------- | +| `85aa15b` | fix(nav): hide bug-report entry in nav when admin disables the toggle | +| `786b395` | fix(a11y): skip-link no longer blocks logo click outside focus | +| `bde167d` | fix(feedback): hide user-facing feedback link when admin disables the feature | +| `c63e4de` | fix(feedback): gate ErrorDetails report-bug button on bugReportEnabled | | `a967895` | feat(admin): replace overview section-grid with audit-log preview + system snapshot | -| `dddc18c` | fix(admin): make api-tokens table responsive on mobile | -| `3e45a7b` | fix(dashboard): disambiguate quick-add submenu labels | -| `2c227fb` | fix(dashboard): mood tile mobile shows number once + label | -| `bb4dc12` | fix(dashboard): no onboarding flicker on load; collapsed by default | -| `bffdccb` | feat(dashboard): medication compliance graph wired to layout toggle | -| `47ac14b` | feat(insights): mood chart auto-aggregates to weekly/monthly | -| `4e2386e` | feat(dashboard): 7-day-average → 7-day-trend with delta indicator per metric | -| `8ccdfac` | feat(dashboard): top tiles selectable in layout settings | -| `316c3b0` | fix(charts): chart wrappers allow vertical scroll passthrough on mobile | -| `41945b2` | fix(admin): /admin/users mobile layout — card-list at < md | -| `8370b2d` | fix(mobile): chart controls + medication buttons + mood list icons to 44px | -| `00f8cd5` | fix(settings): passkey list responsive — card view at < md | -| `c0b14f4` | fix(auth): bump login buttons to 44px tap-target on mobile | +| `dddc18c` | fix(admin): make api-tokens table responsive on mobile | +| `3e45a7b` | fix(dashboard): disambiguate quick-add submenu labels | +| `2c227fb` | fix(dashboard): mood tile mobile shows number once + label | +| `bb4dc12` | fix(dashboard): no onboarding flicker on load; collapsed by default | +| `bffdccb` | feat(dashboard): medication compliance graph wired to layout toggle | +| `47ac14b` | feat(insights): mood chart auto-aggregates to weekly/monthly | +| `4e2386e` | feat(dashboard): 7-day-average → 7-day-trend with delta indicator per metric | +| `8ccdfac` | feat(dashboard): top tiles selectable in layout settings | +| `316c3b0` | fix(charts): chart wrappers allow vertical scroll passthrough on mobile | +| `41945b2` | fix(admin): /admin/users mobile layout — card-list at < md | +| `8370b2d` | fix(mobile): chart controls + medication buttons + mood list icons to 44px | +| `00f8cd5` | fix(settings): passkey list responsive — card view at < md | +| `c0b14f4` | fix(auth): bump login buttons to 44px tap-target on mobile | ### Features (Phase B1–B6) -| SHA | Summary | -| --------- | ---------------------------------------------------------------------------------- | -| `fe85c2c` | feat(admin): restore from backup with full data replacement + triple-confirm | -| `d8c549e` | feat(admin): backup download as JSON | -| `30a74ed` | feat(admin): backup upload | -| `0805452` | fix(admin): backup audit log entries | -| `7c32d63` | feat(admin): link from backups view to docs.healthlog.dev/admin/backups | -| `4db72a8` | feat(integrations): connection-state + sync-error UI in Settings → Integrations | -| `b290a77` | fix(integrations): refresh-token failure marks integration as needing re-auth | -| `604dff0` | feat(integrations): admin Telegram alert on persistent sync failure (≥3) | -| `2fbf56d` | feat(audit): sync failures logged with structured meta | -| `87a40fd` | fix(notifications): auto-disable channels on persistent hard rejects (410, etc.) | -| `a3c0130` | feat(settings): notification channel status UI with re-enable + test | -| `34c967c` | feat(achievements): dedicated /achievements page with locked/unlocked list | -| `a242047` | feat(dashboard): recent achievements card with toggle in layout settings | -| `81f5019` | feat(dashboard): RecentAchievementsCard component + tests | -| `db5a49d` | feat(db): User.onboardingTourCompleted flag | -| `e57fc0a` | feat(onboarding): tour component with spotlight + keyboard navigation | -| `8215e25` | feat(onboarding): auto-launch tour for new users on first dashboard load | -| `fa1c6a6` | feat(settings): allow user to replay the onboarding tour | -| `d692119` | feat(doctor-report): configurable date range with default last-90-days | -| `28467b2` | feat(doctor-report): practice name on cover page (persisted as user preference) | +| SHA | Summary | +| --------- | -------------------------------------------------------------------------------- | +| `fe85c2c` | feat(admin): restore from backup with full data replacement + triple-confirm | +| `d8c549e` | feat(admin): backup download as JSON | +| `30a74ed` | feat(admin): backup upload | +| `0805452` | fix(admin): backup audit log entries | +| `7c32d63` | feat(admin): link from backups view to docs.healthlog.dev/admin/backups | +| `4db72a8` | feat(integrations): connection-state + sync-error UI in Settings → Integrations | +| `b290a77` | fix(integrations): refresh-token failure marks integration as needing re-auth | +| `604dff0` | feat(integrations): admin Telegram alert on persistent sync failure (≥3) | +| `2fbf56d` | feat(audit): sync failures logged with structured meta | +| `87a40fd` | fix(notifications): auto-disable channels on persistent hard rejects (410, etc.) | +| `a3c0130` | feat(settings): notification channel status UI with re-enable + test | +| `34c967c` | feat(achievements): dedicated /achievements page with locked/unlocked list | +| `a242047` | feat(dashboard): recent achievements card with toggle in layout settings | +| `81f5019` | feat(dashboard): RecentAchievementsCard component + tests | +| `db5a49d` | feat(db): User.onboardingTourCompleted flag | +| `e57fc0a` | feat(onboarding): tour component with spotlight + keyboard navigation | +| `8215e25` | feat(onboarding): auto-launch tour for new users on first dashboard load | +| `fa1c6a6` | feat(settings): allow user to replay the onboarding tour | +| `d692119` | feat(doctor-report): configurable date range with default last-90-days | +| `28467b2` | feat(doctor-report): practice name on cover page (persisted as user preference) | ### Hardening (Phase C1–C5) @@ -131,19 +131,19 @@ Multi-Provider-AI-Abstraktion + `MockAIProvider`. ### QA + Reconcile (Phase D) -| SHA | Summary | -| --------- | ------------------------------------------------------------------------ | -| `cd3b890` | refactor(v1.4.15): apply simplify-review safe suggestions | -| `6465412` | fix(a11y): trap focus + restore + ring on onboarding tour | -| `66d2e07` | fix(a11y): break long Withings error strings inside status banner | +| SHA | Summary | +| --------- | -------------------------------------------------------------------------- | +| `cd3b890` | refactor(v1.4.15): apply simplify-review safe suggestions | +| `6465412` | fix(a11y): trap focus + restore + ring on onboarding tour | +| `66d2e07` | fix(a11y): break long Withings error strings inside status banner | | `79bb167` | fix(ai): MockAIProvider DEFAULT_RESPONSE conforms to v1.4.15 strict schema | -| `d947563` | style(v1.4.15): prettier sweep on phase-D reconcile touched files | +| `d947563` | style(v1.4.15): prettier sweep on phase-D reconcile touched files | ### Release (Phase E1–E3) -| SHA | Summary | -| --------- | ---------------------------------------- | -| `4dcaa08` | chore(release): v1.4.15 | +| SHA | Summary | +| --------- | ----------------------- | +| `4dcaa08` | chore(release): v1.4.15 | --- @@ -206,7 +206,7 @@ fährt. ### Sonstige Process-Items -- Strict-Schema-Migration für AI-Insights-Route + UI (M6 senior); +- Strict-Schema-Migration für AI-Insights-Route + UI (M6 senior); `.passthrough()` retiren. - `dashboard-layout.test.ts` Typecheck-Regression aufräumen (in E1 bereits gefixt — bleibt aber als „pre-existing" in mehreren STATE- diff --git a/docs/audit/v1416-auto-deploy-fix.md b/docs/audit/v1416-auto-deploy-fix.md index 1528960e0..ff75620dd 100644 --- a/docs/audit/v1416-auto-deploy-fix.md +++ b/docs/audit/v1416-auto-deploy-fix.md @@ -30,12 +30,12 @@ We need: deploy fires only when the image digest actually changes. Coolify v4.0.0-beta.470 (current production) exposes these deploy-trigger toggles on a `dockercompose` application: -| Setting | Effect | API access | -| ---------------- | ----------------------------------------------------------------- | ------------------- | -| Auto Deploy | GitHub-App webhook listens to push events | UI only (no MCP / REST endpoint exposes it on v4-beta) | -| Watch Paths | Glob list — push-event paths must match for auto-deploy to fire | UI only | -| Deploy Webhook | Bearer-protected `GET /api/v1/deploy?uuid=…` — programmatic trigger | MCP-callable | -| Notification Webhook | Outgoing POST when deploy completes (success / failure) | UI only | +| Setting | Effect | API access | +| -------------------- | ------------------------------------------------------------------- | ------------------------------------------------------ | +| Auto Deploy | GitHub-App webhook listens to push events | UI only (no MCP / REST endpoint exposes it on v4-beta) | +| Watch Paths | Glob list — push-event paths must match for auto-deploy to fire | UI only | +| Deploy Webhook | Bearer-protected `GET /api/v1/deploy?uuid=…` — programmatic trigger | MCP-callable | +| Notification Webhook | Outgoing POST when deploy completes (success / failure) | UI only | The MCP `application.update` action exposed by `coolify-apps01` intentionally restricts mutations to the safe subset @@ -47,8 +47,7 @@ guardrails the MCP wraps around the install — too far outside agent scope. The Coolify community has an open feature request to expose -`auto_deploy_enabled` over REST; the v4-stable line (expected July -2026) is the realistic landing window. +`auto_deploy_enabled` over REST; the v4-stable line (expected July 2026) is the realistic landing window. ## Watchtower — re-examined diff --git a/docs/audit/v1416-settings-audit.md b/docs/audit/v1416-settings-audit.md index 7cafeab2e..c5af60f1f 100644 --- a/docs/audit/v1416-settings-audit.md +++ b/docs/audit/v1416-settings-audit.md @@ -21,18 +21,18 @@ B2 owns AI provider UX, B7 just shipped Export. ## 1. Inventory -| Slug | Route | Section component | Sidebar icon | i18n title key | i18n description key | -| ----------------- | ------------------------------------------- | -------------------------------------------------------- | --------------------- | ----------------------------------------- | ----------------------------------------------- | -| `account` | `/settings/account` | `account-section.tsx` (``) | `User` | `settings.sections.account.title` | `settings.sections.account.description` | -| `integrations` | `/settings/integrations` | `integrations-section.tsx` (``) | `Link2` | `settings.sections.integrations.title` | `settings.sections.integrations.description` | -| `notifications` | `/settings/notifications` | `notifications-section.tsx` (``) | `Bell` | `settings.sections.notifications.title` | `settings.sections.notifications.description` | -| `dashboard` | `/settings/dashboard` | `dashboard-section.tsx` (``) ⇢ `dashboard-layout-section.tsx` | `LayoutDashboard` | `settings.sections.dashboard.title` | `settings.sections.dashboard.description` | -| `thresholds` | `/settings/thresholds` | `thresholds-settings-section.tsx` (``) ⇢ `thresholds-section.tsx` | `SlidersHorizontal` | `settings.sections.thresholds.title` | `settings.sections.thresholds.description` | -| `ai` (out of scope) | `/settings/ai` | `ai-section.tsx` (``) | `Sparkles` | `settings.sections.ai.title` | `settings.sections.ai.description` | -| `api` | `/settings/api` | `api-section.tsx` (``) | `KeyRound` | `settings.sections.api.title` | `settings.sections.api.description` | -| `export` (out of scope) | `/settings/export` | `export-section.tsx` (``) | `Download` | `settings.sections.export.title` | `settings.sections.export.description` | -| `advanced` | `/settings/advanced` | `advanced-section.tsx` (``) | `Settings2` | `settings.sections.advanced.title` | `settings.sections.advanced.description` | -| `about` | `/settings/about` | `about-section.tsx` (``) | `Info` | `settings.sections.about.title` | `settings.sections.about.description` | +| Slug | Route | Section component | Sidebar icon | i18n title key | i18n description key | +| ----------------------- | ------------------------- | -------------------------------------------------------------------------------------------- | ------------------- | --------------------------------------- | --------------------------------------------- | +| `account` | `/settings/account` | `account-section.tsx` (``) | `User` | `settings.sections.account.title` | `settings.sections.account.description` | +| `integrations` | `/settings/integrations` | `integrations-section.tsx` (``) | `Link2` | `settings.sections.integrations.title` | `settings.sections.integrations.description` | +| `notifications` | `/settings/notifications` | `notifications-section.tsx` (``) | `Bell` | `settings.sections.notifications.title` | `settings.sections.notifications.description` | +| `dashboard` | `/settings/dashboard` | `dashboard-section.tsx` (``) ⇢ `dashboard-layout-section.tsx` | `LayoutDashboard` | `settings.sections.dashboard.title` | `settings.sections.dashboard.description` | +| `thresholds` | `/settings/thresholds` | `thresholds-settings-section.tsx` (``) ⇢ `thresholds-section.tsx` | `SlidersHorizontal` | `settings.sections.thresholds.title` | `settings.sections.thresholds.description` | +| `ai` (out of scope) | `/settings/ai` | `ai-section.tsx` (``) | `Sparkles` | `settings.sections.ai.title` | `settings.sections.ai.description` | +| `api` | `/settings/api` | `api-section.tsx` (``) | `KeyRound` | `settings.sections.api.title` | `settings.sections.api.description` | +| `export` (out of scope) | `/settings/export` | `export-section.tsx` (``) | `Download` | `settings.sections.export.title` | `settings.sections.export.description` | +| `advanced` | `/settings/advanced` | `advanced-section.tsx` (``) | `Settings2` | `settings.sections.advanced.title` | `settings.sections.advanced.description` | +| `about` | `/settings/about` | `about-section.tsx` (``) | `Info` | `settings.sections.about.title` | `settings.sections.about.description` | The slug list lives at `src/components/settings/section-slugs.ts` (server-safe constant) and is mirrored by the icon/title list at the top of @@ -60,18 +60,18 @@ The `settings.*` namespace inside `messages/{en,de}.json` mixes three styles: ### 2.1 Section-component naming drift -| Component file | Default export | Comment | -| -------------------------------------- | --------------------------- | ---------------------------------------------------------------------------------------------------- | -| `account-section.tsx` | `AccountSection` | OK — slug + `-section.tsx` + `` | -| `integrations-section.tsx` | `IntegrationsSection` | OK | -| `notifications-section.tsx` | `NotificationsSection` | OK | -| `dashboard-section.tsx` | `DashboardSection` | OK — but ALSO has `dashboard-layout-section.tsx` (``) as the inner card. | -| `thresholds-settings-section.tsx` | `ThresholdsSettingsSection` | **Drift** — the slug is `thresholds`, the file is `thresholds-settings-section.tsx`, AND the inner card lives at `thresholds-section.tsx` (``). The "settings" infix is redundant (everything in `src/components/settings/` is already a settings component). | -| `ai-section.tsx` | `AiSection` | OK (out of scope) | -| `api-section.tsx` | `ApiSection` | OK | -| `export-section.tsx` | `ExportSection` | OK (out of scope) | -| `advanced-section.tsx` | `AdvancedSection` | OK | -| `about-section.tsx` | `AboutSection` | OK | +| Component file | Default export | Comment | +| --------------------------------- | --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `account-section.tsx` | `AccountSection` | OK — slug + `-section.tsx` + `` | +| `integrations-section.tsx` | `IntegrationsSection` | OK | +| `notifications-section.tsx` | `NotificationsSection` | OK | +| `dashboard-section.tsx` | `DashboardSection` | OK — but ALSO has `dashboard-layout-section.tsx` (``) as the inner card. | +| `thresholds-settings-section.tsx` | `ThresholdsSettingsSection` | **Drift** — the slug is `thresholds`, the file is `thresholds-settings-section.tsx`, AND the inner card lives at `thresholds-section.tsx` (``). The "settings" infix is redundant (everything in `src/components/settings/` is already a settings component). | +| `ai-section.tsx` | `AiSection` | OK (out of scope) | +| `api-section.tsx` | `ApiSection` | OK | +| `export-section.tsx` | `ExportSection` | OK (out of scope) | +| `advanced-section.tsx` | `AdvancedSection` | OK | +| `about-section.tsx` | `AboutSection` | OK | **Decision (refactor commit 2):** the route-level wrapper is named after the slug (``), the inner card keeps its own descriptive name @@ -92,19 +92,20 @@ The historic flat namespace (`settings.profile`, `settings.passkeyName`, …) predates the section split. Result: the same concept is reachable under two different keys. -| Concept | Modern key | Legacy key still in code | -| ---------------------- | -------------------------------------------------------------- | ------------------------------------------------------ | -| Account page title | `settings.sections.account.title` | `settings.profile` *(card heading inside the page)* | -| AI page title | `settings.sections.ai.title` (= `settings.ai.title`) | `settings.kiInsights` (card heading) — duplicate | -| Withings card title | (none — only flat key) | `settings.withings` | -| Token actions | (none) | `settings.tokenRevoke`, `settings.tokenRevoked`, … | -| Doctor report | `settings.sections.export.cards.doctorReport.title` | `settings.doctorReport` (legacy) | -| Audit log | (none) | `settings.auditLog`, `settings.auditAction`, … | -| Danger zone | (none) | `settings.dangerZone`, `settings.dangerZoneTitle`, … | -| moodLog card title | (none) | `settings.moodLogTitle` | -| Notifications channels | (none) | `settings.telegram`, `settings.ntfy`, `settings.webPush` | +| Concept | Modern key | Legacy key still in code | +| ---------------------- | ---------------------------------------------------- | -------------------------------------------------------- | +| Account page title | `settings.sections.account.title` | `settings.profile` _(card heading inside the page)_ | +| AI page title | `settings.sections.ai.title` (= `settings.ai.title`) | `settings.kiInsights` (card heading) — duplicate | +| Withings card title | (none — only flat key) | `settings.withings` | +| Token actions | (none) | `settings.tokenRevoke`, `settings.tokenRevoked`, … | +| Doctor report | `settings.sections.export.cards.doctorReport.title` | `settings.doctorReport` (legacy) | +| Audit log | (none) | `settings.auditLog`, `settings.auditAction`, … | +| Danger zone | (none) | `settings.dangerZone`, `settings.dangerZoneTitle`, … | +| moodLog card title | (none) | `settings.moodLogTitle` | +| Notifications channels | (none) | `settings.telegram`, `settings.ntfy`, `settings.webPush` | **Decision (refactor commit 2):** + - Keep `settings.sections..{title,description}` as the canonical source for `

` + subtitle. No change needed. - Introduce `settings.sections..cards..title` / @@ -117,18 +118,18 @@ different keys. ### 2.3 Anti-pattern: section title vs sidebar label vs document `` -| Slug | Sidebar label (DE) | Page `<h1>` (DE) | Browser `<title>` | Match? | -| ------------- | --------------------- | ----------------------- | ---------------------------- | ------ | -| account | "Konto" | "Konto" | (Next.js inherits root) | yes | -| integrations | "Integrationen" | "Integrationen" | " | yes | -| notifications | "Benachrichtigungen" | "Benachrichtigungen" | " | yes | -| dashboard | "Dashboard" | "Dashboard" | " | yes | -| thresholds | "Persönliche Zielwerte" | "Persönliche Zielwerte" | " | yes | -| ai | "KI-Auswertungen" | "KI-Insights" (legacy `settings.ai.title` = "KI-Insights") | " | **mismatch** — sidebar says "Auswertungen", page heading says "Insights" | -| api | "API & Tokens" | "API & Tokens" | " | yes | -| export | "Export" | "Export" | " | yes | -| advanced | "Erweitert" | "Erweitert" | " | yes | -| about | "Über" | "Über" | " | yes | +| Slug | Sidebar label (DE) | Page `<h1>` (DE) | Browser `<title>` | Match? | +| ------------- | ----------------------- | ---------------------------------------------------------- | ----------------------- | ------------------------------------------------------------------------ | +| account | "Konto" | "Konto" | (Next.js inherits root) | yes | +| integrations | "Integrationen" | "Integrationen" | " | yes | +| notifications | "Benachrichtigungen" | "Benachrichtigungen" | " | yes | +| dashboard | "Dashboard" | "Dashboard" | " | yes | +| thresholds | "Persönliche Zielwerte" | "Persönliche Zielwerte" | " | yes | +| ai | "KI-Auswertungen" | "KI-Insights" (legacy `settings.ai.title` = "KI-Insights") | " | **mismatch** — sidebar says "Auswertungen", page heading says "Insights" | +| api | "API & Tokens" | "API & Tokens" | " | yes | +| export | "Export" | "Export" | " | yes | +| advanced | "Erweitert" | "Erweitert" | " | yes | +| about | "Über" | "Über" | " | yes | The AI mismatch is **out of B6 scope** — B2 owns the AI section. Flagged for B2. @@ -143,18 +144,18 @@ Per Marc's `feedback_settings_no_split.md`, there must be no instance where a single concept is selected at the top of a section and configured at the bottom. Audit: -| Section | Top-bottom split? | Notes | -| ------------------ | ----------------- | ------------------------------------------------------------------------------------ | -| Account | No | One profile card, one passkey card, one password card, one tour card. Sequential, not split. | -| Integrations | No | Withings + moodLog cards, each self-contained. | -| Notifications | **Borderline** | `<NotificationStatusCard>` lists per-channel status at the top; the per-channel config cards (`<TelegramCard>`, `<NtfyCard>`, `<WebPushCard>`) follow below. The status card has `Re-enable` + `Send test` actions per channel that arguably duplicate functionality in the config cards. **Not a top/bottom-split-of-one-concept** — the status card is a read-only summary, the config cards are mutators. Keeping it. | -| Dashboard | No | One layout card. | -| Thresholds | No | One editor card with per-metric rows. | -| AI | **YES (out of scope, B2)** | Provider dropdown at the top selects between OpenAI/Anthropic/Local; key/credential inputs for each provider live further down. This is the case Marc named explicitly. | -| API | No | Endpoints reference card + tokens card. | -| Export | No | 5 cards, each self-contained. | -| Advanced | No | Single danger-zone card (post-B7 cleanup). | -| About | No | Identity + sources + updates cards. | +| Section | Top-bottom split? | Notes | +| ------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Account | No | One profile card, one passkey card, one password card, one tour card. Sequential, not split. | +| Integrations | No | Withings + moodLog cards, each self-contained. | +| Notifications | **Borderline** | `<NotificationStatusCard>` lists per-channel status at the top; the per-channel config cards (`<TelegramCard>`, `<NtfyCard>`, `<WebPushCard>`) follow below. The status card has `Re-enable` + `Send test` actions per channel that arguably duplicate functionality in the config cards. **Not a top/bottom-split-of-one-concept** — the status card is a read-only summary, the config cards are mutators. Keeping it. | +| Dashboard | No | One layout card. | +| Thresholds | No | One editor card with per-metric rows. | +| AI | **YES (out of scope, B2)** | Provider dropdown at the top selects between OpenAI/Anthropic/Local; key/credential inputs for each provider live further down. This is the case Marc named explicitly. | +| API | No | Endpoints reference card + tokens card. | +| Export | No | 5 cards, each self-contained. | +| Advanced | No | Single danger-zone card (post-B7 cleanup). | +| About | No | Identity + sources + updates cards. | **Decision:** AI flagged for B2 (already in roadmap). All other sections are clean. Notifications kept as-is — the read-only-status-then-mutator @@ -162,14 +163,14 @@ pattern is a deliberate choice, not a split anti-pattern. ### 2.5 Duplicate functionality between sections -| Concept | Owner section | Duplicated where? | Action | -| ----------------------- | ---------------------- | ------------------------------------------------------------------------------ | --------------------------------------- | -| Doctor-report PDF | Export (canonical) | Used to live in Advanced as `<ExportCard>`. **Already removed in B7.** | None. | -| CSV/JSON export buttons | Export (canonical) | Used to live in Advanced. **Already removed in B7.** | None. | -| Language selector | Account ⇢ profile card | NONE. | OK. | -| Channel test send | Notifications ⇢ status card | Each individual channel card (`<TelegramCard>`, etc.) ALSO has a test-send button. | Document — not removing; the status card surfaces it for failed channels (after auto-disable), the config cards have it as a "did I get the credentials right" smoke test. Different intents. | -| Withings credentials | Integrations ⇢ Withings card | NONE. | OK. | -| User-level settings vs admin-level settings | mostly disjoint | `settings.adminAreaTitle` / `settings.openAdminConsole` exist as keys but are **not currently rendered anywhere** in any settings section component. Stale. | Mark `settings.adminAreaTitle` etc. as deprecated in JSON. | +| Concept | Owner section | Duplicated where? | Action | +| ------------------------------------------- | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Doctor-report PDF | Export (canonical) | Used to live in Advanced as `<ExportCard>`. **Already removed in B7.** | None. | +| CSV/JSON export buttons | Export (canonical) | Used to live in Advanced. **Already removed in B7.** | None. | +| Language selector | Account ⇢ profile card | NONE. | OK. | +| Channel test send | Notifications ⇢ status card | Each individual channel card (`<TelegramCard>`, etc.) ALSO has a test-send button. | Document — not removing; the status card surfaces it for failed channels (after auto-disable), the config cards have it as a "did I get the credentials right" smoke test. Different intents. | +| Withings credentials | Integrations ⇢ Withings card | NONE. | OK. | +| User-level settings vs admin-level settings | mostly disjoint | `settings.adminAreaTitle` / `settings.openAdminConsole` exist as keys but are **not currently rendered anywhere** in any settings section component. Stale. | Mark `settings.adminAreaTitle` etc. as deprecated in JSON. | ### 2.6 Settings vs Admin: scope rule @@ -196,14 +197,14 @@ in the user settings page that never shipped. **Marking deprecated.** The following toggles or behaviours exist in the data layer but have no end-user-visible setting today: -| Feature | Where it lives | Should it have a setting? | -| ---------------------------------------- | --------------------------------------- | -------------------------------------------- | -| Onboarding-tour replay | already shipped in `<AccountSection>` (v1.4.15 B5) | already done | -| Achievements opt-out | server-side `<UserAchievement>` table | low priority — defer | -| AI raw-data toggle (`rawData`) | already in `<AiSection>` (out of scope) | already done | -| Personal medical-references override | server-side `users.medicalReferences` | defer (B5a referenced this — not yet user-tunable) | -| Per-metric reminder schedule | `Medication.schedule` | covered by medication editor, not settings | -| Locale fallback ("auto-detect off") | `i18n/config.ts` | low priority — defer | +| Feature | Where it lives | Should it have a setting? | +| ------------------------------------ | -------------------------------------------------- | -------------------------------------------------- | +| Onboarding-tour replay | already shipped in `<AccountSection>` (v1.4.15 B5) | already done | +| Achievements opt-out | server-side `<UserAchievement>` table | low priority — defer | +| AI raw-data toggle (`rawData`) | already in `<AiSection>` (out of scope) | already done | +| Personal medical-references override | server-side `users.medicalReferences` | defer (B5a referenced this — not yet user-tunable) | +| Per-metric reminder schedule | `Medication.schedule` | covered by medication editor, not settings | +| Locale fallback ("auto-detect off") | `i18n/config.ts` | low priority — defer | Nothing is shipped-without-UI that should be exposed in B6. The "deferred" items belong in v1.5 product roadmap, not this audit. @@ -231,23 +232,23 @@ Spot-checked: Marc asked: "are settings grouped sensibly?". Current order in the sidebar: -1. Account — personal identity + sign-in -2. Integrations — third-party data sources -3. Notifications — per-channel delivery -4. Dashboard — UI layout -5. Thresholds — target ranges (used by charts + insights) -6. AI — analysis provider -7. API — bearer tokens for headless clients -8. Export — data out -9. Advanced — danger zone -10. About — version + links +1. Account — personal identity + sign-in +2. Integrations — third-party data sources +3. Notifications — per-channel delivery +4. Dashboard — UI layout +5. Thresholds — target ranges (used by charts + insights) +6. AI — analysis provider +7. API — bearer tokens for headless clients +8. Export — data out +9. Advanced — danger zone +10. About — version + links This order roughly reads as: **identity → data flow in → output configuration → automation → data flow out → housekeeping → meta**. Defensible. No re-order required. One concept worth highlighting: **Thresholds + Dashboard are both UI -configuration**, but Thresholds also drives *insight* + *AI* outputs. +configuration**, but Thresholds also drives _insight_ + _AI_ outputs. Putting Thresholds between Dashboard and AI keeps it close to both concerns. Leaving as-is. @@ -258,6 +259,7 @@ concerns. Leaving as-is. Commit 1 (this commit) — `docs(audit): v1.4.16 settings naming + consolidation audit` Commit 2 — `refactor(settings): consistent naming + i18n key namespace` + - Rename `thresholds-settings-section.tsx` → `thresholds-section.tsx` (route-level wrapper). - Rename existing inner card from `thresholds-section.tsx` → @@ -277,6 +279,7 @@ Commit 2 — `refactor(settings): consistent naming + i18n key namespace` until a follow-up hygiene PR. Commit 3 — `refactor(settings): remove duplicate toggles, route to canonical owner` + - Document the settings-vs-admin scope rule in `CLAUDE.md`. - No actual duplicate found that needs removing today; commit body documents the audit conclusion ("no duplicate user-facing toggles @@ -285,6 +288,7 @@ Commit 3 — `refactor(settings): remove duplicate toggles, route to canonical o deprecated"). Commit 4 — `test(settings): coverage for renamed/consolidated sections` + - Update `src/components/settings/__tests__/sections.test.tsx` to import the renamed thresholds component and assert the new file layout. diff --git a/docs/audit/v1416-summary.md b/docs/audit/v1416-summary.md index e94589a7c..1aa94e0f9 100644 --- a/docs/audit/v1416-summary.md +++ b/docs/audit/v1416-summary.md @@ -58,51 +58,51 @@ How It Works, Comparison Views, Provider Configuration. ### Wave A — Quick fixes -| Bucket | Commit | Subject | -| ------ | ------- | ------------------------------------------------------------------------------------------------------ | -| A1 | `77fe256` | fix(nav): admin sub-items don't expand from gravatar dropdown or admin-link click | -| A2 | `577d8dd` | fix(insights): BD-Zielbereich computes correctly for real measurement data | -| A3 | `277a5aa` | fix(admin): api-tokens table no horizontal overflow on Pixel-5 viewport | -| A4 | `4df6dac` | feat(charts): "7-Tage-Trend" rename + slope30 fallback for sparse metrics | -| A5 | `93e712d` | fix(dashboard): top-tile selector persists (widget-id enum drift fixed) | -| A6 | `9b01c86` | feat(charts): medication chart matches other charts (7d trend + indicator + target-range) | +| Bucket | Commit | Subject | +| ------ | ------------------ | ------------------------------------------------------------------------------------------ | +| A1 | `77fe256` | fix(nav): admin sub-items don't expand from gravatar dropdown or admin-link click | +| A2 | `577d8dd` | fix(insights): BD-Zielbereich computes correctly for real measurement data | +| A3 | `277a5aa` | fix(admin): api-tokens table no horizontal overflow on Pixel-5 viewport | +| A4 | `4df6dac` | feat(charts): "7-Tage-Trend" rename + slope30 fallback for sparse metrics | +| A5 | `93e712d` | fix(dashboard): top-tile selector persists (widget-id enum drift fixed) | +| A6 | `9b01c86` | feat(charts): medication chart matches other charts (7d trend + indicator + target-range) | | A7 | (within `9b01c86`) | feat(insights): rate-limit 10/h + cache-evict on regenerate (cross-agent race captured A7) | -| A8a | `2da0703` | fix(geo): preserve umlauts in city names (login-overview no longer renders "Nrnberg") | -| A8b | `af77e5e` | feat(charts): split-half mean delta on long-window trend | +| A8a | `2da0703` | fix(geo): preserve umlauts in city names (login-overview no longer renders "Nrnberg") | +| A8b | `af77e5e` | feat(charts): split-half mean delta on long-window trend | ### Wave B — Quality-leap features -| Bucket | Headline commits | What it does | -| ------ | --------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | -| B1a | `74c2eb8`, `901f44e`, `8008613`, `2611bb4` | BP / weight / pulse / mood / medication chart polish | -| B1b | `4d7d074`, `9e8be4b`, `b76351e`, `0c287f1`, `d2cdf9d`, `5063ad7`, `3b0d21e` | `/insights` hero + recs grid + dashboard preview | -| B2 | (worktree `agent/b2-ai-provider-ux` ff) | Single-pulldown Settings → AI + chain editor | -| B3 | `5d1ece1`, `f1bd801`, `2877710`, (chart inside `8d9f864`) | Admin host-load chart (in-process sampler, 7d) | -| B4 | (audit-log inside `8ac5602`), `4cc3d8d`, `6520ae4` | Admin audit-log filter + CSV + app-log preview | -| B5a | `27f3933`, `466b8b5`, `7fbfca6`, `53aade9`, `a66c128` | Curated medical-reference bundle + citation footnote | -| B5b | `2611bb4` (column), runner inside `901f44e`, `613d661`, `d2bda42` | Multi-provider fallback chain + last-working cache | -| B5c | `8a438a0`, `c39a527`, `13f1ae5`, `c8b30c1`, `7f54c0c`, `680f84c`, `10a67ff`, `fed2e7e` | Per-rec rationale (window / comparedTo / deviation) | -| B5d | `0cb0373`, `af21d4d`, `7ec1030`, `63cfd8e`, `d343ab5`, `173c3e1` | Deterministic confidence meter (server-overrides) | -| B5e | `badc893`, `8255e3e`, `ca84fb7`, `47ca1e4`, `71ffe30`, `8879282` | RecommendationFeedback + daily aggregator + admin | -| B6 | `01a05e4`, `a432cb2`, `ed0cfda`, `d914f76` | Settings naming audit + i18n parity guard | -| B7 | `621109c`, `a512650`, `94c748d`, (routes inside `226cac4`), `d5c8912`, `830b2b0`, `e628f33` | Settings → Export consolidation | -| B8 | `775df8c`, `2cf7b74`, `e4a408e`, `f9f99ea` | Comparison overlay on charts + tiles + AI narration | +| Bucket | Headline commits | What it does | +| ------ | ------------------------------------------------------------------------------------------- | ---------------------------------------------------- | +| B1a | `74c2eb8`, `901f44e`, `8008613`, `2611bb4` | BP / weight / pulse / mood / medication chart polish | +| B1b | `4d7d074`, `9e8be4b`, `b76351e`, `0c287f1`, `d2cdf9d`, `5063ad7`, `3b0d21e` | `/insights` hero + recs grid + dashboard preview | +| B2 | (worktree `agent/b2-ai-provider-ux` ff) | Single-pulldown Settings → AI + chain editor | +| B3 | `5d1ece1`, `f1bd801`, `2877710`, (chart inside `8d9f864`) | Admin host-load chart (in-process sampler, 7d) | +| B4 | (audit-log inside `8ac5602`), `4cc3d8d`, `6520ae4` | Admin audit-log filter + CSV + app-log preview | +| B5a | `27f3933`, `466b8b5`, `7fbfca6`, `53aade9`, `a66c128` | Curated medical-reference bundle + citation footnote | +| B5b | `2611bb4` (column), runner inside `901f44e`, `613d661`, `d2bda42` | Multi-provider fallback chain + last-working cache | +| B5c | `8a438a0`, `c39a527`, `13f1ae5`, `c8b30c1`, `7f54c0c`, `680f84c`, `10a67ff`, `fed2e7e` | Per-rec rationale (window / comparedTo / deviation) | +| B5d | `0cb0373`, `af21d4d`, `7ec1030`, `63cfd8e`, `d343ab5`, `173c3e1` | Deterministic confidence meter (server-overrides) | +| B5e | `badc893`, `8255e3e`, `ca84fb7`, `47ca1e4`, `71ffe30`, `8879282` | RecommendationFeedback + daily aggregator + admin | +| B6 | `01a05e4`, `a432cb2`, `ed0cfda`, `d914f76` | Settings naming audit + i18n parity guard | +| B7 | `621109c`, `a512650`, `94c748d`, (routes inside `226cac4`), `d5c8912`, `830b2b0`, `e628f33` | Settings → Export consolidation | +| B8 | `775df8c`, `2cf7b74`, `e4a408e`, `f9f99ea` | Comparison overlay on charts + tiles + AI narration | ### Wave C — Catch-up (deferred from v1.4.15) -| Item | Commit | Notes | -| ------------------------------------- | --------- | ---------------------------------------------------------------- | -| CI fix (encryption-key + tour-overlay) | `fbcd106` | Both pre-existing red since `d8c549e`; both green from here on | -| H1 admin restore-failed scrub | `fdac9e2` | code-review HIGH | -| H2 moodEntry.tags JSON-array refine | `7f1a4de` | code-review HIGH | -| H4 tour-launcher per-user sessionKey | `2afe3c4` | code-review HIGH | -| H4 design 44 px tap targets sweep | `b863e2c` | tour / backups / notifications | -| i18n parity Quelle / Leitlinie | `2a7ef72` | B5a follow-on | -| MED tabs horizontal scroll | `d7c2b2a` | | -| MED bottom-nav 5+More | `072eee6` | overflow sheet | -| MED system-status retry button | `65b4bf9` | | -| Auto-deploy v1.5 doc | `4be6465` | Coolify auto-deploy stays on git-push for v1.4.16; deferred | -| docker-publish drop qemu-arm64 | `cc0f343` | qemu-SIGILL root cause; native-runner matrix in v1.5 | +| Item | Commit | Notes | +| -------------------------------------- | --------- | -------------------------------------------------------------- | +| CI fix (encryption-key + tour-overlay) | `fbcd106` | Both pre-existing red since `d8c549e`; both green from here on | +| H1 admin restore-failed scrub | `fdac9e2` | code-review HIGH | +| H2 moodEntry.tags JSON-array refine | `7f1a4de` | code-review HIGH | +| H4 tour-launcher per-user sessionKey | `2afe3c4` | code-review HIGH | +| H4 design 44 px tap targets sweep | `b863e2c` | tour / backups / notifications | +| i18n parity Quelle / Leitlinie | `2a7ef72` | B5a follow-on | +| MED tabs horizontal scroll | `d7c2b2a` | | +| MED bottom-nav 5+More | `072eee6` | overflow sheet | +| MED system-status retry button | `65b4bf9` | | +| Auto-deploy v1.5 doc | `4be6465` | Coolify auto-deploy stays on git-push for v1.4.16; deferred | +| docker-publish drop qemu-arm64 | `cc0f343` | qemu-SIGILL root cause; native-runner matrix in v1.5 | 5 of 8 deferred HIGH from v1.4.15 Wave-D landed; 3 of 5 deferred MED from A5 mobile landed; Coolify image-digest auto-deploy deferred per @@ -124,20 +124,20 @@ Marc's "leave it" call. ### Wave E — Release -| Item | Result | -| ------------------------------------------- | ----------------------------------------------------- | -| Pre-release verify | `pnpm typecheck` clean; `pnpm test` 1540/1540; integration 59/59 | -| Release commit | `d443c22 chore(release): v1.4.16` | -| Tag | `v1.4.16` (annotated) | -| GHCR — tag run | `25616783583` success, digest `2f1a0d6b381d…` | -| GHCR — main run | `25616782255` success, digest `4841bef396ad…` | -| Coolify auto-deploy | NO — same race as v1.4.14/v1.4.15; retag-on-host fallback used | -| Live image digest | `sha256:05f8a126d63962d9a4af4769de830d3fee022d634787e811b4339ee464420daa` | -| `/api/version` transition | `1.4.15` → `1.4.16` at `2026-05-10T03:45:58+02:00` | -| Smoke (14 routes, Marc's session) | 13/14 200; `/dashboard` 404 expected (root is dashboard) | -| GH release | https://github.com/MBombeck/HealthLog/releases/tag/v1.4.16 | -| Docs site | `8addef4` + `2a5802b` on `healthlog-docs/main` (44 pages, three new deep-dive pages) | -| Landing site | `3d17207` on `healthlog-landing/main` (1.4.15 → 1.4.16, AI cards updated) | +| Item | Result | +| --------------------------------- | ------------------------------------------------------------------------------------ | +| Pre-release verify | `pnpm typecheck` clean; `pnpm test` 1540/1540; integration 59/59 | +| Release commit | `d443c22 chore(release): v1.4.16` | +| Tag | `v1.4.16` (annotated) | +| GHCR — tag run | `25616783583` success, digest `2f1a0d6b381d…` | +| GHCR — main run | `25616782255` success, digest `4841bef396ad…` | +| Coolify auto-deploy | NO — same race as v1.4.14/v1.4.15; retag-on-host fallback used | +| Live image digest | `sha256:05f8a126d63962d9a4af4769de830d3fee022d634787e811b4339ee464420daa` | +| `/api/version` transition | `1.4.15` → `1.4.16` at `2026-05-10T03:45:58+02:00` | +| Smoke (14 routes, Marc's session) | 13/14 200; `/dashboard` 404 expected (root is dashboard) | +| GH release | https://github.com/MBombeck/HealthLog/releases/tag/v1.4.16 | +| Docs site | `8addef4` + `2a5802b` on `healthlog-docs/main` (44 pages, three new deep-dive pages) | +| Landing site | `3d17207` on `healthlog-landing/main` (1.4.15 → 1.4.16, AI cards updated) | --- @@ -212,7 +212,7 @@ Full backlog: `.planning/v15-backlog.md`. Highlights: first time since v1.4.13). Coolify auto-deploy fired on the `chore(release)` commit before GHCR finished and pulled the host's stale local `:latest` cache; retag-on-host fallback (`docker pull - :1.4.16 && docker tag :1.4.16 :latest && docker compose up -d app`) +:1.4.16 && docker tag :1.4.16 :latest && docker compose up -d app`) flipped `/api/version` 1 s after the up command returned. - **Coolify auto-deploy**: still fires on every git-push (deferred per Marc's call); v1.5 plan in `docs/audit/v1416-auto-deploy-fix.md`. @@ -236,7 +236,7 @@ Full backlog: `.planning/v15-backlog.md`. Highlights: - `/settings/ai-providers/` — setup paths for all five providers, fallback-chain editor, test-connection, credential storage table. - **healthlog-landing** (Next.js) — `softwareVersion 1.4.15 → - 1.4.16` in JSON-LD; AI-insights hero card rewritten as "AI insights +1.4.16` in JSON-LD; AI-insights hero card rewritten as "AI insights that show their work" leading with explainability + confidence + citations; capability badges row picks up two new badges.