whisper-money/resources/js/components
Víctor Falcón ae81e20a66
perf(dashboard): optimize query performance and eliminate redundant requests (#146)
## Why

### Problem

The dashboard page takes ~4 seconds to load for users with many balance
records. Profiling revealed 29 queries across the initial page load + 3
separate API calls, a 576 KB wasted payload from unused bank records,
and a critical 3.7s bottleneck in `BalanceLookup` correlated subqueries.

## What

### Changes

**Query optimizations:**
- Replace correlated `MAX()` subqueries in `BalanceLookup` with
derived-table `joinSub` pattern — **48x faster** (3,693ms → 77ms) on
accounts with thousands of balance records
- Replace `whereHas` (EXISTS subqueries) with JOINs in
`DashboardAnalyticsController` and `CashflowAnalyticsController` — ~3x
faster per query
- Cache encryption check results in `HandleInertiaRequests` middleware
to avoid 2 duplicate queries per request

**Payload & request reduction:**
- Remove dead `banks` query from `DashboardController` (2,365 records,
576 KB never used by frontend)
- Remove duplicate `categories` and `accounts` queries already provided
by middleware shared props
- Consolidate 3 separate `fetch()` API calls into Inertia v2
`Inertia::defer()` props grouped under `'dashboard'` (single follow-up
request with skeleton fallbacks)

**Frontend:**
- Replace `useDashboardData` fetch hook with `usePage()` props +
`<Deferred>` components
- Convert `CashflowSummaryCard` from internal fetch to prop-based
- Use `router.reload({ only: [...] })` for balance update refetch

### Performance summary

| Metric | Before | After |
|--------|--------|-------|
| Initial page queries | 16 | 12 |
| Follow-up HTTP requests | 3 separate API calls | 1 Inertia deferred |
| BalanceLookup time | 3,693ms | 77ms |
| Wasted payload | 576 KB | 0 |

## Verification

### Tests

All 633 feature tests pass, including 40 dashboard/cashflow-specific
tests.
2026-02-24 08:43:48 +01:00
..
accounts feat: investment benefits — show gains/losses on investment accounts (#140) 2026-02-23 13:59:10 +01:00
automation-rules feat: Integrate EnableBanking as open banking provider (#106) 2026-02-12 09:09:28 +01:00
budgets feat: Add 'Today' marker on budget spending chart (#134) 2026-02-19 11:48:18 +01:00
cashflow fix(cashflow): prevent breakdown cards overflow on mobile (#139) 2026-02-20 11:22:05 +01:00
categories feat: Integrate EnableBanking as open banking provider (#106) 2026-02-12 09:09:28 +01:00
charts fix(charts): use settings popover for chart controls on mobile (#137) 2026-02-19 16:53:00 +01:00
dashboard perf(dashboard): optimize query performance and eliminate redundant requests (#146) 2026-02-24 08:43:48 +01:00
icons Subscriptions (#15) 2025-12-06 19:09:56 +01:00
labels feat: Integrate EnableBanking as open banking provider (#106) 2026-02-12 09:09:28 +01:00
landing feat: Spanish localization (#74) 2026-02-08 11:58:08 +01:00
onboarding feat: Decrypt encrypted transactions on key unlock (#123) 2026-02-16 10:37:43 +01:00
open-banking feat: Add Bitpanda exchange integration (#132) 2026-02-19 09:26:31 +01:00
partials fix: Discord link 2026-02-18 13:00:30 +01:00
shared feat: Spanish localization (#74) 2026-02-08 11:58:08 +01:00
transactions Fix horizontal scroll on transactions table (#127) 2026-02-17 08:45:07 +01:00
ui feat: Add multi-currency conversion for net worth charts (#138) 2026-02-20 10:45:23 +01:00
alert-error.tsx Set up a fresh Laravel app 2025-11-07 12:01:36 +00:00
app-content.tsx Set up a fresh Laravel app 2025-11-07 12:01:36 +00:00
app-logo-icon.tsx Automated rules labels (#30) 2025-12-15 12:11:55 +01:00
app-logo.tsx Add animated logo icon that transitions based on encryption key state 2025-12-12 11:24:42 +01:00
app-mobile-nav.tsx Mobile design (#17) 2025-12-08 15:43:09 +01:00
app-shell.tsx Set up a fresh Laravel app 2025-11-07 12:01:36 +00:00
app-sidebar-header.tsx feat: Decrypt encrypted transactions on key unlock (#123) 2026-02-16 10:37:43 +01:00
app-sidebar.tsx Fix mobile bottom nav alignment for 5 items (#81) 2026-01-27 19:02:38 +01:00
appearance-dropdown.tsx feat: Spanish localization (#74) 2026-02-08 11:58:08 +01:00
appearance-tabs.tsx feat: Spanish localization (#74) 2026-02-08 11:58:08 +01:00
bank-logo.tsx feat: Integrate EnableBanking as open banking provider (#106) 2026-02-12 09:09:28 +01:00
breadcrumbs.tsx feat: Spanish localization (#74) 2026-02-08 11:58:08 +01:00
delete-user.tsx feat: Spanish localization (#74) 2026-02-08 11:58:08 +01:00
encrypted-text.tsx fix: make encryption key storage SSR-safe to prevent 502 errors 2025-12-08 17:13:45 +01:00
encryption-key-button.tsx feat: Spanish localization (#74) 2026-02-08 11:58:08 +01:00
heading-small.tsx Add Budgeting Feature to Track and Manage Spending (#36) 2026-01-21 15:25:50 +01:00
heading.tsx Set up a fresh Laravel app 2025-11-07 12:01:36 +00:00
icon.tsx Set up a fresh Laravel app 2025-11-07 12:01:36 +00:00
input-error.tsx Set up a fresh Laravel app 2025-11-07 12:01:36 +00:00
nav-footer.tsx feat: Spanish localization (#74) 2026-02-08 11:58:08 +01:00
nav-main.tsx feat: Spanish localization (#74) 2026-02-08 11:58:08 +01:00
nav-user.tsx Format + Open transactions on row click 2025-12-08 15:58:50 +01:00
sync-status-button.tsx feat: Spanish localization (#74) 2026-02-08 11:58:08 +01:00
text-link.tsx Set up a fresh Laravel app 2025-11-07 12:01:36 +00:00
two-factor-recovery-codes.tsx feat: Spanish localization (#74) 2026-02-08 11:58:08 +01:00
two-factor-setup-modal.tsx feat: Spanish localization (#74) 2026-02-08 11:58:08 +01:00
unlock-message-dialog.tsx Remove encryption from bank account names (#104) 2026-02-09 14:15:26 +01:00
user-info.tsx feat: Replace user avatar with Facehash faces (#86) 2026-02-01 11:33:09 +01:00
user-menu-content.tsx feat: Spanish localization (#74) 2026-02-08 11:58:08 +01:00