deployment/local/, and a single script brings the whole
system up, applies database migrations, and health-checks every service.
Prerequisites
The Dockerized flow needs only one thing:- Docker Engine 24+ with the Compose v2 plugin. Verify with
docker --versionanddocker compose version.
The local frontend image is a production build (
node server.js), not next dev, so there is
no hot reload: after editing backend or frontend source you must rebuild with
docker compose up -d --build (or re-run the deploy script).Quickstart
1
Get the code and enter the local deployment
2
Create the env files
deploy.sh copies them from the examples on first run, or do it yourself:3
Set the essentials in backend/.env
Set a long random
JWT_SECRET, an ADMIN_DEFAULT_PASSWORD (this seeds the admin login on the
first migration), and at least one LLM key (e.g. OPENAI_API_KEY). Leave RECAPTCHA_SECRET_KEY
and SMTP_HOST empty so local dev skips captcha and email verification.4
Bring the stack up
.env files, runs docker compose up -d --build, then health-checks Postgres,
the backend, and the frontend. The equivalent manual command is docker compose up -d --build.5
Log in
Open http://localhost:3000, sign in at
/login with username admin
and the ADMIN_DEFAULT_PASSWORD you set (this account is pre-verified), then open the Studio at
/app.What comes up
deploy.sh runs the Compose file at deployment/local/docker-compose.yml, which starts four services:
On first start the backend’s
entrypoint.sh waits for Postgres, runs alembic upgrade head (creating the
schema and seeding the admin user), runs python -m app.db.init_checkpointer (creating the
LangGraph checkpointer tables), and then starts uvicorn.
Configuration
Settings resolve in the order env var →.env → YAML → defaults (see backend/app/core/config.py):
backend/.env(secrets):JWT_SECRET,ADMIN_DEFAULT_PASSWORD, LLM API keys, optionalSMTP_*,RECAPTCHA_SECRET_KEY,GOOGLE_OAUTH_CLIENT_ID. Compose assemblesDATABASE_URLfrom thePOSTGRES_*values, so you do not set it directly.frontend/.env:API_PROXY_TARGET(defaulthttp://backend:8000) and theNEXT_PUBLIC_*keys, baked into the image at build time (so changing them needs a rebuild).deployment/local/backend/config.local.yaml(non-secret): the default LLMprovider/model, CORS origins, andobservability.provider(noneto disable Phoenix/LangSmith tracing). Secrets never come from YAML.
First login and accounts
- Seeded admin is the practical way in: the first migration creates user
admin(role admin,email_verified=true) using yourADMIN_DEFAULT_PASSWORD. - Self-registration (
/login→ register) enforces email verification before login, so withoutSMTP_*configured a self-registered local user cannot log in. Use the admin account, or configure SMTP. - Captcha is skipped automatically when
RECAPTCHA_SECRET_KEYis empty.