Skip to main content

Deployment

Deploy the ledger backend (both books) and the docs site.

Backend on Coolify

Every book gets its own Coolify app:

  1. Add a Docker application. Source = this repo. Dockerfile = apps/ledger/Dockerfile.
  2. Set env (all secrets encrypted at rest):
    • ENTITY_IDVALURA_UAE or VALURA_IND_IFSC
    • LEDGER_DB_URL — the per-book Postgres DSN
    • LEDGER_TOKEN + LEDGER_ADMIN_TOKEN
    • Per-book broker creds (see Credentials)
  3. Migrate on boot. The container runs alembic upgrade head on start.
  4. Configure a domain.
  5. Deploy.

Health probes: GET /health/live (200) and GET /health/ready (200 = migrations at head, DB reachable).

Docs site (this app) on Coolify

  1. Add a Docker application. Source = this repo. Dockerfile = apps/ledger/docs/Dockerfile.
  2. Set build args:
    • DOCS_URL — canonical URL (e.g. https://ledger-docs.valura.<domain>)
    • DOCS_BASE_URL/ (unless serving from a subpath)
  3. Set the domain.
  4. 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:

  1. Open the app in Coolify.
  2. 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_URL for drift alerts (optional).
  • OpenAPI docs — /docs on each backend.