Commit Graph
244 Commits
Author SHA1 Message Date
Marc-André Bombeck 9bae4dd2f6 fix(ui): stack the date-time field on narrow viewports
A native date input keeps its intrinsic width on mobile WebKit and won't
shrink, so the `date + fixed-width time` row overran a phone-width sheet —
the time field and its clock icon spilled past the screen edge and every
add form (measurements, mood, medication, …) scrolled sideways. Stack the
two halves on narrow viewports and only place them side-by-side from the
`sm` breakpoint up; each half then takes the full sheet width and nothing
overflows.
2026-06-30 10:33:16 +02:00
Marc-André Bombeck 3d75db917e fix(settings): keep the section nav hydration-stable
The settings section navigation filtered its entries by the resolved
`user.modules` map directly in render. That map resolves at different
points on the server-rendered pass and the hydrating client pass, so the
two renders emitted a different number of nav entries — a hydration
mismatch that made React discard and regenerate the tree, leaving every
control on the page non-interactive (a disclosure that wouldn't open, an
export button that did nothing).

Emit the full fail-open list on both the server pass and the first client
paint (gated behind a `useSyncExternalStore` hydration probe), then apply
the module filter once, after hydration. Server and first client render
now always match, so the nav — and the rest of the settings page — stays
interactive.
2026-06-30 09:49:09 +02:00
Marc-André Bombeck c306d42347 chore(release): v1.25.9 — custom metrics
Renumber the custom-metrics migration to 0223 (the next free slot on the
trunk) and cut the release: version bump, regenerated OpenAPI contract,
service-worker stamp, and CHANGELOG entry.
2026-06-30 08:59:44 +02:00
Marc-André Bombeck bdac5b2c0d feat(admin): resolve the sign-in carrier online + give it its own column
The network operator (carrier) used to resolve only from the optional
offline GeoLite2-ASN database. On a host without it the carrier stayed
empty even though the location resolved fine online.

Mine the operator from the same online provider response the location
lookup already fetches — ip-api's top-level `isp`/`org`/`as`, ipwho.is's
nested `connection.{isp,org,asn}` — so the carrier is populated out of the
box. The offline ASN database stays authoritative when configured.

A single `lookupIpGeo` now returns location + ASN + carrier in one pass;
the audit write and the backfill both go through it. The backfill also
revisits rows that already had a location but no carrier, so the column
fills in across existing history, not just for new sign-ins.

In the admin sign-in overview the carrier moves out of a chip stacked
under the login method into its own column, next to the location.
2026-06-29 23:51:40 +02:00
Marc-André Bombeck b6886c50d2 chore(release): v1.25.7 2026-06-29 22:42:50 +02:00
Marc-André Bombeck e51c6dc2ad feat(geo): allow an opt-in plain-HTTP location provider
A self-hoster can set IP_GEO_ALLOW_INSECURE=true alongside an http:// URL to
use a free HTTP-only provider — the free ip-api.com endpoint is HTTP-only (its
HTTPS form needs a paid key) but its geolocation is often more accurate and it
carries the ISP. The default stays HTTPS-only with ipwho.is; plain HTTP is
refused unless the operator explicitly opts in, since the looked-up IP then
travels unencrypted over the server's own egress. Whitelisted in compose and
documented in the env example.
2026-06-29 20:38:04 +02:00
Marc-André Bombeck c275683e42 chore(release): v1.25.5 2026-06-29 20:04:25 +02:00
Marc-André Bombeck 2c701e121e fix(measurements): keep blood-pressure field labels on one line
In the three-column blood-pressure entry grid the "Systolic (mmHg)" /
"Diastolic (mmHg)" / "Pulse (bpm)" labels wrapped onto a second line in
narrow columns. Render the localised label as the metric name (which
truncates if it must) plus the unit as a compact muted affix that never
wraps, so each field reads on a single line while keeping its unit.
2026-06-29 19:09:17 +02:00
Marc-André Bombeck 7e901e674a fix(ui): own the time picker so it follows the 24-hour preference
The native datetime-local / time picker renders its clock and AM/PM
toggle by the browser UI language, not the page lang or the app's
time-format preference — so an English-language browser showed AM/PM
even with 24-hour selected. Replace the native time control with an
app-controlled TimeField (text entry + a dependency-free popover of
hour/minute, plus AM/PM in 12-hour mode) whose hour cycle always tracks
the preference. DateTimeField now composes the native calendar (date)
with TimeField (time); the committed value stays a local
yyyy-MM-ddTHH:mm string, and min/max clamp the recombined value.

Also thread the time-format preference into the doctor-report PDF so its
generated-at timestamp honours it instead of the locale default.
2026-06-29 19:03:47 +02:00
Marc-André Bombeck 00ea61ee9f chore(release): v1.25.3 2026-06-29 15:53:41 +02:00
Marc-André Bombeck b84cdba6e0 chore(release): v1.25.2 2026-06-29 07:16:21 +02:00
Marc-André Bombeck 7c2e11369c chore(release): v1.25.1 2026-06-29 01:07:42 +02:00
Marc-André Bombeck 8eaa8a714e chore(release): v1.25.0 2026-06-28 18:48:09 +02:00
Marc-André Bombeck 9e62d044b6 chore(release): v1.24.0 2026-06-28 02:02:05 +02:00
Marc-André Bombeck 1e4715dfc9 chore(release): v1.23.0 2026-06-27 22:29:59 +02:00
Marc-André Bombeck eb97701f45 chore(release): v1.22.1 2026-06-27 18:29:52 +02:00
Marc-André Bombeck 480ff18cf2 chore(release): v1.22.0 2026-06-27 16:37:35 +02:00
Marc-André Bombeck 65a3eb74be chore(release): v1.21.4 2026-06-27 12:18:42 +02:00
Marc-André Bombeck d78361596d chore(release): v1.21.3
Adds the Coach goal / if-then-plan memory model (propose-then-confirm,
encrypted, migration 0194) and a standing Coach quality harness (graded
golden set + red-team in CI, optional nightly model judge off by default).
Caches the dashboard snapshot per language. No breaking changes.
2026-06-27 11:02:15 +02:00
Marc-André Bombeck 5142582d3d chore(release): v1.21.2.1
Hotfix: the Coach and daily briefing failed for ChatGPT-provider accounts —
a provider tool-call rejection surfaced as a 500. Provider failures now
degrade gracefully, the Codex tool-call wire format is corrected, and the
provider error body is captured for diagnosis. Also: the thinking bubble
shows only the animated dots.
2026-06-27 10:33:11 +02:00
Marc-André Bombeck 388c8b23dd chore(release): v1.21.2
Surfaces the Coach's existing intelligence as ambient presence: a per-metric
"Coach read", a visible scope handoff and a seeded opener, briefing callbacks,
a tension verdict and return-to-baseline note on the score, two motivational-
interviewing moves, and grounding parity on the local model path. No
migrations, no breaking changes.
2026-06-27 00:37:15 +02:00
Marc-André Bombeck f3ffafaae1 chore(release): v1.21.1
Patch release. Pins the action row in the centred dialog so the primary
button stays reachable without scrolling under long forms, browser zoom, or
display scaling. No migrations, no breaking changes.
2026-06-26 22:55:37 +02:00
Marc-André Bombeck e6ac604c83 chore(release): v1.21.0 2026-06-26 14:03:51 +02:00
Marc-André Bombeck cd6fff9730 chore(release): v1.20.2 2026-06-26 09:36:02 +02:00
Marc-André Bombeck 2c112c3323 fix(dashboard): stop the chart-row render loop on tab resume
A user reported the dashboard crashing on returning to a backgrounded
tab. The on-focus snapshot refetch re-rendered the page, and each chart
received a fresh inline `() => markChartReady(id)` handler every render;
the chart's data-ready notify effect, keyed on that ever-changing prop,
re-fired on every commit. That per-commit passive effect kept the chart
row's anchored popovers re-committing until the browser tripped its
render-depth guard and the page fell back to its error card.

Latch the notify behind a ref so it fires once, when the chart's initial
query settles, and depend on the load flag alone. The handler is read
through a ref so a late-arriving callback still fires without re-arming
the effect. Extract the pure fire-once decision into a small helper with
direct unit coverage (no DOM runner, per project convention).
2026-06-23 21:45:42 +02:00
Marc-André Bombeck b9368b9a69 chore(release): v1.20.0 2026-06-22 08:36:28 +02:00
Marc-André Bombeck b4bf31a8c9 chore(release): v1.19.2 2026-06-21 21:21:13 +02:00
Marc-André Bombeck 41dab24985 chore(release): v1.19.1 2026-06-21 14:24:39 +02:00
Marc-André Bombeck 31efb3e884 chore(release): v1.19.0 2026-06-21 12:46:32 +02:00
Marc-André Bombeck 3e578836cc chore(release): v1.18.11 2026-06-21 09:40:53 +02:00
Marc-André Bombeck 16759b4df8 chore(release): v1.18.10
Fix encrypted day-log data loss and the stalled cumulative-measurement drain;
capture Withings sleep vitals and Oura VO2max; harden AI grounding across the
briefing, Coach, narrative, and status cards; full-page Coach with history and a
working mic; on-device lab OCR; preventive-care, labs, and settings polish; BP
warm/cold parity, a statement timeout, and a covering measurements index.
2026-06-20 17:19:14 +02:00
Marc-André Bombeck 731714ebde chore(release): v1.18.9
Coach new-chat surface with streamed answers and a token footer; lab-report OCR
ingestion with a mandatory per-row review; qualitative lab results; labs list
default, sort, and delete; VO2max on the dashboard with Oura ingest; preventive-
care date and due-status polish; faster condition journal; honest report
staleness; dashboard freshness on background sync.
2026-06-20 13:05:34 +02:00
Marc-André Bombeck 3dd5b3dd5b chore(release): v1.18.8 — coded condition and lab terminology in the export 2026-06-20 09:51:10 +02:00
Marc-André Bombeck 1f4ba5939d style: apply prettier across the tree
One-shot prettier pass so the new format:check gate starts from a clean
baseline. Formatting only — no behaviour change. Generator-owned and
vendored artifacts stay untouched via .prettierignore.
2026-06-19 22:20:31 +02:00
Marc-André Bombeck 7c2762b0a5 docs(changelog): expand the v1.18.7 entry for migrations and contract changes
Record the share-link restore and passphrase gate, the Labs/preventive/
condition settings sections, the AI-request batching and prompt
consolidation, the mobile consistency pass, the medication-supply
freshness fix, the budget-gate hardening, and the three new migrations.
2026-06-19 22:11:47 +02:00
Marc-André Bombeck cdb76f1930 chore(release): v1.18.7 2026-06-19 20:03:28 +02:00
Marc-André Bombeck 155cedda50 chore(release): v1.18.6.1 2026-06-19 00:05:20 +02:00
Marc-André Bombeck 1118d36cf8 docs: consolidate the v1.18.6 changelog for the full cycle
Cover the whole release — offline reads, cited reference ranges + Coach
grounding, responsible safety alerts + diabetes opt-in, the module tour,
the module-consistency and settings/admin IA pass, sleep/coach polish,
and the reminder completion route — and correct the additive migration
note (0173–0177).
2026-06-18 22:45:26 +02:00
Marc-André Bombeck 36ce82866a chore(release): v1.18.6 2026-06-18 15:35:49 +02:00
Marc-André Bombeck 474e99e0f8 chore(release): v1.18.5 2026-06-18 14:43:47 +02:00
Marc-André Bombeck 37a361197a chore(release): v1.18.4 2026-06-18 11:46:19 +02:00
Marc-André Bombeck 8bc8b5765d chore(release): v1.18.3 2026-06-17 14:17:45 +02:00
Marc-André Bombeck ff5efb4234 chore(release): v1.18.2 2026-06-17 07:56:07 +02:00
Marc-André Bombeck 7acd770da6 docs(changelog): v1.18.1 release notes 2026-06-16 23:40:36 +02:00
Marc-André Bombeck e1e3cb6364 chore(release): v1.18.1
Maintenance patch clearing two transitive security advisories. Bump the
package version, record the changelog entry, and regenerate the OpenAPI
version line. No functional changes.
2026-06-16 19:22:33 +02:00
Marc-André Bombeck 0dbb70134c chore(release): v1.18.0 — module enable/disable and the settings IA redesign 2026-06-16 11:58:23 +02:00
Marc-André Bombeck 497982b4b4 chore(release): v1.17.1 — preventive care, lab results, and more of the data you already have 2026-06-15 01:40:36 +02:00
Marc-André Bombeck 3f5b1a66a1 chore(release): v1.17.0 — clinical depth for glucose and sleep, three new sources
Add the blood-glucose clinical panel with Nightscout, sleep debt and chronotype,
Polar and Oura over OAuth, reorder-aware medication supply and an invite
deep-link. Every new metric is computed once on the server and read the same way
on the dashboard, the coach, the doctor-report and the companion app, each behind
a still-learning gate. The coach now reasons from the new signals, mood and cycle
entry is one sectioned sheet, and previously-hidden wearable data surfaces.
2026-06-14 21:29:45 +02:00
Marc-André Bombeck 870ee01826 chore(release): v1.16.17 — restore the sleep timeline, clear the dashboard after a dose
Two daily-use fixes: the last-night hypnogram bar collapsed to its breakdown
for nights whose stages share an end instant, and the dashboard kept prompting
for a dose until a full reload after it was recorded. No breaking changes.
2026-06-14 20:21:31 +02:00
Marc-André Bombeck 04b09e2905 chore(release): v1.16.16 — one engine for sleep, recovery and glucose
Read sleep, recovery and blood glucose from a single source on every surface —
dashboard, coach, doctor-report, CSV and FHIR exports, and the companion app —
so the displayed figure agrees wherever it appears. Sleep nights reconstruct
once with source de-duplication; WHOOP-native recovery is canonical and resolves
to one row per night; glucose converts to the user's unit at the point it is
served. Hardens the consent receipt path and deepens WHOOP sync with per-resource
cursors, targeted refresh and full backfill. Several displayed numbers become
correct-but-different — flagged in the changelog.
2026-06-14 17:58:56 +02:00