Bundle of hotfixes against v0.5.4 PR #190 surfaced by the QA review:
- Locale resolver now accepts every supported locale instead of
silently demoting es/fr/it/pl to English. The same PR shipped the
translations into the locale files; without this change those
strings were unreachable dead code.
- Ledger row is written only after `dispatchNotification` reports a
successful delivery. A transient APNs / network blip used to land
the ledger first and silently nuke the day's nudge for that user;
now the next tick is free to retry. New `skippedNoChannel` +
`failed` counters on the tick summary so the wide-event attributes
the outcome.
- Per-user `try` wrapper around the inner processing so one bad row
(corrupt timezone, dispatcher exception) cannot abort the rest of
the 22:00 candidates.
- P2002 race on the ledger insert now counts as `dispatched` — the
worker that lost the race already delivered the push, so the user
did receive it.
- Dead-code drop: the now-unused `moodReminderEnabled` select field
(the `where` clause already filters), and the redundant
`MoodReminderCandidate` interface.
- `localHmAsUtc` helper in `@/lib/timezone` re-derives the UTC
offset at the target local time so `todayStart.getTime() + h *
3.6e6` no longer drifts by an hour on DST transition days. The
medication-reminder `scheduledFor` field and the iOS-snooze
`scheduledAt` ISO both route through it now.
- New daily 03:25 Europe/Berlin cron sweeps the
`mood_reminder_dispatches` ledger to a 90-day retention horizon,
matching the audit-log cleanup cadence.
Test coverage rewritten to pin every new contract — outcome bubble,
ledger-after-delivery, per-user try wrapper, P2002 race semantics,
six-locale dispatch — plus a regression test for the v0.5.4 FR
apostrophe typo.
HealthLog — personal health-tracking PWA with weight, blood pressure,
pulse, mood tracking, medication compliance, Withings integration,
doctor report PDF export, and Dracula-themed UI.