Commit Graph

66 Commits

Author SHA1 Message Date
Carlos Escalante
3a357e4f0b Cap paste-import payload at 1 MB (ARCH-05)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 19:13:32 -06:00
Carlos Escalante
b4123703ef Rate-limit logins, constant-time creds, pin CORS, secure cookie
Both login endpoints now share verify_admin_credentials (hmac
compare_digest, SEC-02) and a 5/min/IP sliding-window rate limit that
returns 429 with Retry-After (SEC-03). CORS is pinned to the prod
domain and localhost dev origins instead of '*' (SEC-04). The session
cookie's Secure flag is driven by COOKIE_SECURE instead of hardcoded
false (SEC-08).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 19:13:19 -06:00
Carlos Escalante
15ea1ef4c2 Fail fast on missing or weak auth secrets; 7-day tokens
SECRET_KEY, ADMIN_USERNAME, and ADMIN_PASSWORD no longer have working
defaults: the backend refuses to boot if they are unset, default, or
weak (SEC-01). Token expiry drops from 30 to 7 days (SEC-05). New
COOKIE_SECURE (default true) and CORS_ORIGINS settings. Dev compose now
sources credentials from .env with required-var errors instead of
hardcoding them (ARCH-14); .env.example documents the template.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 19:13:19 -06:00
Carlos Escalante
5c265129e8 Add five-hat codebase review and phased improvement plan
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 19:13:19 -06:00
Carlos Escalante
20b4ad102d Wrap transaction_type in col() for notin_ filter
All checks were successful
Deploy to VPS / deploy (push) Successful in 12s
SQLModel enum columns need col() to expose SQLAlchemy operators like
notin_. Without it the agent tool raised at query build time and the
chat card flashed away.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 22:58:28 -06:00
Carlos Escalante
ec716e698f Exclude SALARY and DEPOSITO from agent recent-transactions tool
All checks were successful
Deploy to VPS / deploy (push) Successful in 13s
The 'last N transactions' answer was including salary deposits, which the
user reads as expense activity. Filter income types out at the query level.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 22:55:53 -06:00
Carlos Escalante
f556c392fb Pass OPENAI_API_KEY and AGENT_MODEL to prod from Gitea secrets
All checks were successful
Deploy to VPS / deploy (push) Successful in 13s
Backend was hitting OpenAI with no key (401) because the deploy workflow
never wrote OPENAI_API_KEY into .env.prod. Add it plus AGENT_MODEL.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 22:49:55 -06:00
Carlos Escalante
aa4bb6512f Proxy /api/v1 and /api/auth from Hono to FastAPI in prod
All checks were successful
Deploy to VPS / deploy (push) Successful in 45s
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>
2026-04-29 22:43:34 -06:00
Carlos Escalante
6b3069eef4 Fix prod backend hostname collision on nginx-prod-network
All checks were successful
Deploy to VPS / deploy (push) Successful in 5s
Frontend joins both wealthysmart-network-prod and nginx-prod-network
(needed for nginx-proxy reverse proxy + TLS). Another container on
nginx-prod-network is named "backend" too (receipts-backend-prod),
so DNS resolved "backend" to a sibling app and the agent endpoint
returned 404. Pin the agent/backend URLs to the unique container
name wealthysmart-backend-prod.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 22:31:16 -06:00
Carlos Escalante
ead8fb8684 Fix prod frontend container: tsx on PATH and cap build heap
All checks were successful
Deploy to VPS / deploy (push) Successful in 5s
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>
2026-04-29 22:21:45 -06:00
Carlos Escalante
097fe9c4cf Point sync-db at old-vps and add A2UI theming notes
All checks were successful
Deploy to VPS / deploy (push) Successful in 1m17s
The production SSH alias is old-vps; the placeholder "production"
alias does not exist. Also captures research findings on theming
the A2UI basic catalog without overriding component internals,
for later reference.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 22:02:58 -06:00
Carlos Escalante
c92bfc66fe Update pages and components for new module paths
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>
2026-04-29 22:02:46 -06:00
Carlos Escalante
cf8b7be778 Fix Tabs orientation selectors
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>
2026-04-29 22:02:33 -06:00
Carlos Escalante
8b3a19b552 Add Skeleton primitive and budget detail loading state
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>
2026-04-29 22:02:22 -06:00
Carlos Escalante
5d5727ec4e Add Asistente chat page with A2UI render tools
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>
2026-04-29 22:02:12 -06:00
Carlos Escalante
140a75f706 Add cookie-based SPA auth and update container plumbing
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>
2026-04-29 22:02:02 -06:00
Carlos Escalante
7f602a67af Add Microsoft Agent Framework assistant with read-only tools
Wires up an OpenAI-backed MAF agent that exposes WealthySmart
data through tool calls (recent transactions, cycle summary,
analytics, pensions). Pulls in agent-framework + AG-UI adapter
+ OpenAI client deps.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 22:01:50 -06:00
Carlos Escalante
5f2a4105f3 Migrate frontend to Vite + Hono CopilotKit runtime
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>
2026-04-29 22:01:40 -06:00
Carlos Escalante
c4768e6912 Drop legacy pages, contexts, and dashboard widgets
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>
2026-04-29 22:01:26 -06:00
Carlos Escalante
9fe17c0607 Drop legacy Next.js + CRA scaffold assets
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 22:01:06 -06:00
Carlos Escalante
98d32df763 Ignore tech_docs and local Claude state
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 21:57:58 -06:00
Carlos Escalante
d4d0f65759 Exclude income transactions from budget transactions list
All checks were successful
Deploy to VPS / deploy (push) Successful in 16s
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>
2026-04-15 19:27:50 -06:00
Carlos Escalante
d929ed6573 Remove Ahorro from budget UI, add SALARY type and savings auto-accrual
All checks were successful
Deploy to VPS / deploy (push) Successful in 23s
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>
2026-04-15 19:13:29 -06:00
Carlos Escalante
94a8a894a6 Convert all currencies to CRC and poll rates every 6h
All checks were successful
Deploy to VPS / deploy (push) Successful in 14s
Budget/transactions/salarios totals summed Transaction.amount directly,
so USD/EUR entries were treated as CRC and effectively disappeared from
the dashboard (the analytics fix in 9a80f2a only covered analytics).
Adds a shared get_converted_amount_expr() helper driven by the full
Currency enum — USD/EUR via ExchangeRate-API, BTC/XMR via CoinGecko —
and wires it into every func.sum(Transaction.amount) site.

Also starts a background task in the FastAPI lifespan that force-refreshes
every currency 4x/day, persisting USD to the DB and updating in-memory
caches for the rest. Failures are swallowed per-currency so a CoinGecko
outage cannot take out USD/EUR, and the last-known rate is always retained.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 17:16:20 -06:00
Carlos Escalante
9a80f2a997 Convert USD and EUR to CRC in analytics endpoints
All checks were successful
Deploy to VPS / deploy (push) Successful in 13s
All three analytics endpoints (by-category, monthly-trend, daily-spending)
now convert foreign currency amounts to CRC using current exchange rates.
EUR/CRC rate derived from ExchangeRate-API (USD-based cross rate).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 20:41:38 -06:00
Carlos Escalante
efe6d88286 Add EUR currency support for international transactions
All checks were successful
Deploy to VPS / deploy (push) Successful in 50s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 20:29:37 -06:00
Carlos Escalante
4da00750a8 Fix migration to use IF NOT EXISTS and Postgres-compatible DEFAULT
All checks were successful
Deploy to VPS / deploy (push) Successful in 13s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 20:14:20 -06:00
Carlos Escalante
792cef5006 Fix analytics case() bug, add privacy mode, add prod DB sync script
All checks were successful
Deploy to VPS / deploy (push) Successful in 28s
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>
2026-04-03 20:10:58 -06:00
Carlos Escalante
78e20f30cb Replace axios with native fetch API wrapper
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>
2026-04-03 20:10:48 -06:00
Carlos Escalante
51c106dc6c Add Proyecciones page with yearly financial projections view
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 20:10:37 -06:00
Carlos Escalante
0fdb5447b7 Add deferred transactions, revamp budget projections and UI
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>
2026-04-03 20:10:23 -06:00
Carlos Escalante
37e04273b9 Add clickable legend toggles and charge trend chart
All checks were successful
Deploy to VPS / deploy (push) Successful in 14s
- 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>
2026-04-02 16:38:30 -06:00
Carlos Escalante
c005956458 Support multi-file upload for municipal receipts
All checks were successful
Deploy to VPS / deploy (push) Successful in 15s
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>
2026-04-02 16:23:14 -06:00
Carlos Escalante
8f775e5531 Add python-dateutil to requirements for production
All checks were successful
Deploy to VPS / deploy (push) Successful in 33s
The municipal receipts endpoint uses dateutil.relativedelta to derive
the billing period (previous month from receipt date).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 16:16:33 -06:00
Carlos Escalante
739a32efd4 Add municipal receipt module and convert navbar to sidebar
All checks were successful
Deploy to VPS / deploy (push) Successful in 58s
- New module: Municipalidad de Belén receipt extraction via pdftotext+regex
  - Backend: MunicipalReceipt + WaterMeterReading models, upload/list/detail/water-consumption endpoints
  - Auto-creates budget Transaction on upload (duplicate-safe via reference)
  - Frontend: ServiciosMunicipales page with summary cards, water consumption bar chart, receipt history, PDF upload
- Convert top navbar to left sidebar with section headers (General, Finanzas, Servicios)
  - Desktop: fixed 220px sidebar, mobile: sheet overlay
  - Grouped nav: Dashboard | Presupuesto, Salarios, Pensiones, Analytics | Municipalidad

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 16:11:51 -06:00
Carlos Escalante
45166f9d20 Add privacy mode toggle to blur sensitive financial amounts
All checks were successful
Deploy to VPS / deploy (push) Successful in 14s
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>
2026-04-01 10:43:50 -06:00
Carlos Escalante
aedf3aa3b0 Fix plus sign showing before negative rendimientos values
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 10:24:58 -06:00
Carlos Escalante
cab4d86b5c Restore MEMP/MPAT in Bank enum for DB compatibility
All checks were successful
Deploy to VPS / deploy (push) Successful in 13s
Existing account rows reference these values. Enum must stay compatible
with data in production. Only the frontend and seed data were cleaned up.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 10:21:28 -06:00
Carlos Escalante
22334c2129 Remove MPAT and MEMP fund references from pension module
All checks were successful
Deploy to VPS / deploy (push) Successful in 56s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 10:18:36 -06:00
Carlos Escalante
0923337fff Fix pension paste parser for split-line format from bank website
All checks were successful
Deploy to VPS / deploy (push) Successful in 14s
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>
2026-04-01 10:09:51 -06:00
Carlos Escalante
898b540b3f Fix roiEarned crash when chart data has fewer than 12 entries
All checks were successful
Deploy to VPS / deploy (push) Successful in 14s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 10:06:08 -06:00
Carlos Escalante
3c9656f416 Add manual pension data entry and fix chart to use real historical data
All checks were successful
Deploy to VPS / deploy (push) Successful in 23s
- Add paste-and-preview modal for entering pension fund balances from bank website
- Backend upsert logic so n8n PDF uploads overwrite manual entries
- Chart now shows actual snapshot data with dynamic month labels
- New POST /pensions/manual endpoint for JSON-based fund entry

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 10:03:29 -06:00
Carlos Escalante
e011a3adcc Fix date picker defaulting to UTC instead of browser local time
All checks were successful
Deploy to VPS / deploy (push) Successful in 17s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 21:02:08 -06:00
Carlos Escalante
b68129a171 Add cumulative balance tracking with editable overrides
All checks were successful
Deploy to VPS / deploy (push) Successful in 21s
- New BalanceOverride table for manual balance adjustments per month
- Cumulative balance computation with cross-year carryover
- Three new columns: Acum. Anterior, Neto Mes, Balance Acum.
- Inline editing on Balance Acum. cell (pencil icon for overrides)
- Year navigation clamped to 2026–2030, fresh start at March 2026
- PUT/DELETE /budget/balance-override/{year}/{month} endpoints

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 12:03:43 -06:00
Carlos Escalante
99d0c4ebd7 Split budget Resumen into Detalle, Transacciones, and Proyecciones sub-tabs
All checks were successful
Deploy to VPS / deploy (push) Successful in 14s
Reduces scrolling by organizing the budget overview into three inner tabs.
Clicking a month in the yearly table auto-switches to the Detalle tab.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 11:14:43 -06:00
Carlos Escalante
26a26b8ca2 Fix category dropdown showing ID and sort alphabetically
All checks were successful
Deploy to VPS / deploy (push) Successful in 14s
SelectValue now renders the category name instead of the raw ID.
Categories are sorted alphabetically when fetched.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 10:56:03 -06:00
Carlos Escalante
fe8d0144eb Add Electronics category and fix DEPOSITO shown as expense
All checks were successful
Deploy to VPS / deploy (push) Successful in 24s
DEPOSITO transactions (salaries) were displaying with negative sign and
red styling. Flipped logic so only COMPRA is negative; DEPOSITO and
DEVOLUCION both show as positive income.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 10:49:22 -06:00
Carlos Escalante
eccfd53e0b Add pension PDF upload, parsing, and fund summary API
All checks were successful
Deploy to VPS / deploy (push) Successful in 48s
Backend: parse BAC pension statement PDFs (VOL, ROP, FCL) via
pdftotext, store snapshots with duplicate detection, reject
credit card statements. Endpoints: POST /upload, GET /snapshots,
GET /fund-summary.

Frontend: wire up drag-and-drop upload, load real balances and
rendimientos from API, show upload results with error/duplicate
feedback.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 22:24:42 -06:00
Carlos Escalante
1b90f0c70a Add Pensions page with fund overview, growth chart, and projections
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 18:13:52 -06:00
Carlos Escalante
bd1346f9da Exclude DEPOSITO transactions from budget projections
All checks were successful
Deploy to VPS / deploy (push) Successful in 12s
Salary deposits were being counted as expenses in uncovered actuals,
causing negative balances. DEPOSITO transactions are income tracked
separately in the Salarios page.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 23:29:45 -06:00