Skip to content

CI/CD

Audience: devops, backend
Status: specced
Owns: devops
Depends on: System architecture, Backend stack ADR, Observability

Accepted: GitHub Actions for pipeline definition and UI. Runners may be self-hosted later if needed.

Considered, not chosen:

Tool Notes
Woodpecker Simple, Drone-compatible, self-hosted — thinner UI than GHA
Gitea Actions Nice UI if git hosting moved to Gitea; not current hosting model
Drone CI Near-identical to Woodpecker; no reason to pick over Woodpecker if self-hosting

Target: Actions deploy Orchestrator / CAP / @elimi/common / @elimi/proto. Gateway hosts:

Env Hostname
Staging www.staging-api.elimi-ecosystem.e-limi.africa
Production api.elimi-ecosystem.e-limi.africa

Paths: /v1/ol/…, /v1/cap/…, /v1/lms/… (and later /v1/wm/…).

Until container registry + Swarm/K8s are online, deploys use immutable tarballs from GitHub Actions → SCP → release directories under ~/elimi-ecosystem/<app>_<env>/current symlink → pm2 reload (cluster mode). Runbook: monorepo infra/deploy/README.md.

  • Pack: infra/deploy/pack.sh
  • Activate: infra/deploy/activate.sh (migrate → deploy console commands → optional seed → symlink flip, health gate, rollback)
  • Workflow: .github/workflows/deploy-orchestrator.yml — push staging → staging VPS; push main → production VPS (Environment approval); workflow_dispatch for either
  1. Lint
  2. Type-check
  3. Unit tests
  4. Pack deployable artifact (tarball today; container image later)
  5. Integration tests (docker-compose against real Postgres + RabbitMQ)
  6. Push artifact / registry (Actions artifact + SCP today; GHCR later)
  7. Deploy to staging
  8. Manual promote to production

Migrations: each service owns Prisma migrations; activate runs prisma migrate deploy on the VPS before flipping current. Deploy console commands (node dist/console/cli.js --deploy) run after migrate and before optional seed — see Console commands. Keep event/API changes backward-compatible for at least one release so services need not deploy in lockstep.

  • Longer-term: containerize every service; docker-compose for local (services + Postgres instances + RabbitMQ + SigNoz); Swarm then K8s when needed.
  • Current VPS: PM2 is the process manager (cluster mode, ≥2 instances) under release dirs.
  • Inside a future container, PM2 may still own cluster mode for CPU cores only — do not double-cluster restart logic with Swarm/K8s.
  • Secrets: CI secrets store → env injected at deploy; Vault later if sprawl grows.
  • Postgres: pgBackRest or WAL-G — WAL archive + nightly base backup to S3-compatible storage.
  • Schedule restore drills — an untested backup is a hypothesis.