Deployment Production

Backend Staging Deployment

Staging and production container deployment notes for the hosted stack.

Host
docs.bagels.top
Source
documentation/backend-container-deployment.md
Updated
2026-04-15

Backend Container Deployment

The backend still builds as one image with two runtime processes:

Local development continues to use Docker Compose from this repo. Hosted staging and production now deploy through repo-owned Ophelia source manifests, GHCR images, and the shared Ophelia Postgres addon on the VPS.

Local

  1. Copy or fill in /Users/kyle/Developer/projects/multiplatform/aspectavy/aspectavy-platform/backend/.env.local
  2. Start the stack:
./bin/setup-local-env
docker compose -f ops/docker/docker-compose.yml up -d --build

Useful checks:

docker compose -f ops/docker/docker-compose.yml ps
docker compose -f ops/docker/docker-compose.yml logs -f api
docker compose -f ops/docker/docker-compose.yml logs -f worker
curl http://127.0.0.1:3001/health
curl http://127.0.0.1:3001/livez
curl http://127.0.0.1:3001/readyz

Backup local bundled Postgres:

./ops/scripts/backup-postgres.sh local

Hosted Staging And Production

The canonical hosted deploy sources now live under:

Those manifests define the live bagels.top rehearsal layout:

- staging-app.bagels.top - staging-api.bagels.top - staging-docs.bagels.top - staging-admin.bagels.top

- app.bagels.top - api.bagels.top - docs.bagels.top - admin.bagels.top

Each Ophelia app deploys:

dev.bagels.top remains platform-owned static hosting in the Ophelia repo.

One-Time VPS Bootstrap

Do this once per environment before the first CI deploy:

- ops/deploy/ophelia/aspectavy-staging.env.example -> ~/ophelia-runtime/apps/aspectavy-staging/env - ops/deploy/ophelia/aspectavy-production.env.example -> ~/ophelia-runtime/apps/aspectavy-production/env

  1. Copy the checked-in env example into the runtime app env path:
  2. Fill the secrets and provider credentials.
  3. Leave the file in place. CI deploys fail fast if it is missing.

The shared Postgres addon rewrites DATABASE_URL during the first successful deploy, so the placeholder value in the example file is expected.

CI Deployment Flow

Staging workflow:

- DEPLOY_STAGING_SSH_HOST - DEPLOY_STAGING_SSH_PORT - DEPLOY_STAGING_SSH_USER - DEPLOY_STAGING_SSH_PRIVATE_KEY

Production workflow:

- DEPLOY_PRODUCTION_SSH_HOST - DEPLOY_PRODUCTION_SSH_PORT - DEPLOY_PRODUCTION_SSH_USER - DEPLOY_PRODUCTION_SSH_PRIVATE_KEY

Both workflows now:

  1. run backend npm run typecheck and npm test
  2. build and push the backend image to GHCR
  3. sync the source manifest into ~/ophelia-runtime/apps/<app>/source-manifest.yml
  4. run ~/ophelia/cli/ship deploy ... --apply on the VPS

Branch policy:

Runtime Validation

Useful hosted checks after a deploy:

curl -I https://staging-app.bagels.top/login
curl -I https://staging-api.bagels.top/readyz
curl -I https://staging-docs.bagels.top/
curl -I https://staging-admin.bagels.top/

curl -I https://app.bagels.top/login
curl -I https://api.bagels.top/readyz
curl -I https://docs.bagels.top/
curl -I https://admin.bagels.top/

Useful VPS-local checks:

ssh -p 22022 kyle@209.74.71.165 'docker compose -f ~/ophelia-runtime/apps/aspectavy-staging/compose.yml ps'
ssh -p 22022 kyle@209.74.71.165 'docker compose -f ~/ophelia-runtime/apps/aspectavy-production/compose.yml ps'
ssh -p 22022 kyle@209.74.71.165 'curl -f http://127.0.0.1:3401/readyz'
ssh -p 22022 kyle@209.74.71.165 'curl -f http://127.0.0.1:3501/readyz'

Legacy Compose Files

These files remain in the repo for local development, backup/restore helpers, and temporary rollback use only:

They are no longer the primary hosted deployment path.

Backup and restore helpers remain available:

./ops/scripts/backup-postgres.sh production-bundled
DATABASE_URL=postgres://... ./ops/scripts/backup-postgres.sh production-external

FORCE=1 ./ops/scripts/restore-postgres.sh production-bundled ./backups/production-bundled-YYYYMMDD-HHMMSS.dump
FORCE=1 DATABASE_URL=postgres://... ./ops/scripts/restore-postgres.sh production-external ./backups/production-external-YYYYMMDD-HHMMSS.dump

Notes

- app.aspectavy.com - api.aspectavy.com - docs.aspectavy.com - admin.aspectavy.com