Commit Graph
5 Commits
Author SHA1 Message Date
Marc-André Bombeck b68206eca4 feat(settings): add 6 assistant-surface feature flags to AppSettings
Operator-side kill matrix for every LLM-driven surface. Master flag
`assistantEnabled` plus five sub-flags carve the seven surfaces:
Coach + chat, Daily Briefing + advisor, per-metric status cards,
correlation narration, Health-Score delta explainer. Defaults are
`true` so existing installs upgrade without losing affordances.

New `src/lib/feature-flags/` module exposes `getAssistantFlags()`,
`resolveAssistantFlags()` and the `AssistantDisabledError` typed
error route handlers throw to surface the 403 +
`errorCode: "assistant.disabled.<surface>"` envelope. The resolver
forces every sub-flag false when the master is off so callers never
have to compose `master && sub`.

Locks per `.planning/RESPONSE-TO-IOS-TEAM-2026-05-16.md` §3 R5:
the same matrix gates server-routed AND iOS on-device surfaces.

Migration 0065 is additive only; `app_settings` gains six boolean
columns, all default `true`, idempotent under `IF NOT EXISTS`.
2026-05-16 13:38:49 +02:00
Marc-André Bombeck 26568c18a8 feat(admin): server-default timezone setting for new signups
v1.4.25 W7 phase 5 — proposal §5 admin half.

GET /api/admin/settings now returns defaultUserTimezone (null = use
Europe/Berlin fallback). PUT accepts the field:
  - empty string clears the column (resolver falls back)
  - non-empty must pass isValidTimezone(); otherwise 422
  - successful writes invalidate the server-default resolver cache
    so the registration handler sees the new value on the next
    signup without waiting 60s for the TTL

The admin form gets a third row in the General Settings section
between 'default language' and the toggles, mirroring the user
picker UX (native select over Intl.supportedValuesOf, fallback
'Europe/Berlin (default)' option clears the override). 3 new i18n
keys per locale (defaultUserTimezone +
defaultUserTimezoneDescription + defaultUserTimezoneFallback);
descriptions follow proposal §5: 'Used for new accounts that don't
carry a browser-detected zone. Does not affect existing users.'

Tests: 3 new cases in src/app/api/admin/settings/__tests__/route.test.ts
covering valid IANA write, empty-string clear, and invalid-zone
rejection.
2026-05-14 12:05:46 +02:00
Marc-André BombeckandClaude Opus 4.7 d438a8520d feat(admin): bug-report toggle, unify "Trennen" button styling
Bucket E+F of the v1.4.3 polish pass.

**Disconnect-button styling unified.** Three integrations had three
different "Trennen" buttons: Withings used `outline` + `text-
destructive`; moodLog used solid `destructive` (red bg, white text);
the AI/Codex card used `ghost` + `text-destructive`. Same action,
three readings — confusing. All three now use the Withings pattern
(`outline` + `text-destructive`). The actual confirmation button
inside the AlertDialog keeps its solid-red treatment so the final
"yes, do it" still reads as a strong commit.

**Bug-report explicit on/off toggle.** Until v1.4.3 the bug-report
feature was implicitly gated on "is the GitHub token + repo
configured". An admin who wanted to *temporarily* hide the report
button (e.g. during a freeze window) had to clear the encrypted
token, forcing re-entry on resume — destructive for a reversible
intent. Migration `0027_bug_report_enabled_toggle` adds
`app_settings.bug_report_enabled BOOLEAN NOT NULL DEFAULT TRUE`,
the admin settings schema accepts `bugReportEnabled`, and a Switch
in the admin → Bug Report card lets the operator flip it.
`POST /api/bugreport` now returns 503 ("Bug reports are disabled by
the administrator") when the flag is off — the client already
renders a "not configured" screen on that status, so the report
button hides gracefully without further client-side wiring.

i18n keys added: `admin.bugReportEnabledLabel` + `…Description` in
both DE and EN.

Tests + typecheck green (671/671).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 21:45:18 +02:00
Marc-André BombeckandMarc-André Bombeck a6524721da fix(i18n): localise medication reminders and dashboard streak per user (#124)
Closes the v3 audit "Locale Mixing" CRIT plus three of the cousin
findings the v1.4 discovery audit added:

1. **`getPhaseMessage` and `getPhaseKeyboard` were German-only.** Every
   medication reminder shipped via Telegram, ntfy, and Web Push read
   "Erinnerung", "Bald fällig", etc. regardless of the recipient's
   locale. This is the user-facing surface most affected by the v3
   "Locale Mixing" finding because the strings hit users on a 15-minute
   cron, not just an admin / settings page they might never open. The
   reminder worker now passes `med.user.locale` through; messages and
   button labels resolve from `messages/{de,en}.json` under
   `medicationReminders.*`. `callback_data` keys stay stable English
   identifiers so the bot dispatcher keeps matching them across locale
   changes.

2. **`/api/dashboard/summary` ships a hard-coded "Tage in Folge" label
   and "Hi, X" salutation.** Both now come from
   `dashboard.streakLabel` / `dashboard.greetingSalutation` resolved
   server-side against the user's locale.

3. **Mixed-locale Zod messages.** `validations/measurement.ts:69` had
   "Wert muss zwischen … liegen" while line 86 had "Value out of
   plausible range" — the response envelope leaked German into English
   sessions and vice versa. `validations/admin.ts` had four German
   messages (web-push subject, Umami URL, Glitchtip DSN, GitHub
   bug-report repo). All now resolve to a single English wording (the
   app is English-first; the German UI translates the field labels
   client-side, the server-side validation message is treated as a
   developer-facing string).

Adds 13 new tests in `reminder-phases.test.ts` covering English,
German, and unknown-locale fallbacks for messages and keyboards;
updates `validations/measurement.test.ts` to match the unified English
message. The audit's remaining items
(`classifications.ts` server-returned EN category strings,
`pulse-targets.ts`, `targets/route.ts` labels,
`/api/admin/notifications/reminder-check`) ride a follow-up i18n PR —
those are admin-only or client-renderable surfaces with lower
user-facing priority.

Tests: 358 → 371 (+13). Typecheck clean. Locale-integrity test still
green.

Co-authored-by: Marc-André Bombeck <noreply@anthropic.com>
2026-05-08 12:11:44 +02:00
Marc-André Bombeck 38309932f3 Initial release v1.0.0
HealthLog — personal health-tracking PWA with weight, blood pressure,
pulse, mood tracking, medication compliance, Withings integration,
doctor report PDF export, and Dracula-themed UI.
2026-03-10 20:14:33 +01:00