Local development
The full loop — code → migrate → sync → test — on a laptop.
Repository layout
apps/ledger/
├── ledger/ # FastAPI backend + services + brokers + posting
├── frontend/ # Vite + React UI (both books)
├── alembic/ # migrations
├── db/seeds/ # accounts.json (UAE), accounts.india.json (India)
├── tests/ # ~400 tests
├── scripts/ # dev-up, dev-down, seed_accounts, e2e_india, ...
├── .env.uae.local # UAE-book config
├── .env.ind.local # India-book config
└── Dockerfile / docker-compose.dev.yml
The two-book DB layout
- Single Postgres container serves both books.
ledger_uaeDB → UAE backend (:8077).ledger_indDB → India backend (:8078).- Same schema (
ledger), same tables, same migrations — just different data.
ENTITY_ID (VALURA_UAE / VALURA_IND_IFSC) is set per backend in its
.env.*.local and is used by:
- The seeder — picks
accounts.jsonoraccounts.india.json - Logging / observability
- The India-only services (they refuse to run against a UAE DB)
Compose services
docker-compose.dev.yml defines:
| Service | Purpose | Port |
|---|---|---|
postgres | shared DB | 5433 (host) |
migrate-uae | one-shot alembic + seed for UAE | — |
migrate-ind | one-shot alembic + seed for India | — |
ledger-uae | UAE backend | 8077 |
ledger-ind | India backend | 8078 |
ledger-ui | Vite dev server | 3100 |
The backend containers mount ./ read-write so uvicorn --reload picks up
code changes without rebuilding.
Migrations
docker exec valura-ledger-ind alembic current
docker exec valura-ledger-ind alembic upgrade head
docker exec valura-ledger-ind alembic downgrade -1
The migrate-* compose services run alembic upgrade head on boot, then exit.
Tests
- Pure-logic (default) — no DB, no network. Sub-second per file.
- DB-backed — a handful; use the local container.
- e2e —
scripts/e2e_india.pydrives a full India run end-to-end.
./.venv/Scripts/python.exe -m pytest tests/ -q # everything
./.venv/Scripts/python.exe -m pytest tests/test_india_*.py -q # India only
python -m scripts.e2e_india # DB-backed e2e
Frontend
cd apps/ledger/frontend
pnpm install
pnpm dev
The book toggle in the sidebar flips apiBase() between :8077 and :8078
and triggers a full reload so react-query caches don't cross-contaminate.
Common gotchas
.envoverrides inline env. Move.envaside if you're pointing at a different DB temporarily.- India container restart — occasionally uvicorn's
--reloadmisses a change (touched file with no content diff). If a new endpoint 404s,docker restart valura-ledger-ind. - Windows asyncpg loop flakiness — DB-backed pytest can flake on Windows;
use
scripts/e2e_india.pythere. - The India backend can hit live brokers. Read Credentials before running syncs.