This page describes the deployment topology that matches the current repository.
For system boundaries and design rationale, use Architecture Overview. For environment variable details, use Configuration.
This section documents one AWS ECS/Fargate deployment shape for ezrules. It is a reference topology, not a requirement for all deployments or self-hosted users.
The application runtime is split across these services/tasks:
| Runtime | Responsibility |
|---|---|
frontend |
Serves the Angular SPA |
api |
Runs uv run ezrules api --port 8888 for manager APIs and /api/v2/evaluate |
celery-worker |
Runs uv run celery -A ezrules.backend.tasks worker -l INFO --pool=solo for backtesting jobs |
celery-beat |
Runs uv run celery -A ezrules.backend.tasks beat -l INFO for field-observation and shadow drain schedules |
init / migration task |
One-shot task that runs schema setup, Alembic migrations, and initial org bootstrap before services start |
Required backing services:
| Dependency | Purpose |
|---|---|
| PostgreSQL | Source of truth for rules, auth, outcomes, audit history, and analytics data |
| Redis | Celery broker plus the default queue backing store for async field-observation and shadow drains |
Use same-origin browser routing by default.
Recommended ALB routing:
| Path | Target |
|---|---|
/* |
frontend service |
/api/* |
api service |
/docs |
api service |
/redoc |
api service |
/openapi.json |
api service |
/ping |
api service |
Why this is the default:
- the production frontend build now defaults to same-origin API requests
- browser auth, cookies, and refresh flows stay on one public origin
- no explicit CORS configuration is needed for the main UI path
If you intentionally split frontend and API across different public origins:
- Build the frontend image with
EZRULES_FRONTEND_API_URL=https://api.example.com. - Set
EZRULES_CORS_ALLOWED_ORIGINS=https://app.example.comon the API task. - Use
EZRULES_CORS_ALLOW_ORIGIN_REGEXonly when a fixed allowlist is not practical.
Minimum task/service contract:
frontendcan be scaled independently from the APIapimust have network access to PostgreSQL and Rediscelery-workermust share the same code image and runtime env asapi, plus broker connectivitycelery-beatmust share the same code image and runtime env asapi, plus broker connectivityinitmust run to completion beforeapi,celery-worker, andcelery-beatare treated as ready
Minimum environment inputs:
EZRULES_DB_ENDPOINTEZRULES_APP_SECRETEZRULES_CELERY_BROKER_URLEZRULES_APP_BASE_URL- optional SMTP settings if invite/reset emails should leave the environment
- optional
EZRULES_AI_AUTHORING_MODEL,EZRULES_AI_AUTHORING_BASE_URL, andEZRULES_AI_AUTHORING_API_KEYif AI-assisted draft generation should work without per-org Settings configuration - optional
EZRULES_CORS_ALLOWED_ORIGINS/EZRULES_CORS_ALLOW_ORIGIN_REGEXonly for split-origin deployments
Recommended production rollout sequence:
- Run the
inittask against the target database. - Deploy or update the
apiservice. - Deploy or update
celery-worker. - Deploy or update
celery-beat. - Deploy or update
frontend. - Verify
/ping, login, a sample/api/v2/evaluaterequest, and one async queue-driven flow.
The repository still ships local Docker setups for validation and development.
Use docker-compose.demo.yml when you want a seeded environment:
docker compose -f docker-compose.demo.yml up --buildThis starts:
- PostgreSQL
- Redis
initapicelery-workercelery-beatfrontend- Mailpit
The database is recreated from scratch on each full rerun so old schemas do not poison the demo.
Use docker-compose.prod.yml to validate the production images and startup sequence locally:
cp .env.example .env
docker compose -f docker-compose.prod.yml up --buildThis mirrors the app-level runtime split but remains a single-host Docker setup rather than an ECS deployment.
Use docker compose up -d to run infrastructure locally while you keep API and frontend as local dev processes.
That stack now includes both celery-worker and celery-beat so async queue drains behave like the documented runtime.
Use this after any deployment change:
curl http://<api-host>/pingreturns{"status":"ok"}.- Browser login succeeds through the public frontend.
POST /api/v2/evaluatesucceeds with a valid API key or Bearer token.- A queued backtest can move beyond
PENDING. - Shadow/field-observation drains keep progressing, confirming
celery-beatis alive.
This repository now documents the correct app/runtime topology, but infra implementation is still external work.
Typical follow-up items:
- ECS task definitions and service autoscaling policies
- ALB listeners, target groups, and TLS certificates
- secrets delivery for app/API/SMTP credentials
- RDS PostgreSQL and Redis provisioning
- logging, metrics, and alerting for
api,celery-worker, andcelery-beat