Files
WealthySmart/CLAUDE.md
Carlos Escalante 7dfe2da2a9 OpenAPI type codegen with CI drift gate (plan 3.4, ARCH-16, FE-14)
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>
2026-06-12 07:53:00 -06:00

2.7 KiB

WealthySmart

Personal finance management web app.

Stack

  • Frontend: React 19 + Vite + TypeScript + Tailwind CSS 4
  • Package manager: pnpm

Development

cd frontend && pnpm install && pnpm run dev

The backend refuses to boot without SECRET_KEY, ADMIN_USERNAME, and ADMIN_PASSWORD (no insecure defaults). Copy .env.example to .env and fill it in; the dev docker-compose reads it.

Database Migrations

Schema changes go through Alembic — never edit the schema by hand and never reset the prod DB. Workflow:

cd backend
# 1. Edit app/models/models.py
# 2. Autogenerate against the dev DB, then REVIEW the generated file
DATABASE_URL='postgresql://wealthy_user:wealthy_pass@localhost:5433/wealthysmart' \
  .venv/bin/alembic revision --autogenerate -m "describe the change"
# 3. Migrations apply automatically at app startup (run_alembic_upgrade)

Tests

cd backend && .venv/bin/python -m pytest tests/ -q   # backend (55+ tests)
cd frontend && pnpm typecheck                        # frontend

Local Docker

# Backend + DB containers
docker exec wealthysmart-db-dev psql -U wealthy_user -d wealthysmart -c 'SQL;'

Deployment

  • Deployed via Gitea Actions (self-hosted runner on VPS)
  • Push to main triggers: GitHub → webhook → Gitea mirror sync → Actions workflow → Docker build & deploy
  • Domain: wealth.cescalante.dev
  • Reverse proxy: nginx-proxy + acme-companion (auto TLS)

Infrastructure

  • Single server: ssh old-vps — runs everything (WealthySmart, n8n, Forgejo, Vaultwarden, nginx-proxy)
  • ssh production is NOT valid — do not use
  • n8n UI: https://n8n.cescalante.dev — n8n DB queryable via docker exec portfolio-db-prod psql -U portfolio_user -d n8n

n8n Flows

Four automated flows on old-vps feed data into WealthySmart:

  1. BAC Credit Card — Gmail trigger → POST /transactions/
  2. Salary Deposits — Gmail trigger → POST /transactions/
  3. Municipal Receipts — Cron trigger → POST /municipal-receipts/upload
  4. Pension PDFs (e88c3UhBeo9WCbcy) — Gmail trigger (daily midnight) → POST /pensions/upload

Flow export: docs/WealthySmart_ BAC Pensions Statements parser.json

API Type Generation

Frontend read types are generated from the backend OpenAPI spec. After changing backend response models:

cd backend && DATABASE_URL='sqlite://' SECRET_KEY=$(openssl rand -hex 32) \
  ADMIN_USERNAME=x ADMIN_PASSWORD=x-x OPENAI_API_KEY=dummy \
  .venv/bin/python -c "import json; from app.main import app; json.dump(app.openapi(), open('../frontend/openapi.json','w'), indent=1, sort_keys=True)"
cd ../frontend && pnpm gen:api   # regenerates src/lib/api-types.gen.ts

CI regenerates and fails the deploy if api-types.gen.ts is stale.