Skip to content

Deployment Process

Three environments

Environment Branch VPS path DB suffix
development develop local Docker _dev
staging staging /opt/dev/<project>/ _staging
production main /opt/prod/<project>/ _prod

Branch discipline

feature/*  →  develop  →  staging  →  main
hotfix/*   →  main     (and back-merged to develop)
  • Never commit directly to main or staging
  • Hotfix path is the only exception, and it must be back-merged to develop the same day
  • Merge requests in Forgejo require at least one approval

Promotion rules

  • Develop → staging: automatic on push if CI passes
  • Staging → production: manual, with explicit approval from João. Never automated. Never inferred. Never assumed.

Per-project deployment shape

Most projects share this shape:

  1. Build container image (tagged with the git SHA and the semver from VERSION)
  2. Push image to the Forgejo container registry
  3. SSH to VPS, cd /opt/prod/<project>/, docker compose pull && docker compose up -d
  4. Confirm healthcheck passes via docker ps
  5. Tag the git commit v<MAJOR>.<MINOR>.<PATCH>
  6. Update CHANGELOG.md (auto via git-cliff, then human review)

Version policy

  • VERSION file at the root of every project
  • Semver: MAJOR.MINOR.PATCH
  • API responses include X-App-Version header
  • A version badge is rendered bottom-left of every page, invisible until hover

Rollback

For container-based services:

docker compose stop <service>
docker tag <image>:v<old> <image>:rollback
docker compose up -d <service>

For schema changes that broke things: the Alembic down() migration must work. If it does not work, that is the bug to fix, not the deployment.

What is special about the JB stack

  • No CI/CD provider. Build happens locally or on the VPS. There is no GitHub Actions because there is no GitHub.
  • Forgejo Actions is available but not currently used — tracked for future.
  • jb-skills-gateway can be redeployed without restarting individual skills — they live-reload from filesystem.