[1.4.16] — 2026-05-09
Added
- Per-recommendation explainability. Every insight recommendation now
carries a rationale: which time window was analysed, what was compared,
and the deviation that triggered the recommendation. The card expands
inline to reveal the rationale plus a mini-chart of the data window. - Confidence score per recommendation. Each recommendation gets a
deterministic 0–100 confidence score (server-computed from sample size,
recency, and signal strength) shown as a colour-banded ring + bar meter.
Below-threshold recommendations are tagged "low confidence — based on
limited data" rather than hidden. - "Was this helpful?" feedback. Thumbs-up / thumbs-down on every
recommendation, persisted per user with provider attribution. Daily
aggregator writes per-(severity × provider) helpful-rate to admin
settings; the aggregate is visible under/admin/ai-quality. - Medical-reference grounding. Recommendations cite curated AHA / ESH
/ ESC / WHO / DGE guidelines via a validatedreferenceId; the
citation links open the source guideline in a new tab. - Multi-provider AI fallback chain. The insight wrapper tries each
configured provider in turn on hard failures (401 / 403 / 429 / 5xx /
transport). Schema 422 still bubbles. Last-working provider is cached
per user for an hour. Order, enable / disable, and provider list are
configurable under Settings → AI. - Apple-Health-style chart polish. Blood pressure, weight, pulse,
body fat, sleep, steps, mood, and medication-compliance charts gain
gradient fills, smooth interpolation, a 90-day-median personal-baseline
reference line, in-target zone shading, rich tooltips with delta
vs. baseline, and 600 ms ease-out animation that respects
prefers-reduced-motion. Sparse data (<3 points) renders an explicit
empty state instead of a degenerate line. - Comparison overlay (vs. last month / vs. last year). A new toggle
at the top of every chart, tile, and the insights surface overlays the
prior period as a dimmed line beneath the current one and adds a delta
callout (Δ ±N). The AI summary narrates the comparison ("your average
BP improved by 4 mmHg vs. last month") when the toggle is active. - Settings → Export. Consolidated
/settings/exportpage with one
card per export type: doctor-report PDF (configurable date range +
practice name), measurements CSV, medications CSV (optional intake
history), mood CSV, full JSON backup. Each download writes a
user.export.<kind>audit-log entry and shares a 10/h rate-limit
bucket. Doctor-report entry-point relocated under this route. - Achievements page. New
/achievementspage with locked + unlocked
breakdown grouped by category (medication / vitals / security /
engagement). Recent unlocks card on the dashboard, toggleable from
layout settings. - Onboarding tour for new users. First-run spotlight walk-through
highlighting tile-strip, quick-add menu, insights, integrations, and
achievements. Skippable, keyboard-navigable, replayable from
Settings → Account. - Admin host-load chart. New chart over the system-status section
shows host CPU, memory, and disk-IO over the last 2 hours, sampled
every minute, retained for 7 days. - Admin app-log preview. Tail of the last 1 hour of structured
wide-events from the per-process ring buffer, filterable by trace_id /
level / action / time-window with a JSON inspector modal. - Admin AI quality preview. New
/admin/ai-qualityroute surfaces
helpful-rate per (severity × provider), tinted by band so degrading
providers stand out at a glance.
Changed
- Insights surface uses the new RecommendationCard everywhere. The
/insightspage and the dashboard insights tile both render the
polished card — rationale expand, confidence meter, citation footnote,
feedback thumbs — backed by a shared TanStack Query cache. - Trend label normalised to "7-day trend". Every chart, tile, and
subtitle uses the long form. A signed numeric delta indicator (±N.N)
with metric-aware colouring appears next to the value on every chart,
including mood and medication-compliance. /adminoverview redesigned. The section grid is gone; the
overview now shows a system-status snapshot with host-load chart and
an audit-log preview. Sidebar carries the section list.- Sidebar admin sub-items only expand on
/admin/*. Clicking the
Admin link or opening the Gravatar dropdown no longer auto-expands
the sub-list when you are not on an admin route. - Settings → AI is a single dropdown. The provider selector at the
top drives the configuration form below; no more top/bottom split. All
five providers (Codex / OpenAI / Anthropic / Local / Admin OpenAI) are
reachable from the same UI. - Top dashboard tiles selectable per metric. The widget-id enum bug
from v1.4.15 that silently 422'd every layout PUT is fixed; the
per-metric tile toggle in layout settings now actually persists. - AI rate-limit raised to 10/hour. Default bumped from 2/h to 10/h;
configurable viaINSIGHTS_RATE_LIMIT_PER_HOUR. Generating a new
insight evicts every previously cached per-status insight for that
user, so the dashboard never shows a stale cached payload.
Fixed
- BD-Zielbereich percentage now counts in-range readings correctly.
The v1.4.15 fix corrected the denominator but kept the ESH narrow-band
predicate (sysLow ≤ sys ≤ sysHigh AND diaLow ≤ dia ≤ diaHigh), so
normotensive readings (e.g. 117/79) belowsysLow=120counted as out
of range. Predicate switched to one-sided ceiling semantics with a
hypotension floor (90 ≤ sys ≤ sysHigh AND 50 ≤ dia ≤ diaHigh),
centralised inisBpReadingInTarget()shared by six call sites. - Trend on "all" filter shows a meaningful split-half delta. Long
windows where the per-week rate fell below the 1-decimal display
precision now also surface a split-half mean delta (second-half mean
minus first-half mean) for windows ≥ 90 days. - Login overview no longer strips umlauts. The geo helper decodes
viaarrayBuffer()+TextDecoder('utf-8')instead of
Response.json(), so an upstream proxy stripping the
Content-Type: charsetparameter cannot poison the umlaut path.
Nürnberg, München, Düsseldorf, Köln, Würzburg, Bückeburg, Weißenfels
all roundtrip correctly. /admin/api-tokenstable no horizontal overflow on mobile. The
desktop<table>falls back to a card list at<mdviewports, with
long names + permission badges wrapping cleanly inside the card.- Skip-link no longer blocks logo click. The "Skip to content"
shortcut still leads the tab order but no longer blocks pointer events
on the logo. - Bug-Report nav entry follows the admin feature toggle. When the
admin disables bug reporting the entry vanishes from sidebar,
bottom-nav, topbar, and the error-detail "Report bug" button. - Feedback link follows the admin feature toggle. When feedback
collection is disabled, the UI entry point disappears too. - Cached AI insights replaced when the user regenerates. Generating
a new insight invalidates the per-statusaudit_logsentries plus the
TanStack Query cache, so the dashboard always shows the freshest
payload.
Performance
- Comparison overlays computed via reusable bucket-series helper. No
extra round-trip per chart — the dashboard fetcher and AI snapshot
both read from the sameavg30LastMonth/avg30LastYearfields. /api/insights/feedbackpersists with optimistic UI updates.
Thumbs-up / thumbs-down apply instantly; the localStorage refresh-
defence keeps the verdict on rerender even before the mutation
resolves.
Security
- AI provider apiKeys encrypted at rest. Provider chain entries that
carry a key store it AES-256-GCM via the existingsrc/lib/crypto.ts
helper. /api/insights/feedbackgated byrequireAuth+ idempotency-key.
The dedicated rate-limit bucket prevents thumbs-spam.- Per-provider attribution server-filled. Clients cannot tamper with
which provider gets credit for a recommendation; the attribution is
resolved server-side from the latestinsights.generateaudit row. - Admin egress redacts secrets. Audit-log
detailsand app-log
metafields run throughredactSecrets()before leaving the admin
API surface.
Internal
docker-publishworkflow no longer hangs on main-branch builds.
Root cause was a qemu-arm64 SIGILL during multi-arch emulation; arm64
dropped from the platforms list. Native arm64 runner matrix scheduled
for v1.5.- CI integration tests + e2e workflows green again. Both had been
pre-existing red sinced8c549e(encryption-key YAML scalar parsed
as integer 0 + spotlight tour overlay intercepting clicks). Both fixed
this milestone.
Deferred to v1.5
- Coolify image-digest auto-deploy trigger (currently fires on every
git-push; Marc-side UI flip is the realistic fix). - Native arm64 runner matrix for full multi-arch docker publish.
- Cross-user feedback aggregation prompt-tuning ratchet (depends on
v1.4.16 feedback collection accumulating data). - Dedicated
/insights/comparepage (i18n keys
comparison.insightsCallout.{lastMonth,lastYear}reserved).