This guide covers everything you need to run any part of the Call of Code platform locally using Docker Compose.
The repository ships with five Docker Compose configurations:
| File | Purpose | Services |
|---|---|---|
docker-compose.yml |
API-only dev (standalone) | coc-api |
docker/docker-compose.yml |
All platforms master stack | all 6 services |
docker/coc-member/docker-compose.yml |
Full COC Member stack | coc-api + server + web |
docker/coc-admin/docker-compose.yml |
Full COC Admin stack | coc-api + server + web |
docker/callofcode.in/docker-compose.yml |
Full callofcode.in website stack | coc-api + frontend |
All platform stacks build
coc-apilocally from the repo rootDockerfileand pull their respective frontend/backend images from Docker Hub.
- Docker Desktop or Docker Engine + Docker Compose plugin (v2.22+)
- Git
No need to install Bun, Node, or any other runtime locally — everything runs inside containers.
Copy the example and fill in your Supabase credentials:
cp .env.example .env.local| Variable | Description |
|---|---|
DATABASE_URL |
Supabase connection-pooling URL (Prisma runtime) |
DIRECT_URL |
Direct DB connection URL (Prisma Migrate) |
SUPABASE_URL |
Your Supabase project URL |
SUPABASE_SERVICE_ROLE_KEY |
Supabase service-role secret key |
Each platform directory ships example files with all variables documented and placeholder values. Copy and fill in only the secrets you need:
# COC Member
cp docker/coc-member/.env.local.backend.example docker/coc-member/.env.local.backend
cp docker/coc-member/.env.local.frontend.example docker/coc-member/.env.local.frontend
# COC Admin
cp docker/coc-admin/.env.local.backend.example docker/coc-admin/.env.local.backend
cp docker/coc-admin/.env.local.frontend.example docker/coc-admin/.env.local.frontend
# callofcode.in
cp docker/callofcode.in/.env.local.frontend.example docker/callofcode.in/.env.local.frontend| Platform | File | Key Variables |
|---|---|---|
| All backends | .env.local.backend |
JWT_SECRET, REFRESH_SECRET, RESEND_API_KEY |
coc-admin backend |
.env.local.backend |
+ WHATSAPP_LINK, DISCORD_LINK |
coc-member frontend |
.env.local.frontend |
VITE_API_URL |
coc-admin frontend |
.env.local.frontend |
VITE_API_URL, VITE_GIF_URL |
callofcode.in frontend |
.env.local.frontend |
API_BASE_URL, GITHUB_TOKEN (optional) |
Never commit real secrets. All
*.env.local*files are git-ignored by default.
Use this when you need all three platforms running simultaneously (e.g. testing cross-platform API behaviour or running the full suite locally):
# From the repo root — watch mode recommended
docker compose -f docker/docker-compose.yml up --watch
# Or standard mode
docker compose -f docker/docker-compose.yml up --buildAll six services share a single coc-network bridge and a single coc-api instance:
| Service | Container | Host port | Override env var |
|---|---|---|---|
coc-api |
3000 |
3000 | COC_API_PORT |
callofcode-frontend |
3001 |
3001 | CALLOFCODE_PORT |
coc-admin-server |
8000 |
8001 | COC_ADMIN_BACKEND_PORT |
coc-admin-web |
5173 |
5174 | COC_ADMIN_FRONTEND_PORT |
coc-member-server |
8000 |
8002 | COC_MEMBER_BACKEND_PORT |
coc-member-web |
5173 |
5175 | COC_MEMBER_FRONTEND_PORT |
Port remapping: because
coc-adminandcoc-memberboth internally bind8000and5173, the master stack remaps them to unique host ports to avoid conflicts. Internal service-to-service communication (API_URL=http://coc-api:3000) still uses the original container ports.
Env files required: make sure all six env files exist before starting (see Environment Setup above).
Use this when you're only working on the coc-api itself:
# Standard mode
docker compose up --build
# Watch mode — Docker syncs src/ changes and restarts bun automatically
docker compose watchThe API will be available at http://localhost:3000
Health check: http://localhost:3000/health
cd docker/coc-member
docker compose up --build| Service | URL |
|---|---|
coc-api |
http://localhost:3000 |
server (member backend) |
http://localhost:8000 |
web (member frontend) |
http://localhost:5173 |
cd docker/coc-admin
docker compose up --build| Service | URL |
|---|---|
coc-api |
http://localhost:3000 |
server (admin backend) |
http://localhost:8000 |
web (admin frontend) |
http://localhost:5173 |
cd docker/callofcode.in
docker compose up --build| Service | URL |
|---|---|
coc-api |
http://localhost:3000 |
frontend |
http://localhost:3001 |
All stacks use health-checked depends_on to ensure correct startup ordering:
coc-api (healthy) → server/backend (healthy) → web/frontend
The coc-api health check polls GET /health every 30 seconds with a 15-second grace period on startup. Downstream services only start once coc-api reports healthy.
The root docker-compose.yml supports docker compose watch with the following rules:
| Path changed | Action |
|---|---|
src/** |
Sync — files copied into container instantly; bun --watch picks up the change |
package.json / bun.lock |
Rebuild — full image rebuild to reinstall dependencies |
prisma/** |
Rebuild — triggers prisma generate on next container start |
# Start in watch mode (preferred for API development)
docker compose watch# Start in the background (detached)
docker compose up -d --build
# Follow logs
docker compose logs -f
# Follow logs for a specific service
docker compose logs -f coc-api
# Stop all containers
docker compose down
# Stop and remove volumes (clean slate)
docker compose down -v
# Rebuild a single service without restarting others
docker compose build coc-api
# Open a shell inside a running container
docker compose exec coc-api sh
# Run Prisma Studio (from inside the coc-api container)
docker compose exec coc-api bunx prisma studioThe root Dockerfile uses a multi-stage build:
| Stage | Target | Purpose |
|---|---|---|
deps |
— | Installs production dependencies only |
builder |
target: builder |
Installs all deps + generates Prisma client; used by all dev compose files |
runner |
— | Lean production image; runs as non-root cocuser |
The dev compose files use target: builder so that devDependencies and the Prisma CLI are available inside the container.
open Dockerfile: no such file or directory
The dockerfile: path in compose is relative to the context, not the compose file. Our configs set context: ../.. (repo root) so dockerfile: Dockerfile resolves correctly.
Port already in use
For the individual stacks, set a custom port via the PORT env variable:
PORT=3001 docker compose upFor the master stack, override the specific service port:
COC_API_PORT=3010 COC_ADMIN_BACKEND_PORT=8010 docker compose -f docker/docker-compose.yml upPrisma migration errors on startup
The coc-api container runs prisma migrate deploy on every start. If the DB is unreachable, the container will exit. Verify your DATABASE_URL and DIRECT_URL in .env.local.
Container exits immediately after healthy
Check logs with docker compose logs coc-api. Common causes: missing env vars or a failed migration.
Stale node_modules in container
The anonymous volume /app/node_modules is intentionally excluded from the host mount to avoid cross-OS binary conflicts. If you change package.json, let Docker rebuild:
docker compose build --no-cache coc-api