One FastAPI codebase, one Docker image, three container roles (gateway / worker / cron) from the same image. Event-sourced ingest into TimescaleDB + PostGIS. JWT-mandatory reads. Image-tag deploys via Coolify from a self-hosted Forgejo registry.
Failure isolation is the point: a heavy report in `worker` does not stall `gateway`.
## Deploy
CI (Forgejo Actions) builds on push to `main`, tags `<registry>/fleet-platform:<sha>` and `:latest`. Coolify deploys by tag. Rollback is `coolify deploy :<prev-sha>`.
`dbmate up` runs on `platform-worker` startup before the worker serves traffic; `gateway` and `cron` wait on a startup probe that confirms migration completion.