# Poweruser Review — WealthySmart > Hat: Daily power user of the app + senior product engineer. Focus: real user journeys, feedback loops, data trust, consistency, missing features. ## Executive Summary WealthySmart has solid fundamentals: clean routing, consistent UI patterns, bilingual support, and thoughtful features like pension projections and municipal receipt tracking. But daily use exposes friction: **no success/error feedback after mutations** (did my delete work?), no error recovery anywhere (failed loads look like empty data), three different month-navigation patterns across modules, a search box that silently does nothing for non-credit-card sources, and — most corrosive to trust — **silent n8n parse failures** that leave invisible gaps in transaction history with no reconciliation view. The data tables are dense and not mobile-adapted. The Asistente is pleasant but read-only and ephemeral. None of these are deep architectural problems; they are a backlog of S/M-effort polish items plus two larger trust-building features (sync status, import review). ## What Works Well - **Navigation & layout** — well-organized sidebar (General, Finanzas, Servicios); smooth mobile menu. - **Strong typed data model** on the client — comprehensive interfaces across all modules. - **Privacy mode** — `data-sensitive` blur with an accessible header toggle. Great for screen-sharing. - **Thoughtful finance features** — pension projections with adjustable assumptions, recurring items with frequency + override logic, billing-cycle awareness, deferred transactions. - **Accessibility baseline** — focus-visible rings, aria-labels, disabled-state management. - **Charts** — Recharts configured properly with tooltips/legends across Analytics, Proyecciones, Pensions, ServiciosMunicipales. - **Import result summaries** — paste-import and PDF upload report imported/updated/duplicate counts. ## Findings ### UX-01 | No success feedback after mutations — High **Location:** `Budget.tsx:180–183`, `RecurringItemsManager.tsx:57–69`, `TransactionList.tsx:64–74`, Pensions upload handlers **Evidence:** Mutations call `onRefresh()`/`refresh()` with zero confirmation — no toast, no inline message. `TransactionList.tsx:68` deletes then refreshes silently. **User impact:** "Did the delete go through?" Users infer success from list churn — anxiety for irreversible actions. **Recommendation:** Add a toast layer (Sonner) and emit success/error on every mutation. Effort: **M** (library + sweep). ### UX-02 | No error recovery flow anywhere — High **Location:** `Analytics.tsx:84–94`, `ServiciosMunicipales.tsx:198–211`, `PasteImportModal.tsx:42–46`, `Budget.tsx:44–76` **Evidence:** `.catch(console.error)` or silent catches; Budget's `fetchTransactions` has no error handling at all. **User impact:** API failure is indistinguishable from "no data." No retry affordance. **Recommendation:** Standard `loading → error(retry) → data/empty` states on every page. Effort: **M** (trivial if TanStack Query lands first). ### UX-03 | Three different month/date-navigation patterns — Medium **Location:** `Budget.tsx` + `Proyecciones.tsx` (chevrons), `Analytics.tsx` (`BillingCycleSelector` dropdown), `Pensions.tsx` (fixed last-12-months, no navigation) **User impact:** Inconsistent mental model; Pensions history before 12 months is unreachable. **Recommendation:** One shared period-navigator component; add history browsing to Pensions. Effort: **M**. ### UX-04 | Search silently inert for non-credit-card sources — Medium **Location:** `Budget.tsx:42–43, 164–188` **Evidence:** `txSearch` only feeds CREDIT_CARD queries; on the "Efectivo y Transferencias" tab the visible search box does nothing. **User impact:** Search appears broken. **Recommendation:** Make search work for all sources, or hide the field when inapplicable. Effort: **S**. ### UX-05 | Deferred-transaction toggle gives no feedback — Medium **Location:** `transaction-columns.tsx:68–72`, `TransactionList.tsx:37` **Evidence:** Toggle PATCHes then refetches; no toast, no row styling change beyond a small "Diferida" badge. **User impact:** User can't tell the deferral took effect without hunting. **Recommendation:** Toast on toggle + muted/strikethrough styling on deferred rows. Effort: **S**. (Pairs with ARCH-11: add the field to `TransactionModal` too.) ### UX-06 | Dirty-form dismissal loses data silently — Low **Location:** `RecurringItemDialog.tsx:50–100` **Recommendation:** ConfirmDialog on close when dirty. Effort: **S**. ### UX-07 | "All time" English label in Spanish UI — Low **Location:** `BillingCycleSelector.tsx:52` **Recommendation:** "Todo el período". Effort: **S** (part of the UX-19 locale sweep). ### UX-08 | Login page is bare — Low **Location:** `Login.tsx` **Evidence:** No remember-me, no error differentiation. (Password reset is N/A for a single-user env-configured credential.) **Recommendation:** Low priority; longer cookie life (bounded by SEC-05) already covers persistence. Effort: **S**. ### UX-09 | Upload errors returned by the API are never displayed — Medium **Location:** Pensions upload result rendering **Evidence:** Backend returns `errors: string[]`; UI shows counts only — a failed parse looks like "Import complete, 0 imported." **User impact:** User can't tell *why* an upload failed (wrong file? corrupt PDF?). **Recommendation:** Render `result.errors` in an Alert list. Effort: **S**. ### UX-10 | No undo for destructive operations — Medium **Location:** `TransactionList.tsx:64–74`, RecurringItemsManager delete **Evidence:** ConfirmDialog exists, but post-confirm deletion is immediate and irreversible. **Recommendation:** Toast-with-Undo grace period (delay the API call ~5s), or DB soft-delete + restore endpoint. Effort: **M**. ### UX-11 | Transaction table is poor on mobile — Medium **Location:** `DataTable.tsx:57–80`, `transaction-columns.tsx` **Evidence:** 5+ columns force horizontal scroll at <640px; tiny text. **Recommendation:** Card-stack rendering on small screens (merchant/amount primary; category/bank secondary) or column-visibility tiers. Effort: **M**. ### UX-12 | Pension projections use hardcoded assumptions — Medium **Location:** `Pensions.tsx:76–116` **Evidence:** `FUNDS_DEFAULT` hardcodes `startBalance`, `monthlyContribution`, `annualRate`; `applySnapshots()` updates only `saldo_final`. **User impact:** Retirement projections drift from reality as contributions change. **Recommendation:** Editable per-fund assumptions persisted server-side (settings or a `PensionAssumption` table). Effort: **M**. ### UX-13 | Cycle filter only applies to one of three Analytics charts — Medium **Location:** `Analytics.tsx:71–95` **Evidence:** Category breakdown respects the selected cycle; monthly-trend and daily-spending queries ignore it. **User impact:** User picks a cycle and two charts silently show all-time data. **Recommendation:** Pass cycle params to all three endpoints (backend support needed) or visually scope the selector to the one chart it affects. Effort: **M**. ### UX-14 | Empty states are dead ends — Low **Location:** `Budget.tsx:186`, `Salarios.tsx:157`, `TransactionList.tsx:81` **Recommendation:** `emptyAction` prop rendering an "Add first item" button. Effort: **S**. ### UX-15 | Destructive-action confirmation applied inconsistently — Medium **Location:** `YearlyOverview.tsx:70–72` (clearing a balance override has no confirm; transaction/recurring deletes do) **Recommendation:** ConfirmDialog on every destructive action. Effort: **S**. ### UX-16 | Asistente is read-only with no export — Low **Location:** `Asistente.tsx:56–79` **Evidence:** Only `SpendingSummaryCard` renders; no CSV export, no report download, no chat persistence. **Recommendation:** "Export CSV" on cards; longer-term, persist useful summaries. Effort: **M**. ### UX-17 | n8n parser failures are invisible — High **Location:** Systemic (n8n → API ingestion path); no sync-status surface anywhere in the app **Evidence:** If BAC changes its email format, the n8n flow fails in n8n's own logs; the app just shows a gap in transactions. **User impact:** The core promise — "your finances, automatically tracked" — fails silently. The user discovers missing weeks at month-end close. **Recommendation:** A Sync Status page: last-received timestamp per source (BAC, salary, municipal, pension), expected-cadence warnings ("no BAC email in 7 days"), n8n error visibility. Backend can derive most of this from existing data (`max(created_at) per source`) — no n8n integration needed for v1. Effort: **M** for derived v1, **L** for full n8n integration. ### UX-18 | No preview when editing recurring items — Medium **Location:** `Budget.tsx:115–201`, `useBudget.ts` **Evidence:** Changing frequency MONTHLY→QUARTERLY shows impact only after save. **Recommendation:** Before/after monthly-total preview in the dialog. Effort: **M**. ### UX-19 | Mixed-language dates and labels across the app — Low (but pervasive) **Location:** `format.ts:19–21` ('en-US'), `Budget.tsx:12–15` (Spanish `MONTH_NAMES`), `Salarios.tsx:42–49` ('en-US'), `ServiciosMunicipales.tsx:54–57` (`MONTH_NAMES_ES`) **Evidence:** Three separate month-name implementations in two languages; `formatDate` returns English. **Recommendation:** One locale-aware date/format module (`Intl` with `es-CR`), delete the per-page constants. Effort: **M** (sweep). ### UX-20 | Duplicates are counted but never reviewable — High **Location:** Import flows (paste-import, PDF upload) — UI shows `duplicates: 3` with no detail **Evidence:** No way to see *which* rows were skipped as duplicates or to override a false-positive dedup. **User impact:** Data-integrity trust gap; a false-positive dedup silently loses a real transaction. **Recommendation:** Import-review response listing skipped rows (merchant/date/amount + matched existing row), with a "import anyway" override. Effort: **L** (backend detail + UI). ### UX-21 | Balance override input has no sanity check — Low **Location:** `YearlyOverview.tsx:55–72` **Recommendation:** Show "Calculated: ₡X" beside the input; warn on large deviation. Effort: **S**. ### UX-22 | Proyecciones → Budget navigation is one-way — Low **Location:** `Proyecciones.tsx:96–99` **Recommendation:** Back affordance/breadcrumb when arriving from Proyecciones. Effort: **S**. ### UX-23 | Chat cards are ephemeral — Low **Location:** `Asistente.tsx`, `ChatCards.tsx` **Evidence:** Refresh loses everything; no save/share affordance on cards. **Recommendation:** Export/copy button on `SpendingSummaryCard`. Effort: **S**. ### UX-24 | Water-meter chart uses raw meter IDs — Low **Location:** `ServiciosMunicipales.tsx:48–52` **Evidence:** Legend shows '7335'/'7345'/'9345'; hardcoded colors; unknown meters fall back to one default color. **Recommendation:** User-editable meter labels ("Casa", "Cochera") in settings. Effort: **S**. ### UX-25 | Sticky header/sidebar scroll jank — Low **Location:** `Layout.tsx:110, 153` **Recommendation:** Consistent scroll container (`overflow-y-auto` on main). Effort: **S**. ## Feature Wishlist (prioritized) 1. **Transaction search & filtering everywhere** — full-text on merchant/notes/reference; date-range, amount-range, category filters. *High impact, M.* 2. **Bulk transaction actions** — multi-select → bulk re-categorize / defer / delete-with-undo. Statement import currently means 50 one-by-one edits. *High impact, M.* 3. **Sync status & reconciliation view** — last import per source, cadence warnings, failed-parse visibility, duplicate review (UX-17 + UX-20 together). *High impact, L. This is the single biggest trust feature.* 4. **CSV export** — transactions, salarios, pensions; for taxes/accountant. *Medium impact, M.* 5. **Budget override history & revert** — when/why an override was set. *Medium impact, S.* 6. **What-if scenario planner** — "save ₡50k more/month" against the 5-year projection. *Medium impact, M.* 7. **Exchange-rate history & per-date override** for reconciling old statements. *Medium impact, S.* 8. **PWA polish** — installable, offline-readable balances. *Medium impact, L.* 9. **Pension contribution calculator** — "reach ₡X by age Y." *Low impact, S.* 10. **Per-month recurring-item skip/override** — e.g., reduced December salary. *Low impact, S.* **Effort key:** S < 4h, one component. M = 4–16h, may need a backend endpoint. L = 16h+, schema or multi-component work.