Local development
On this page
You need two things running: the platform (API and worker) on Postgres, and the frontend. One setup command gets you there.
The source of truth for these steps is dembrane/platform/README.md. If this page and the README disagree, the README is right.
The quick way: Postgres in Docker#
You need Bun (the version in dembrane/platform/.bun-version), pnpm and Docker. To process audio you also need ffmpeg on your PATH.
cd dembrane/platform
bun run setup # Postgres in docker, dependencies, migrations
bun run dev # API on :8080
bun --env-file=.env.local apps/worker/src/main.ts # worker
cd dembrane/frontend
pnpm install
pnpm dev # dashboard on :5173, /api proxied to :8080
pnpm participant:dev # portal on :5174
bun run setup does five things:
- It copies
.env.exampleto.env.localwhen that file is missing, and adds a generatedAUTH_SECRETandINVITE_HASH_SECRET. - It runs
bun install. - It starts Postgres with
docker compose up -d --wait db. - It applies the migrations.
- It seeds the default verification topics.
compose.yml has one service: Postgres 16 with pgvector, published on host port 5433. Set ECHO_DB_PORT to use another port. Postgres is the only service you need. There is nothing else to start.
Without Docker: mprocs#
Run Postgres natively and start everything with mprocs, from dembrane/mprocs.yaml.
You need Bun, pnpm, mprocs, ffmpeg on your PATH, and Postgres 16 with pgvector on port 5432.
The one-time setup is in the README under “Run it without docker”: create the echo role and database, create .env.local from the example on port 5432 with its own secrets, then install, migrate and seed. The role is a superuser so that the migrations can create the vector extension.
Then run mprocs from dembrane/. It starts four processes:
| Process | Port | Note |
|---|---|---|
api |
8080 | Restarts on change. |
worker |
Does not restart on change. Select it and press r. |
|
dashboard |
5173 | Proxies /api to the API. |
portal |
5174 | Proxies /api to the API. |
A fifth process, migrate, does not start on its own. Select it and press s after you pull new migrations.
What local mode does differently#
APP_ENV=local loads packages/config/environments/local.ts. With it:
- Uploaded files go to
.data/filesand audio to.data/audioon disk. The API serves them itself in place of presigned bucket URLs. You need no object storage. - With no
MEDIA_URL, ffmpeg runs inside the API and the worker. That is why ffmpeg must be on yourPATH. - With no
SENDGRID_API_KEY, the API keeps emails in memory and the worker logs “mail not sent”. No email leaves your machine. - Cookies are not marked secure, because local runs on plain
http. - Webhooks may target private addresses, so you can point one at a server on your machine.
Language model features (transcription, summaries, chat, reports) call Google Vertex AI with Google application default credentials. LLM_VERTEX_PROJECT names the Google Cloud project that is billed. See configuration and language model providers.
Commands you will use#
From dembrane/platform:
| Command | What it does |
|---|---|
bun run check |
Lint, types, the layer rule and the tests. Run it before you push. |
bun run test |
The tests, in parallel. |
bun run format |
Fixes lint and formatting with Biome. |
bun run db:generate |
Writes a migration from a schema change. |
bun run db:migrate |
Applies migrations to your local database. |
bun run config show <env> |
Shows the effective config values and where each came from, with secrets hidden. diff <env> <env> and check also exist. |
bun run packages check |
Checks the layer rule. bun run packages write regenerates PACKAGES.md. |
bun run staff:access list |
Lists staff. grant and revoke change it. |
From dembrane/frontend:
| Command | What it does |
|---|---|
pnpm lint |
Biome lint. |
pnpm exec tsc |
Type check. |
pnpm test |
The frontend tests (vitest). |
pnpm build |
Type check and build into dist. |
pnpm messages:extract, pnpm messages:compile |
Update the translation catalogs after you change interface text. CI fails when they are out of date. |
Config in one paragraph#
Every setting is declared once in packages/config/src/schema.ts. A value comes from the schema default, then the environment file for your APP_ENV, then the process environment, in rising precedence. Secrets may only come from the process environment, which locally means .env.local. Config is validated at boot: all problems are shown in one error and the process does not start. To add a key, declare it in the schema, override it per environment if needed, and read it as config.<section>.<key>. bun run config check fails when a key is declared but never read.
Related#
- Architecture
- Background jobs and schedules
- Deployment and releases
- Self-hosting
- Configuration and language model providers
- Contributing
Comments