Skip to content

fix: improve dashboard Core Web Vitals (LCP, FCP, CLS) - #58

Merged
fsousac merged 22 commits into
mainfrom
develop
Aug 21, 2026
Merged

fsousac merged 22 commits into
mainfrom
develop

Conversation

@fsousac

@fsousac fsousac commented Jul 31, 2026

Copy link
Copy Markdown
Owner

Summary

Vercel Speed Insights showed /dashboard as the only route failing Core Web Vitals in production (LCP ~4.8s, FCP ~4s, CLS 0.2 "Needs Improvement") while every other route was "Great". Root-caused to four issues isolated to that route and fixed them:

  • Query fan-out: fetchDashboardTransactionSets fired 6 listTransactions calls per load, 2 pairs of which hit the exact same Supabase query. Extracted a shared fetchTransactionRowsForOptions fetch step so distinct date ranges are fetched once and all 6 views are derived from the same rows in memory.
  • Unnecessary static bundle: the 3 recharts-based chart components were statically imported into the dashboard server page (only route using them). Switched to next/dynamic so the chart bundle is code-split out of the initial JS.
  • CLS from a mismatched Suspense fallback: the loading skeleton had 1 chart row while real content rendered 3, causing a layout jump on hydration. Split rendering into two Suspense boundaries (fed by the same un-awaited data promise, per Next.js's parallel-streaming pattern) each with a fallback matching its real content height.
  • QuickActions blocked on data it doesn't need: it renders static links with no props, but was gated behind the same Suspense boundary as the data-dependent charts. Moved it to render synchronously.

Also audited Supabase connection practices per request: confirmed PostgREST-over-HTTP (no connection-pool concern), userContext reused across the fan-out (no repeated auth calls), and that the double getClaims()+getUser() check in getUserContext is intentional defense-in-depth, not redundant. Flagged (not fixed, out of scope) that calculate_total_saved RPC does an unbounded full-history scan, called 2x per load — fine today, will need revisiting if transaction history grows very large.

As a side effect of touching lib/finance/transactions.ts, fixed 3 pre-existing wall-clock-dependent test flakes (UTC-vs-local and month-end clamping edge cases) in transactions-reports.test.ts, transactions-queries.test.ts, and transaction-form.test.tsx.

Type of Change

  • Bug fix
  • Feature
  • Documentation
  • Security hardening
  • Database migration
  • Refactor

Testing

  • npm run lint
  • npm run build
  • npm audit --audit-level=moderate
  • Manual testing completed

Supabase / Database

  • No database changes
  • Migration added under supabase/migrations
  • RLS impact reviewed

Security Checklist

  • No secrets committed
  • Server Action inputs are validated
  • User-owned records are scoped by authenticated user ID
  • user_metadata is not used for authorization decisions

Notes

Net diff vs main: app/dashboard/page.tsx, lib/finance/transactions.ts, and the 3 associated test files. No behavior change for /transactions or /payments — listTransactions's public signature is untouched, only fetchDashboardTransactionSets was refactored internally.

@fsousac fsousac self-assigned this Jul 31, 2026
@vercel

vercel Bot commented Jul 31, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
dragg-finance Ignored Ignored Aug 21, 2026 1:49am

@fsousac fsousac changed the title Develop fix: improve dashboard Core Web Vitals (LCP, FCP, CLS) Jul 31, 2026
Comment thread lib/crypto/field-encryption.ts Fixed
@fsousac
fsousac merged commit f1a89fc into main Aug 21, 2026
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants