What compose is
docker-compose.yml is a local stack: Postgres, the backend, the voice worker
and the console, on one network, with both published ports bound to
127.0.0.1.
Each service also has its own Dockerfile and deploys on its own. LiveKit is
external in every case: the worker connects out to LIVEKIT_URL.
Read this before it faces a network
The backend has no authentication. Every route is open, including the ones
that read and write the LiveKit project and the agent’s prompt. That is
deliberate for a tool on your own machine and wrong on a public address. Put
something in front of it, or do not expose it.
Three more facts that follow from that:
CONSOLE_WRITES_ENABLED stays off. It defaults to false in code.
Compose turns it on because compose is local. Anywhere else, leave it off and
the write routes refuse.
- Your LiveKit signing secret is stored unencrypted. On first boot the
backend copies the LiveKit project from the environment into the
livekit_settings table, and the Deployment page edits it there. So the
secret is in Postgres, in the pgdata volume, and in any dump you take.
Rotating the key in your LiveKit project is the revocation path.
CORS_ORIGINS_STR unset means every origin is allowed. Compose sets it
to http://localhost:5173, but the code default is empty and
BACKEND_CORS_ORIGINS returns ["*"] for empty, so a backend started
without it accepts browser calls from anywhere. Set it explicitly on any
host that is not your own machine.
The worker
agent/fly.toml is set up for Fly: performance-1x, blue/green, and a
kill_timeout of five minutes matching the drain_timeout=300 on
AgentServer. That pairing is what makes a deploy mid-call finish the call
instead of dropping it.
The worker restarts itself when the stored LiveKit project changes, which is
why the compose service carries restart: unless-stopped. Whatever you deploy
onto needs the same: a process supervisor that brings it back.
The backend
It runs alembic upgrade head on startup, under a Postgres advisory lock so
concurrent boots serialise. There is no separate migration step, and a slow
database does not stop it booting: it serves tokens from the environment until
Postgres catches up.
The console
Static files. The three VITE_ values are compiled in at build time, so the
image is environment-specific: build one per environment, and never reuse a
local image against a remote backend.
Where secrets live
In .env, which is gitignored, except for the LiveKit project once the backend
has copied it into Postgres. Nothing else in this repo persists a credential.