From 1dd1a9a7a557357078c963ccd2ba80e511b7eb09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Thu, 21 May 2026 11:45:25 +0200 Subject: [PATCH] fix(mood-chart): align queryKey to the shared mood-analytics factory entry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pre-fix the dashboard mounted two separate consumers against the same `/api/mood/analytics` endpoint: `app/page.tsx:291` keyed on `queryKeys.moodAnalytics()` (`["mood-analytics"]`) and the chart at `mood-chart.tsx:316` keyed on a bare `["mood-chart-data"]` literal. TanStack treats different keys as separate cache slots, so a cold dashboard mount fired two requests against the same endpoint — wasting one HTTP round trip, one pg pool slot, and ~22 KB of payload per cold mount (empirical-trace #3). Re-key the chart to `queryKeys.moodAnalytics()` so TanStack dedups the request; align the chart's `staleTime` to the dashboard's 60 s window so a route swing back to the dashboard within a minute stays a free cache hit. The chart's own subscription becomes the cache writer for any insights / mood sub-page that mounts it without the dashboard parent having fetched first. No payload-shape change — the chart already typed its response as `MoodAnalyticsData` which matches the dashboard's `{ entries, summary }` shape byte-for-byte. --- src/components/charts/mood-chart.tsx | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/components/charts/mood-chart.tsx b/src/components/charts/mood-chart.tsx index 9522bafde..c4b097be5 100644 --- a/src/components/charts/mood-chart.tsx +++ b/src/components/charts/mood-chart.tsx @@ -2,6 +2,7 @@ import { useQuery } from "@tanstack/react-query"; import { useAuth } from "@/hooks/use-auth"; +import { queryKeys } from "@/lib/query-keys"; import { ResponsiveContainer, ComposedChart, @@ -312,8 +313,22 @@ export function MoodChart({ const displayTitle = title ?? t("charts.mood"); + // v1.4.40 W-RSC — align the chart's queryKey with the dashboard's + // `useQuery({ queryKey: queryKeys.moodAnalytics() })` call against the + // same `/api/mood/analytics` endpoint. Pre-fix the chart fetched its + // own copy under `["mood-chart-data"]` (audit C1) — TanStack treated + // the two keys as separate cache slots and the cold-mount dashboard + // fired the request twice (once at `app/page.tsx:291`, once here on + // the chart's first render). The dedup eliminates a ~22 KB round-trip + // and frees one pg pool slot per cold mount. + // + // `staleTime: 60_000` matches the dashboard's `DASHBOARD_QUERY_OPTS` + // so a route swing back to the dashboard within a minute keeps the + // cache fresh; the chart's own subscription becomes the cache writer + // for any insights / mood sub-page that mounts the chart without the + // dashboard parent having fetched first. const { data, isLoading } = useQuery({ - queryKey: ["mood-chart-data"], + queryKey: queryKeys.moodAnalytics(), queryFn: async (): Promise => { const res = await fetch("/api/mood/analytics"); if (!res.ok) throw new Error("Failed to fetch mood analytics"); @@ -321,6 +336,8 @@ export function MoodChart({ return json.data as MoodAnalyticsData; }, enabled: isAuthenticated, + staleTime: 60_000, + refetchOnWindowFocus: false, }); const chartData = useMemo((): ChartDataPoint[] | undefined => {