/) production latencyProduction slowness on / comes from a client-only home page that waits for NextAuth session, then fires four separate /api/* GETs before the shell leaves loading. On Vercel + remote MongoDB that often means four serverless cold starts and four DB handshakes. Highest-impact fix: server-fetch initial payload (match dashboard/page.tsx) or a single bootstrap API; align Vercel + Atlas region; measure before micro-optimizing queries.
Users report high latency when opening / in production. The page feels slow on cold load and sometimes on return visits (API routes are NetworkOnly in the PWA — by design for shared-device safety).
| Layer | Path | Role |
|---|---|---|
| Home page | src/app/(main)/page.tsx | "use client"; useAppData hook |
| Session gate | src/components/navigation/AppShell.tsx | Skeleton until useAuth().isLoading |
| Auth | src/components/auth/AuthContext.tsx | useSession() → blocks data fetch |
| API client | src/lib/utils/api-client.ts | Four fetch calls |
| Routes | src/app/api/categories, bank-accounts, transactions, transactions/category-month-totals | Each via apiHandler → connectDB + getUserData() |
| PWA | next.config.mjs | /api/* GET = NetworkOnly (no SW cache) |
| Reference pattern | src/app/(main)/dashboard/page.tsx | RSC + Promise.all + Suspense (faster pattern) |
| Client cache | src/lib/utils/client-cache.ts, transactions-cache.ts | localStorage cold paint; repeat visits only |
| # | Endpoint | Purpose |
|---|---|---|
| 1 | /api/categories | Category list |
| 2 | /api/bank-accounts | Account cards |
| 3 | /api/transactions?limit=10&lean=true&sort=… | Recent 10 transactions |
| 4 | /api/transactions/category-month-totals?startDate&endDate&… | Month aggregates for category rows |
Static (1+2) and dynamic (3+4) start only after user is set. isLoading stays true until both staticData and transactions exist (monthly totals use monthlyPending separately).
Refactor / like the dashboard:
Promise.all, one connectDB, one auth()).HomeClient for modals, filters, outbox, optimistic merges.Why: Data can stream in the first HTML instead of after JS + session + 4 round-trips. Often 1–3s faster on cold production loads.
GET /api/home/bootstrap returning:
{
"bankAccounts": [],
"categories": [],
"transactions": [],
"monthlyCategoryTotals": []
}
One serverless invocation, one DB connection, one auth check. Keep granular routes for filters and pagination.
Why: Reduces cold-start multiplication from 4 → 1 on Vercel.
Verify in Vercel + MongoDB Atlas:
maxPoolSize / minPoolSize as needed).connectDB caches per function instance (src/lib/mongodb.ts), but each parallel route on a cold instance can still pay connect once.
Middleware already protects routes (src/middleware.ts). Client still waits on /api/auth/session before fetching.
Options:
/ can fetch immediately.(main) layout for authenticated users.Session is JWT (auth.config.ts — no DB read per session), but network latency to /api/auth/session remains.
useLayoutEffect, when both static + tx cache hit, set isLoading: false immediately (today it clears in a later useEffect — possible skeleton flash).monthlyPending skeleton while bank accounts + tx list paint from cache.setTransactions(null) if cache exists for the new hash (already intended in pwa-performance skill).limit: 10, lean: true — good; index { userId: 1, date: -1, isDeleted: 1 } on transactions.getCategoryMonthTotals: aggregation over all month transactions — can dominate if history is large. Consider pre-aggregated monthly summaries on write, or ensure $match on date is selective early in the pipeline.Modals already use dynamic(..., { ssr: false }). Further wins: lazy-load below-the-fold sections; audit TransactionList and icon imports on the critical path. Lower impact than (1)–(3).
| Signal | What to check |
|---|---|
| Browser | Waterfall: /api/auth/session + four APIs on cold load |
| Vercel | Function duration per route; cold-start count |
| MongoDB | Slow queries on getTransactions and getCategoryMonthTotals |
If one API is ~80% of latency → fix that query. If all four are slow only on first hit after idle → cold start × 4.
/api/* GET stays NetworkOnly unless an ADR approves scoped private caching.isLoading behavior for repeat visits.category-month-totals as hot./ keeps session → four cold API routes on many visits. Users see long skeletons on Vercel + remote MongoDB; you risk abandoning the PWA for daily checks because “it feels slow” even when data and auth are correct./Users/mg/Project/personal-finance-notion.cursor/skills/pwa-performance/SKILL.md, .cursor/skills/caching-strategy/SKILL.md/api/* is network-onlyCursor analysis session, 2026-05-23 — production latency on /.