Deployment
The backend ships as a Docker image whose entrypoint is start.sh, serving on port 8080. The same codebase runs in three roles: the API service, a migration job, and Celery workers.
Container
Build from the repository root:
Run it with an env file (see Environment configuration for the variables it expects):
start.sh loads .env in local mode, applies migrations via migrate.sh when a database is configured, then starts the server (Gunicorn with Uvicorn workers in production, Uvicorn otherwise).
Migrations
In cloud deployments, migrations run as a separate job (its image entrypoint is migrate.sh, running alembic upgrade head), and the API service sets SKIP_MIGRATIONS=true so it does not migrate on boot. This keeps schema changes to a single controlled step.
Make migrations backward compatible so a new revision can run before the new code is fully rolled out. To roll a schema change back:
Workers
Celery workers deploy as their own service from the worker image, sharing the broker and result backend (BROKER_URL, CELERY_RESULT_BACKEND). Scale workers independently of the API. See Background tasks.
Google Cloud Run
The production target is Cloud Run. Deploy the API service, run the migration job separately, and connect Cloud SQL:
The image is a standard container, so it also runs on other platforms (AWS ECS, Azure Container Apps, plain Docker) given the same environment variables.
Operations
- Health —
GET /healthreturns{"status": "ok"}; use it as the container health check. - Logs — the application logs to stdout/stderr; set
JSON_LOGGER_ENABLED=truefor structured logs (see Architecture). - Rollback — redeploy the previous image; reverse migrations only if the new revision was not backward compatible.
- Secrets — supply
JWT_SECRET_KEY, database, and OAuth credentials through the platform’s secret manager, not the image.