Marc-André Bombeck
d665a5db42
chore(release): v1.4.39.2 — per-request rollup convergence and progressive dashboard paint
...
v1.4.39.1 wired the rollup write hook into the Withings sync, /api/import,
and admin-restore paths and widened the boot-time backfill discovery to
per-(user, type, day). Two follow-ups Marc surfaced from the post-deploy
trace remained: the dashboard chart still painted its `< 3 daily points`
empty-state on the 30-point range for accounts whose historic rollup
partition had not yet been folded, and the cold-mount UX waterfall left
every per-type tile waiting on the heavy /api/analytics envelope.
### Fixed
- GET /api/measurements?source=rollup now reconciles the rollup table
against the live measurements table when the read returns suspiciously
few rows. A request that lands while the boot backfill is still folding
the historic partition would previously short-circuit on the sparse
rollup (`rollupRows.length > 0`) and never reconcile with the live
table. The route now probes
`COUNT(DISTINCT date_trunc('day', measured_at))` against measurements
for the requested window when the rollup carries fewer than three
rows on a window of at least seven days; if the live table holds more
distinct days than the rollup, the route folds the
(user, type, DAY, [from, to]) partition inline via
`recomputeUserRollups` and re-reads. The chart paints the full window
on the same request without paying the cost on subsequent requests.
The probe is gated on rollup sparsity so covered-tenant hot paths
stay single-read.
### Changed
- Dashboard analytics fan-out split across two parallel queries. The
per-type tile strip now reads from the slim `?slice=summaries`
branch and paints as soon as the slim slice resolves; the
BD-Zielbereich and glucose tiles stream in from the thick branch
afterwards. Pre-fix the single thick-slice query blocked every
per-type tile until the heavy fan-out resolved, so the mood and
medication tiles (separate routes) painted first and every other
tile arrived as one delayed burst. Both queries share the
`caches.analytics` 60 s LRU server-side so warm hits stay free.
### Notes
- No schema migration. Runtime-only fix on top of the v1.4.39.1
write-path hooks.
- pnpm test --run green at 4654 / 4655 (1 long-standing skip);
targeted suites (src/app/api/measurements, src/lib/measurements,
src/app/__tests__) all clean.
- The inline rollup fold cost is bounded by the requested window and
one measurement type. For the dashboard chart's 30-day BP_SYS window
that is a single 30-row upsert against the composite primary key —
well inside the request budget.
2026-05-21 09:56:24 +02:00
..
2026-05-18 06:07:14 +02:00
2026-05-17 15:36:38 +02:00
2026-05-16 19:46:43 +02:00
2026-05-16 14:19:57 +02:00
2026-05-11 02:44:12 +02:00
2026-05-12 22:45:42 +02:00
2026-05-16 13:20:49 +02:00
2026-05-10 12:51:33 +02:00
2026-05-09 16:06:52 +02:00
2026-05-09 16:08:20 +02:00
2026-05-09 18:08:25 +02:00
2026-05-09 18:08:25 +02:00
2026-05-09 17:02:59 +02:00
2026-05-09 18:08:25 +02:00
2026-05-09 18:08:25 +02:00
2026-05-10 11:09:41 +02:00
2026-05-10 13:02:39 +02:00
2026-05-10 11:09:41 +02:00
2026-05-10 13:12:11 +02:00
2026-05-10 13:15:14 +02:00
2026-05-11 08:27:51 +02:00
2026-05-10 11:09:41 +02:00
2026-05-10 13:00:11 +02:00
2026-05-11 08:27:51 +02:00
2026-05-11 08:27:51 +02:00
2026-05-10 13:16:19 +02:00
2026-05-10 11:09:41 +02:00
2026-05-11 08:27:51 +02:00
2026-05-10 14:01:38 +02:00
2026-05-10 11:09:41 +02:00
2026-05-11 08:27:51 +02:00
2026-05-10 11:09:41 +02:00
2026-05-10 11:09:41 +02:00
2026-05-10 11:09:41 +02:00
2026-05-11 08:27:51 +02:00
2026-05-11 08:27:51 +02:00
2026-05-11 08:27:51 +02:00
2026-05-10 17:24:59 +02:00
2026-05-11 08:27:51 +02:00
2026-05-10 11:09:41 +02:00
2026-05-10 11:09:41 +02:00
2026-05-10 11:09:41 +02:00
2026-05-10 11:09:41 +02:00
2026-05-10 11:09:41 +02:00
2026-05-10 00:29:22 +02:00
2026-05-10 11:09:41 +02:00
2026-05-10 11:09:41 +02:00
2026-05-10 11:09:41 +02:00
2026-05-11 08:27:51 +02:00
2026-05-10 11:09:41 +02:00
2026-05-10 11:09:41 +02:00
2026-05-10 11:09:41 +02:00
2026-05-10 11:09:41 +02:00
2026-05-10 11:09:41 +02:00
2026-05-10 11:09:41 +02:00
2026-05-10 11:09:41 +02:00
2026-05-11 08:27:51 +02:00
2026-05-11 08:27:51 +02:00
2026-05-10 11:09:41 +02:00
2026-05-11 08:27:51 +02:00
2026-05-11 08:27:51 +02:00
2026-05-11 08:27:51 +02:00
2026-05-11 08:27:51 +02:00
2026-05-10 11:09:41 +02:00
2026-05-11 08:27:51 +02:00
2026-05-11 08:27:51 +02:00
2026-05-11 08:27:51 +02:00
2026-05-11 08:27:51 +02:00
2026-05-11 08:27:51 +02:00
2026-05-11 08:27:51 +02:00
2026-05-10 18:17:55 +02:00
2026-05-11 08:27:51 +02:00
2026-05-11 08:27:51 +02:00
2026-05-11 08:27:51 +02:00
2026-05-10 14:55:27 +02:00
2026-05-10 15:17:03 +02:00
2026-05-11 08:27:51 +02:00
2026-05-11 08:27:51 +02:00
2026-05-11 08:27:51 +02:00
2026-05-14 23:49:32 +02:00
2026-05-14 23:49:32 +02:00
2026-05-14 23:49:32 +02:00
2026-05-14 23:49:32 +02:00
2026-05-11 08:27:51 +02:00
2026-05-10 11:09:41 +02:00
2026-05-10 11:09:41 +02:00
2026-05-10 19:31:20 +02:00
2026-05-11 08:28:02 +02:00
2026-05-11 08:27:51 +02:00
2026-05-11 08:28:02 +02:00
2026-05-11 08:27:51 +02:00
2026-05-11 08:27:51 +02:00
2026-05-14 23:49:32 +02:00
2026-05-17 15:36:38 +02:00
2026-05-11 08:27:51 +02:00
2026-05-11 08:27:51 +02:00
2026-05-14 23:49:32 +02:00
2026-05-17 15:36:38 +02:00
2026-05-14 23:49:32 +02:00
2026-05-14 23:49:32 +02:00
2026-05-11 08:27:51 +02:00
2026-05-11 08:27:51 +02:00
2026-05-14 23:49:32 +02:00
2026-05-17 15:36:38 +02:00
2026-05-17 15:36:38 +02:00
2026-05-14 23:49:32 +02:00
2026-05-14 23:49:32 +02:00
2026-05-11 08:28:02 +02:00
2026-05-11 08:28:02 +02:00
2026-05-11 08:28:02 +02:00
2026-05-11 08:27:51 +02:00
2026-05-11 08:28:02 +02:00
2026-05-11 08:28:02 +02:00
2026-05-11 08:28:02 +02:00
2026-05-11 08:27:51 +02:00
2026-05-14 23:49:32 +02:00
2026-05-17 15:36:38 +02:00
2026-05-14 23:49:32 +02:00
2026-05-11 08:28:02 +02:00
2026-05-11 08:28:02 +02:00
2026-05-11 08:28:02 +02:00
2026-05-12 22:33:35 +02:00
2026-05-11 08:28:02 +02:00
2026-05-11 08:28:02 +02:00
2026-05-11 08:28:02 +02:00
2026-05-14 23:49:32 +02:00
2026-05-17 15:36:38 +02:00
2026-05-14 23:49:32 +02:00
2026-05-14 23:49:32 +02:00
2026-05-17 15:36:38 +02:00
2026-05-14 23:49:32 +02:00
2026-05-17 15:36:38 +02:00
2026-05-17 15:36:38 +02:00
2026-05-14 23:49:32 +02:00
2026-05-14 23:49:32 +02:00
2026-05-14 23:49:32 +02:00
2026-05-17 15:36:38 +02:00
2026-05-14 23:49:32 +02:00
2026-05-14 23:49:32 +02:00
2026-05-14 23:49:32 +02:00
2026-05-14 23:49:32 +02:00
2026-05-14 23:49:32 +02:00
2026-05-17 15:36:38 +02:00
2026-05-14 23:49:32 +02:00
2026-05-17 15:36:38 +02:00
2026-05-17 15:36:38 +02:00
2026-05-17 15:36:38 +02:00
2026-05-17 15:36:38 +02:00
2026-05-17 15:36:38 +02:00
2026-05-17 15:36:38 +02:00
2026-05-17 15:36:38 +02:00
2026-05-14 23:49:32 +02:00
2026-05-14 23:49:32 +02:00
2026-05-14 23:49:32 +02:00
2026-05-14 23:49:32 +02:00
2026-05-14 23:49:32 +02:00
2026-05-14 23:49:32 +02:00
2026-05-14 23:49:32 +02:00
2026-05-14 23:49:32 +02:00
2026-05-14 23:49:32 +02:00
2026-05-14 23:49:32 +02:00
2026-05-14 23:49:32 +02:00
2026-05-14 23:49:32 +02:00
2026-05-14 23:49:32 +02:00
2026-05-14 23:49:32 +02:00
2026-05-14 23:49:32 +02:00
2026-05-14 23:49:32 +02:00
2026-05-14 23:49:32 +02:00
2026-05-14 23:49:32 +02:00
2026-05-14 23:49:32 +02:00
2026-05-14 23:49:32 +02:00
2026-05-14 23:49:32 +02:00
2026-05-14 23:49:32 +02:00
2026-05-14 23:49:32 +02:00
2026-05-14 23:49:32 +02:00
2026-05-14 23:49:32 +02:00
2026-05-14 23:49:32 +02:00
2026-05-17 19:07:03 +02:00
2026-05-17 19:07:03 +02:00
2026-05-17 19:07:03 +02:00
2026-05-17 15:36:38 +02:00
2026-05-17 19:07:03 +02:00
2026-05-17 19:07:03 +02:00
2026-05-17 19:07:03 +02:00
2026-05-21 07:39:10 +02:00
2026-05-21 07:39:10 +02:00
2026-05-17 19:07:03 +02:00
2026-05-17 19:07:03 +02:00
2026-05-17 19:07:03 +02:00
2026-05-17 19:07:03 +02:00
2026-05-17 19:07:03 +02:00
2026-05-21 07:39:10 +02:00
2026-05-21 07:39:10 +02:00
2026-05-21 07:39:10 +02:00
2026-05-10 11:09:41 +02:00
2026-05-09 01:22:09 +02:00
2026-05-16 12:37:55 +02:00
2026-05-14 23:49:32 +02:00
2026-05-15 22:59:10 +02:00
2026-05-15 22:59:10 +02:00
2026-05-15 22:59:10 +02:00
2026-05-15 22:59:10 +02:00
2026-05-15 22:59:10 +02:00
2026-05-15 22:59:10 +02:00
2026-05-15 22:59:10 +02:00
2026-05-15 22:59:10 +02:00
2026-05-16 09:28:40 +02:00
2026-05-16 09:28:40 +02:00
2026-05-16 09:28:40 +02:00
2026-05-15 22:59:10 +02:00
2026-05-15 22:59:10 +02:00
2026-05-15 22:59:10 +02:00
2026-05-15 22:59:10 +02:00
2026-05-15 22:59:10 +02:00
2026-05-15 22:59:10 +02:00
2026-05-15 22:59:10 +02:00
2026-05-16 09:28:40 +02:00
2026-05-16 09:28:40 +02:00
2026-05-16 09:28:40 +02:00
2026-05-15 22:59:10 +02:00
2026-05-15 22:59:10 +02:00
2026-05-15 22:59:10 +02:00
2026-05-15 22:59:10 +02:00
2026-05-15 22:59:10 +02:00
2026-05-16 09:28:40 +02:00
2026-05-16 09:28:40 +02:00
2026-05-16 09:28:40 +02:00
2026-05-16 10:59:42 +02:00
2026-05-17 00:39:58 +02:00
2026-05-17 00:39:58 +02:00
2026-05-17 00:39:58 +02:00
2026-05-21 09:56:24 +02:00
2026-05-17 00:39:58 +02:00
2026-05-17 00:39:58 +02:00
2026-05-17 00:39:58 +02:00
2026-05-17 00:39:58 +02:00
2026-05-17 00:39:58 +02:00
2026-05-16 14:19:57 +02:00
2026-05-16 12:37:55 +02:00
2026-05-16 14:19:57 +02:00
2026-05-16 16:04:21 +02:00
2026-05-16 16:04:21 +02:00
2026-05-16 19:46:43 +02:00
2026-05-16 22:26:59 +02:00
2026-05-16 19:46:43 +02:00
2026-05-16 19:46:43 +02:00
2026-05-16 19:46:43 +02:00
2026-05-16 19:46:43 +02:00
2026-05-16 19:46:43 +02:00
2026-05-16 19:46:43 +02:00
2026-05-16 21:25:26 +02:00
2026-05-16 19:46:43 +02:00
2026-05-16 19:46:43 +02:00
2026-05-16 19:46:43 +02:00
2026-05-16 19:46:43 +02:00
2026-05-16 19:46:43 +02:00
2026-05-16 19:46:43 +02:00
2026-05-16 19:46:43 +02:00
2026-05-16 19:46:43 +02:00
2026-05-16 19:46:43 +02:00
2026-05-16 19:46:43 +02:00
2026-05-16 19:46:43 +02:00
2026-05-17 00:06:18 +02:00
2026-05-16 22:26:59 +02:00
2026-05-16 21:25:26 +02:00
2026-05-16 21:25:26 +02:00
2026-05-16 21:25:26 +02:00
2026-05-16 22:26:59 +02:00
2026-05-16 22:26:59 +02:00
2026-05-16 21:25:26 +02:00
2026-05-16 21:25:26 +02:00
2026-05-16 21:25:26 +02:00
2026-05-16 22:26:59 +02:00
2026-05-16 21:25:26 +02:00
2026-05-16 22:26:59 +02:00
2026-05-17 09:55:33 +02:00
2026-05-17 13:22:51 +02:00
2026-05-17 15:36:38 +02:00
2026-05-17 13:22:51 +02:00
2026-05-17 15:36:38 +02:00
2026-05-17 15:36:38 +02:00
2026-05-17 16:37:51 +02:00
2026-05-17 15:36:38 +02:00
2026-05-17 19:07:03 +02:00
2026-05-21 07:39:10 +02:00
2026-05-17 23:46:09 +02:00
2026-05-17 19:07:03 +02:00
2026-05-21 09:03:33 +02:00
2026-05-21 07:39:10 +02:00
2026-05-21 07:39:10 +02:00
2026-05-21 07:39:10 +02:00
2026-05-21 07:39:10 +02:00
2026-05-21 07:39:10 +02:00
2026-05-21 07:39:10 +02:00
2026-05-21 07:39:10 +02:00
2026-05-14 23:49:32 +02:00
2026-05-15 22:59:10 +02:00
2026-05-12 22:45:42 +02:00
2026-05-16 21:25:26 +02:00
2026-05-09 17:57:30 +02:00
2026-05-10 11:09:41 +02:00
2026-05-10 11:09:41 +02:00
2026-05-10 11:09:41 +02:00
2026-05-10 11:09:41 +02:00
2026-05-10 13:12:11 +02:00
2026-05-10 11:10:59 +02:00
2026-05-11 08:27:51 +02:00
2026-05-11 08:27:51 +02:00
2026-05-11 08:27:51 +02:00
2026-05-11 08:27:51 +02:00
2026-05-12 22:33:35 +02:00
2026-05-15 22:59:10 +02:00
2026-05-14 23:49:32 +02:00
2026-05-14 23:49:32 +02:00
2026-05-15 22:59:10 +02:00
2026-05-15 22:59:10 +02:00
2026-05-15 22:59:10 +02:00
2026-05-15 22:59:10 +02:00
2026-05-15 22:59:10 +02:00
2026-05-15 22:59:10 +02:00
2026-05-15 22:59:10 +02:00
2026-05-15 22:59:10 +02:00
2026-05-15 22:59:10 +02:00
2026-05-15 22:59:10 +02:00
2026-05-15 22:59:10 +02:00
2026-05-16 03:17:00 +02:00
2026-05-16 03:17:00 +02:00
2026-05-16 09:28:40 +02:00