fix(analytics): stop UMAMI_NOT_CONFIGURED returning 409 — caused dev server hangs
Root cause of recurring dev server hangs:
/api/v1/website-analytics threw CodedError('UMAMI_NOT_CONFIGURED') which
rendered as HTTP 409. React Query default-retries on 4xx (we set retry=1
globally), so every page render fired the umami queries → 409 →
retry → 409. Each request queried system_settings to resolve umami
credentials. Six analytics widgets on the /website-analytics page +
two on the dashboard glance tile × 2 (initial + retry) = 16 system_settings
queries on first paint. Combined with React Query refetching on mount,
the postgres pool (max=20) saturated and the server appeared hung.
Fix: return 200 with `{ data: null, notConfigured: true }` instead of
4xx. Not-configured is a steady empty state, not a transient error —
no retry loop. Updated WebsiteGlanceTile (hides itself) and
WebsiteAnalyticsShell (renders configure-umami CTA) to check the new
notConfigured flag.
Also includes from in-flight work: package.json dev script binds
0.0.0.0 so iPhone on LAN can reach the dev server, and BrandedAuthShell
uses fixed/inset-0 + flex to lock the login surface to the viewport so
iOS Safari doesn't rubber-band-scroll the card.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -104,9 +104,14 @@ export const GET = withAuth(
|
||||
}
|
||||
|
||||
// `data === null` from the service means Umami isn't configured for
|
||||
// this port - surface that explicitly so the UI can render a
|
||||
// "configure your credentials" empty state instead of a chart.
|
||||
if (data === null) throw new CodedError('UMAMI_NOT_CONFIGURED');
|
||||
// this port. Return 200 with `data: null` + the explicit
|
||||
// `notConfigured: true` flag so the UI renders a "configure your
|
||||
// credentials" empty state. **Do not throw** — a 409 here would
|
||||
// trigger React Query's default retry loop, and every retry fires
|
||||
// a system_settings lookup → pool saturation → server hang.
|
||||
if (data === null) {
|
||||
return NextResponse.json({ metric, range, data: null, notConfigured: true });
|
||||
}
|
||||
|
||||
return NextResponse.json({ metric, range, data });
|
||||
} catch (err) {
|
||||
|
||||
Reference in New Issue
Block a user