mirror of
https://github.com/escalante29/WealthySmart.git
synced 2026-07-17 10:08:46 +02:00
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>
85 lines
2.7 KiB
Markdown
85 lines
2.7 KiB
Markdown
# WealthySmart
|
|
|
|
Personal finance management web app.
|
|
|
|
## Stack
|
|
|
|
- **Frontend:** React 19 + Vite + TypeScript + Tailwind CSS 4
|
|
- **Package manager:** pnpm
|
|
|
|
## Development
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
cd backend && .venv/bin/python -m pytest tests/ -q # backend (55+ tests)
|
|
cd frontend && pnpm typecheck # frontend
|
|
```
|
|
|
|
## Local Docker
|
|
|
|
```bash
|
|
# 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:
|
|
|
|
```bash
|
|
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.
|