A production-minded backend for wallet balances, royalty splits, and async financial reporting, designed around correctness under concurrency.
This project is a mini financial system API built to prioritise transactional integrity over raw HTTP throughput.
- Uses PostgreSQL transactions and
SELECT FOR UPDATElocking to prevent double-spending. - Enforces idempotency with a client-owned
Idempotency-Keyand database uniqueness constraints. - Stores all money as integer cents to avoid floating point errors.
- Uses deterministic royalty math: author gets floor(70%), platform gets the remainder.
- Uses BullMQ + Redis for non-blocking report generation.
- NestJS + TypeScript (strict)
- PostgreSQL + Drizzle ORM
- BullMQ + Redis
- Jest + Supertest
- Docker Compose + pnpm
All endpoints except /health require an X-User-Id header (UUID).
| Method | Path | Description | Extra Headers |
|---|---|---|---|
GET |
/health |
Health check | — |
POST |
/wallets/:walletId/deposit |
Deposit funds into a wallet | — |
POST |
/purchases |
Purchase an item (3-wallet royalty split) | Idempotency-Key (UUID) |
POST |
/reports/financial |
Request an async financial report | — |
GET |
/reports/financial/:jobId |
Poll report status and result | — |
Swagger UI is available at /api when SWAGGER_ENABLED=true.
Prerequisites: Node.js 22+, pnpm 9+, Docker + Docker Compose.
- Install dependencies.
pnpm install- Create local environment file.
cp .env.example .env- Start PostgreSQL and Redis.
docker compose up -d- Apply database migrations.
pnpm db:migrate- Seed the platform account.
pnpm db:seed- Start the API.
pnpm start:dev- Verify health endpoint.
curl -s http://localhost:3000/health
# → { "status": "ok" }| Command | Description |
|---|---|
pnpm lint |
ESLint with auto-fix |
pnpm format |
Prettier write |
pnpm typecheck |
TypeScript type check |
pnpm test |
Unit tests |
pnpm test:e2e |
E2e tests |
pnpm test:cov |
Unit tests with coverage |
pnpm knip |
Dead code / unused deps check |
pnpm validate |
Full local quality gate (lint + typecheck + test + knip + build) |
pnpm db:generate |
Generate Drizzle migration from schema changes |
pnpm db:migrate |
Apply pending migrations |
pnpm db:seed |
Seed platform user and wallet |
pnpm db:studio |
Drizzle Studio GUI |
For system context diagrams, module structure, data model, concurrency details, and the full request lifecycle, see docs/architecture.md.
Key decisions are captured in ADRs: