perf(dashboard): bound glucose + bp-in-target windows and stale-time the inline queries

Three small fixes that compound on a power-user dashboard mount:

- **H2**: The per-context glucose summaries walked every persisted
  `BLOOD_GLUCOSE` row a multi-year user has written. The summaries
  only feed the trailing tile, so bound the read to the last 30
  days.
- **M1**: The BP-in-target chunked walk passed no `since` bound
  even though `computeBpInTargetWindows`'s longest sub-window is
  `priorYear`. Pass a 365-day floor through both
  `fetchMeasurementSeriesChunked` calls.
- **M5**: The three inline dashboard `useQuery` blocks shared no
  `staleTime` / `refetchOnWindowFocus` settings, so a tab-focus-
  and-return triggered an immediate refetch storm. Lift a shared
  `DASHBOARD_QUERY_OPTS` object so every query inherits the
  1-minute staleness window the chart queries already use.

iOS-neutral. No contract change; the analytics response shape
stays identical.
This commit is contained in:
Marc-André Bombeck committed 2026-05-16 10:46:49 +02:00
1 parent b012641804
commit c1a52c3268
2 files changed
+37 -3

No files matched your search

+24 -3
View File
@@ -183,9 +183,21 @@ export const GET = apiHandler(async () => {
// `BpReading[]` shape the existing helper expects. The
// `analytics.bp_in_target.row_count` wide-event meta lets ops
// attribute slow requests to specific outlier users.
// v1.4.29 M1 — bound the BP-in-target reads to the trailing
// 365 days. `computeBpInTargetWindows` only needs the last
// year (the longest sub-window it computes is `priorYear`);
// pre-bound, each chunked walk pulled the entire BP history
// every dashboard mount.
const bpInTargetSince = new Date(
now.getTime() - 365 * 24 * 60 * 60 * 1000,
);
const [sysData, diaData] = await Promise.all([
fetchMeasurementSeriesChunked(user.id, "BLOOD_PRESSURE_SYS"),
fetchMeasurementSeriesChunked(user.id, "BLOOD_PRESSURE_DIA"),
fetchMeasurementSeriesChunked(user.id, "BLOOD_PRESSURE_SYS", {
since: bpInTargetSince,
}),
fetchMeasurementSeriesChunked(user.id, "BLOOD_PRESSURE_DIA", {
since: bpInTargetSince,
}),
]);
annotate({
@@ -210,8 +222,17 @@ export const GET = apiHandler(async () => {
}
// Per-context glucose summaries (canonical mg/dL).
//
// v1.4.29 H2 — bound to the trailing 30 days. The dashboard tile
// path only reads the trailing window; pre-bound this query
// walked every persisted BG row a multi-year user has written.
const glucoseSince = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);
const glucoseRows = await prisma.measurement.findMany({
where: { userId: user.id, type: "BLOOD_GLUCOSE" },
where: {
userId: user.id,
type: "BLOOD_GLUCOSE",
measuredAt: { gte: glucoseSince },
},
orderBy: { measuredAt: "asc" },
select: { value: true, measuredAt: true, glucoseContext: true },
});
+13
View File
@@ -191,6 +191,16 @@ export default function DashboardPage() {
useState<HTMLDivElement | null>(null);
const [moodFooterEl, setMoodFooterEl] = useState<HTMLDivElement | null>(null);
// v1.4.29 M5 — the three inline dashboard queries default to a
// 0-ms `staleTime`, so a tab-focus-and-return triggered a refetch
// storm. None of these are real-time data; minute-scale staleness
// is fine and the dashboard's chart queries already match this
// cadence.
const DASHBOARD_QUERY_OPTS = {
staleTime: 60_000,
refetchOnWindowFocus: false,
} as const;
const { data } = useQuery({
queryKey: queryKeys.analytics(),
queryFn: async () => {
@@ -200,6 +210,7 @@ export default function DashboardPage() {
return json.data as AnalyticsData;
},
enabled: isAuthenticated,
...DASHBOARD_QUERY_OPTS,
});
const { data: layoutData } = useQuery({
@@ -211,6 +222,7 @@ export default function DashboardPage() {
return json.data as DashboardLayout;
},
enabled: isAuthenticated,
...DASHBOARD_QUERY_OPTS,
});
const { data: moodData } = useQuery({
@@ -225,6 +237,7 @@ export default function DashboardPage() {
};
},
enabled: isAuthenticated,
...DASHBOARD_QUERY_OPTS,
});
// v1.4.27 B1 — the dashboard's `<InsightsCardPreview>` retired (it