Architecture Overview
Lumio runs as four services: a Next.js frontend, a NestJS API, PostgreSQL, and Redis. Two optional Docker Compose
profiles add self-hosted receipt maps: maps (map-assets, map-tiles-init, tileserver) and geocoder
(nominatim). Background work — the statement parsing queue and scheduled jobs — runs inside the backend
process; there are no separate worker services.
Core services
-
Frontend (Next.js)
- Web UI for uploads, dashboards, and configuration
- Proxies API requests to the backend through a Next.js rewrite (
API_PROXY_TARGET,http://backend:3001in Docker)
-
Backend (NestJS)
- REST API at
/api/v1and Socket.IO for real-time notifications - HttpOnly session cookies with double-submit CSRF protection, RBAC, audit logging
- helmet security headers and Redis-backed rate limiting
- BullMQ queue for statement parsing,
@nestjs/schedulefor cron jobs
- REST API at
-
PostgreSQL
- 85 TypeORM entities and 142 migrations; schema changes only through migrations
-
Redis
- BullMQ statement parsing queue
- Application cache
- Rate limit counters shared by every backend instance
-
Maps (optional)
- tileserver-gl renders the tiles; the backend proxies them under
/api/v1/maps, so the tile server needs no public port - Nominatim geocodes merchant addresses printed on receipts
- See Receipt Maps
- tileserver-gl renders the tiles; the backend proxies them under
Request flow
- Client uploads a statement file.
- Backend computes a SHA-256 hash and checks for duplicate uploads.
- The statement is queued and parsed in the background.
ParserFactoryServicedetects the bank and selects a bank-specific or generic parser; OCR handles images and scans.- A quality gate rates the result
ready,review, orblocked. - An import session previews the transactions and flags conflicts with existing ones; committing the import resolves each conflict.
- Categories are assigned from learning rules and, when configured, AI classification.
Observability
The backend exposes Prometheus-format metrics at GET /api/v1/metrics (requires METRICS_AUTH_TOKEN in
production), health checks at GET /api/v1/health and GET /api/v1/health/ready, and structured JSON logs with
request and trace IDs. Lumio does not ship a monitoring stack — point your own collector at the endpoint. See
Observability.
Next: Backend Architecture