Skip to content

Deployment

Deployment is Docker Compose driven from webapp/docker-compose.yml. There is no separate orchestrator; you build the images that changed, recreate the affected services, and verify health. This page covers the operations you actually run.

Deploying a change

Which command you run depends on what changed. The backend hot-reloads from a bind mount, the frontend is a baked image — see Docker & local setup for the full model.

Frontend change → rebuild the image

The frontend source is not mounted; it is compiled into dist/ at build time (Bun build → Node runtime) and PUBLIC_* env vars are inlined into the client bundle during the build. So any UI change or any change to a PUBLIC_* value requires a rebuild:

Terminal window
docker compose build frontend
docker compose up -d frontend

Backend code change → usually nothing

./backend is bind-mounted and uvicorn --reload restarts the app in place, so editing Python on the host is picked up automatically. Rebuild only when dependencies (pyproject.toml) or the Dockerfile change:

Terminal window
docker compose build backend
docker compose up -d backend

New / changed environment values → recreate the backend

Environment variables are read once at process start. Editing the root .env does nothing to a running container. Recreate the service so Compose re-reads env_file and re-interpolates the environment: block:

Terminal window
docker compose up -d --force-recreate backend

Recreate frontend (and worker) the same way if you changed variables they consume. Remember the backend seeds each integration’s Mongo config from env on first startup only; if a config document already exists it is not overwritten, so changing a credential in .env after the fact means updating it in the UI / Mongo, not just recreating the container.

MongoDB persistence

MongoDB is the system of record. Its data lives in the named volume mongodb_data mounted at /data/db:

volumes:
- mongodb_data:/data/db
- ./mongodb-init:/docker-entrypoint-initdb.d

Consequences:

  • The volume survives docker compose down, up, image rebuilds, and host reboots. Container churn does not lose data.
  • docker compose down -v destroys mongodb_data (and postgres_data, backend_uploads, pgadmin_data). Do not run it against a live environment.
  • Uploaded files persist separately in backend_uploads (/app/uploads); the Intune/Entra certificate is mounted read-only from the host certs/ directory.

Back up by snapshotting the volume or running mongodump against the container:

Terminal window
docker compose exec mongodb mongodump --archive=/data/db/backup.archive \
--username "$MONGO_ROOT_USERNAME" --authenticationDatabase admin
docker compose cp mongodb:/data/db/backup.archive ./backup-$(date +%F).archive

Disk hygiene

Reclaim space regularly:

Terminal window
# Remove dangling (untagged) images — safe, everyday cleanup
docker image prune -f
# Reclaim build cache (can be large after many rebuilds)
docker builder prune -f
# Check what Docker is using
docker system df

Prune images/build-cache, not volumes. Avoid docker system prune -a --volumes on a production host — it will remove the data volumes. Stick to docker image prune / docker builder prune.

Health checks

The backend defines a Compose healthcheck that curls its own endpoint:

healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3

GET /health returns {"status": "healthy", "environment": ..., "database": ...}. Postgres has a pg_isready healthcheck and the worker waits on it (depends_on: condition: service_healthy).

Verify a deployment:

Terminal window
# Service + health status
docker compose ps
# Backend health directly
curl -f http://localhost:8000/health
# Frontend is serving
curl -I http://localhost:4321
# Watch logs for startup / sync errors
docker compose logs -f backend

On backend startup the logs show each integration config being seeded or skipped (... config already exists ... skipping seed), which is a quick confirmation the env wiring reached the container. If a sync is stuck “running” after a restart, see the durability discussion in ConnectWise Automate scoping & durable workflows.