Deployment
Deploy the ledger backend (both books) and the docs site.
Backend on Coolify
Every book gets its own Coolify app:
- Add a Docker application. Source = this repo. Dockerfile =
apps/ledger/Dockerfile. - Set env (all secrets encrypted at rest):
ENTITY_ID—VALURA_UAEorVALURA_IND_IFSCLEDGER_DB_URL— the per-book Postgres DSNLEDGER_TOKEN+LEDGER_ADMIN_TOKEN- Per-book broker creds (see Credentials)
- Migrate on boot. The container runs
alembic upgrade headon start. - Configure a domain.
- Deploy.
Health probes: GET /health/live (200) and GET /health/ready (200 =
migrations at head, DB reachable).
Docs site (this app) on Coolify
- Add a Docker application. Source = this repo. Dockerfile =
apps/ledger/docs/Dockerfile. - Set build args:
DOCS_URL— canonical URL (e.g.https://ledger-docs.valura.<domain>)DOCS_BASE_URL—/(unless serving from a subpath)
- Set the domain.
- Deploy. Nginx serves the static build on port 80.
Health probe: GET /healthz returns 200 ok.
Environment tiers
- local — Docker Compose on a laptop.
- staging — Coolify apps against staging broker credentials.
- production — Coolify apps against production broker credentials.
Every tier uses the same image; the differentiator is the env.
Rollback
Coolify keeps previous images. To roll back a bad release:
- Open the app in Coolify.
- Redeploy the previous image tag from the history.
Data migrations don't auto-rollback — if a bad migration went out, follow the downgrade steps.
Zero-downtime
- Coolify does rolling deploys — the old container stays up until the new one passes health checks.
- The ledger backend is stateless per instance; DB is the only state. Two instances can run against the same book DB during the transition.
- The recon scheduler is advisory-locked cluster-wide — only one instance runs a given check at a time.
- The webhook receiver's background tasks are per-instance; a duplicate delivery during rolling deploy fires the sync twice, both are idempotent.
Observability
- Backend logs — stdout, picked up by Coolify's log aggregator.
- Alerts —
ALERT_WEBHOOK_URLfor drift alerts (optional). - OpenAPI docs —
/docson each backend.