Compras minus devoluciones, one figure per currency, excluding Tasa
Cero anchors (their cuotas are what count). Tooltip explains the math.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Violet 'Tasa Cero'/'Cuota' badges (anchor amount struck through like
deferred), convert/edit action on CC purchases with a live cuota
preview, and a Financiamientos page mirroring the bank's tab (progress,
monto cuota, saldo inicial/faltante, totals).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
manifest.webmanifest with the existing icons, apple-touch-icon, and SW
registration at startup. The old sw.js was a self-unregistering cleanup
stub — meaning serviceWorker.ready never resolved and web push has been
silently dead; the new worker handles push display and notification
clicks, and makes the app installable.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New Planificador page: the current savings pace (prefilled from the
live budget projection's monthly net, editable) versus a scenario with
extra monthly savings, both compounded at a configurable annual rate
over a 1-40 year horizon — side-by-side totals and growth curves.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Analytics gains a 90-day USD/CRC buy/sell chart from the existing
history endpoint (wishlist: rate history). Pensiones gains a
Calculadora de Aporte: fund + target amount + target age → required
monthly contribution via the annuity future-value formula, using the
fund's live balance and configured rate (wishlist: contribution
calculator).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
One chevron component now drives year/month stepping in Budget and
Proyecciones (UX-03). Jumping from Proyecciones to a Budget month shows
a back affordance (UX-22). Water meters can be named (Casa, Cochera…)
via a settings-persisted dialog; the chart legend uses the names
(UX-24).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Every dict-returning route the SPA consumes now declares a response
model (auth, bulk, sync-status, notifications). api-types.gen.ts is
generated from app.openapi() via openapi-typescript, and the 22 hand-
written read interfaces in api.ts are now aliases onto the generated
schemas — backend schema drift becomes a typecheck failure, and CI
regenerates the file and fails the deploy if it's stale. The aliasing
immediately caught two real drifts: RecurringItemType was missing
SAVINGS, and raw_charges (untyped JSON column) is now explicitly
shaped at the boundary.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Per-fund contribution and annual-rate assumptions are now editable in a
Supuestos dialog on Pensiones and persisted server-side in UserSettings
so projections survive devices and reloads; saldo inicial keeps coming
from the latest snapshot (UX-12). The recurring-item dialog confirms
before discarding unsaved edits, with the dirty baseline computed from
the same values the populate effect sets (UX-06). Empty transaction
lists now offer an inline add button (UX-14).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Transactions gain a checkbox column with select-all; a bulk bar offers
assign-category, defer/restore and delete (confirmed) via the new bulk
endpoint, with toasts and invalidation. The paste-import modal now
lists each skipped duplicate with the matched existing row and offers
'Importar duplicados de todos modos' — re-importing ONLY the skipped
lines so first-pass rows can't double-import (UX-20). Two real fixes
found en route: the mobile list ignored undo-pending deletes and used
en-US dates; the desktop date column also lost its en-US stray. Note:
UX-11 (no mobile layout) was a false positive — a card layout already
existed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fund visibility toggles and the header privacy/theme buttons expose
aria-pressed (FE-16); deferred transactions render struck-through and
muted so the state is visible at a glance (UX-05); the balance-override
input documents its keyboard contract (UX-21). The Budget CSV button
rides in the transactions tab header.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
After confirming a delete the row disappears immediately but the API
call waits 5 seconds behind a Deshacer toast action; undo restores the
row without any server round-trip. A failed commit restores the row
and reports the error.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
GET /api/v1/transactions/export streams a CSV (optional source/type/
date filters), cookie-authenticated so window.open downloads work.
Buttons on the Budget transactions tab (all) and Salarios (SALARY
only). Quoting and category resolution covered by tests.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The n8n flows fail invisibly from the app's perspective (review UX-17,
the top trust gap). /api/v1/sync-status derives last-received + cadence
thresholds for BAC, salary, municipal, pensions and exchange rate from
existing data — no n8n integration needed. New Sincronización page
shows per-source freshness and a hint to check n8n; the sidebar item
gets an amber dot when any source is stale. Verified live against the
dev DB (correctly flags its stale BAC data at 43 days).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
src/lib/dates.ts is the single source for month names and date
formatting; the three per-page month arrays are gone (with an
off-by-one guard — the shared array is 1-indexed). formatDate and the
Analytics chart tooltips now speak es-CR, Analytics headings are
Spanish, and the cycle selector says 'Todo el período' (UX-19, FE-17,
UX-07).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A thrown fetch in the auth probe is a network failure, not a 401 — it
now retries once before treating the user as logged out, and logs the
real cause (FE-15). Theme and privacy state initialize lazily from
localStorage so neither the wrong theme nor unmasked sensitive values
flash on reload (FE-07). The CopilotKit orphan-tool-call repair logs
when it has to skip instead of failing silently (FE-11).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Transaction create/update/delete now confirm success or failure with a
toast (UX-01); save failures always show a user-visible message instead
of console-only (FE-06, with a typed error guard replacing the any
cast). Clearing a balance override — which recalculates every following
month — now requires confirmation like the other destructive actions
(UX-15).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Every page now goes through TanStack Query with cancellation,
placeholder data on filter changes, and a visible ErrorState with retry
instead of console.error/silent-empty rendering (FE-02, UX-02).
Analytics keeps the trend query on its own key so cycle changes don't
refetch it. Pensions/Servicios upload-triggered refreshes are bounded
by the api-level 30s timeout (FE-05); pension upload results cap at 10
rows with an overflow note (FE-19). Note: the Pensions ROI fallback
already guarded short chart data — FE-04 was already handled.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
QueryClientProvider (30s staleTime, 1 retry) + Sonner Toaster at the
root. api.ts gains AbortSignal support and a default 30s timeout
(FE-24); query cancellation kills the stale-response races (FE-01,
FE-03). useBudget is now queries + mutations with targeted ['budget']
invalidation and success/error toasts on every mutation (ARCH-13,
UX-01); month navigation keeps the previous month visible while
fetching. Budget's transaction list is a cancellable query with
placeholder data; deferred-toggle gets feedback (UX-05); both panels
render a shared ErrorState with retry instead of failing silently.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- ui/chart.tsx: recharts 3 stopped exposing tooltip/legend content props
on its public types; declare the ChartPayloadItem shape we consume
- base-ui Select onValueChange passes string|null: guard null in
BillingCycleSelector, PasteImportModal, TransactionModal
- type the untyped api.get calls (cycles, categories)
- push-notifications: back the VAPID key with an explicit ArrayBuffer
so it satisfies BufferSource under TS 5.9
Unblocks gating CI on pnpm typecheck.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Docker build's unpinned corepack resolved a newer pnpm that hard-
errors on unreviewed dependency build scripts (ERR_PNPM_IGNORED_BUILDS),
failing deploy task 80. Pin packageManager to the locally-verified
pnpm 10.33.1 and review the build scripts: @swc/core and esbuild are
approved (vite needs their native binaries), @scarf/scarf is ignored.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Every response gets X-Frame-Options, X-Content-Type-Options, and
Referrer-Policy (SEC-07/FE-08). Backend proxy failures now return a
logged 502 instead of an opaque uncaught error (FE-23).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
In production the browser talks to the Hono server, which only proxied
/api/copilotkit/*. All other /api/* requests hit the SPA static fallback
and got index.html back. Forward /api/v1/* and /api/auth/* to BACKEND_URL.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Runner stage was invoking `tsx server.ts` via sh, which doesn't
have node_modules/.bin on PATH, so the container crash-looped with
"tsx: not found" (502 at the edge). Use the absolute binary path
instead.
Also caps the Vite build's V8 heap to 1.5 GB so a future build on
the 4-core / 8 GB VPS can't OOM-kill neighbouring services.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Repoints imports at the relocated lib/api and src/contexts modules,
and refreshes Layout + Login alongside the rest of the migration.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Tailwind variants like data-horizontal and group-data-horizontal
never match the data-orientation=horizontal attribute Base UI
emits, so the flex layout collapsed and TabsList stretched
vertically. Switch to data-[orientation=...] selectors that
actually fire.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the blank flash on the budget detail tab with skeleton
placeholders that mirror the final card layout, so the page no
longer shifts when the API returns.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wires CopilotKit v2 chat into the SPA as the Asistente page,
declares a render_spending_summary action backed by a custom
SpendingSummaryCard, and configures static suggestions shown
before the first message.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Backend now exposes /api/auth/login + /api/auth/logout setting an
httpOnly ws_token cookie, and get_current_user accepts either the
cookie (SPA) or a Bearer token (n8n/CLI). AuthContext probes the
cookie via /api/v1/auth/me. Dockerfiles and compose files updated
for the new agent service deps and CopilotKit dev sidecar.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the Next.js scaffold with a Vite SPA paired with a Hono
sidecar that hosts the CopilotKit runtime and proxies AG-UI traffic
to the MAF backend. Adds dev/prod Dockerfile, .dockerignore,
.gitignore, pnpm workspace config, and updates entrypoints
(main.tsx / App.tsx / index.css / index.html) plus the service
worker accordingly.
Server middleware reconciles MAF MESSAGES_SNAPSHOT id mismatches
so post-tool-call assistant text doesn't render twice, suppresses
duplicate text emitted alongside render tools, and strips OpenAI
training-token leaks from streamed deltas.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Removes Dashboard / Transactions / Transfers pages, the section
configuration UI, the legacy useSettings hook, and the standalone
PrivacyContext/ThemeContext modules. Privacy/theme contexts now live
under src/contexts/ and the API helper / push-notifications module
move under src/lib/.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Salary/deposit transactions were showing in the "Efectivo y
Transferencias" tab on the Budget page with a negative sign,
which is confusing since that view is for expenses only.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Ahorro was already deducted from gross salary so displaying it in
budget projections was misleading. This removes the Ahorro card,
summary line, Proyecciones column, and Ahorro Anual card from the UI,
and strips all savings fields from budget API responses.
Adds SALARY TransactionType so salary deposits can be distinguished
from generic DEPOSITO transfers. When a SALARY transaction arrives,
the system auto-increments MEMP and MPAT savings account balances
(+200K CRC each) once per month via an idempotent accrual log.
New CRUD endpoints at /api/v1/savings-accrual/ allow manual correction
of the accrual history. Feb+Mar 2026 are seeded as historical baseline.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fix SQLAlchemy case() import in monthly-trend endpoint. Add
data-sensitive attributes to Analytics charts and tables for privacy
blur. Add scripts/sync-db.sh for one-click prod-to-local PostgreSQL
sync. Remove SQLite artifacts from gitignore.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Drop axios dependency in favor of a lightweight fetch-based client
that preserves the same { data: T } interface, keeping all 25
consumer files unchanged.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds deferred_to_next_cycle flag to transactions for billing cycle
bleed-over handling. Overhauls budget projection engine and refreshes
Budget page with improved monthly detail and transaction columns.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Both water consumption and charge trend charts now have clickable legends
to show/hide individual series
- Hidden series appear dimmed in the legend
- Added line chart showing charge evolution over time (one line per charge type)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Upload panel now accepts multiple PDFs at once (drag-drop or file picker),
shows a file queue with individual remove buttons, and displays per-file
results after processing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Eye/EyeOff icon next to theme toggle. Persists in localStorage.
Applies CSS blur to all elements marked with data-sensitive attribute
across Dashboard, Budget, Pensions, Salarios, and Transactions pages.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The bank website puts field labels and amounts on separate lines.
Parser now handles both inline and split formats.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>