Getting Started
Prerequisites
- Docker Desktop (or compatible Docker engine)
- Docker Compose v2+
No local Node.js, pnpm, or other toolchain installation is required. The Docker setup handles everything.
Starting Services
The root package.json provides convenience scripts for common setups. Infrastructure services (Postgres, Redis) always start regardless of profile.
| Script | What it does |
|---|---|
pnpm dev:infra | Postgres + Redis only (no profile) |
pnpm dev:backend | Backend services using existing images |
pnpm dev:backend:build | Rebuild base image + all backend images, then start |
pnpm dev:fullstack | Backend + frontend services using existing images |
pnpm dev:fullstack:build | Rebuild base image + all images, then start |
pnpm dev:web | Next.js dev server directly (no Docker) |
pnpm dev:native | Native app + Sanity dev servers (no Docker) |
Web Development
The web app (Next.js) is not included in the Docker Compose setup. To develop on the web app, start the backend services and then run the Next.js dev server separately:
# Terminal 1: start backend (API, GraphQL Router, etc.)
pnpm dev:backend
# Terminal 2: start the Next.js dev server
pnpm dev:webThis gives you native hot module replacement and fast refresh without the overhead of running Next.js inside a container.
When to Use :build
Use the :build variant when:
- You just pulled changes from git (Dockerfiles or dependencies may have changed)
- You changed
Dockerfile.base, any app Dockerfile, orpnpm-lock.yaml - Docker images don't exist yet (fresh clone)
Use the non-:build variant for day-to-day development when images are already built. It skips the image build step and starts containers immediately.
TIP
The :build scripts run docker compose build base-node first to ensure the shared base image is up to date, then docker compose up --build to rebuild all app images. The non-:build scripts just run docker compose up with the appropriate profiles.
Running Profiles Directly
You can also use Docker Compose directly:
# Backend only
docker compose --profile backend up
# Frontend only
docker compose --profile frontend up
# Monitoring only (Aspire dashboard)
docker compose --profile monitoring up
# Everything
docker compose --profile backend --profile frontend upService Ports
| Service | Port | URL |
|---|---|---|
| API | 3001 | http://localhost:3001 |
| Match Gateway | 3002 | http://localhost:3002 |
| GraphQL Router | 4000 | http://localhost:4000 |
| Notifications | 4001 | http://localhost:4001 |
| Identity | 4002 | http://localhost:4002 |
| Loyalty | 4003 | http://localhost:4003 |
| Business | 4004 | http://localhost:4004 |
| API Gateway | 8888 | http://localhost:8888 |
| Traefik Dashboard | 8880 | http://localhost:8880/dashboard/ |
| Docs | 5173 | http://localhost:5173 |
| Aspire Dashboard | 18888 | http://localhost:18888 -- see Observability |
| PostgreSQL | 5432 | postgresql://postgres:postgres@localhost:5432/main |
| Redis | 6379 | redis://localhost:6379 |
Common Tasks
Rebuild the Base Image
When Node.js or pnpm versions change in Dockerfile.base:
docker compose build base-nodeSee Base Image for details.
Reset the Database
Remove the Postgres volume and restart:
docker compose down -v
docker compose --profile backend upWARNING
-v removes all named volumes, including pnpm store and node_modules caches. A fresh pnpm install will run on next start.
View Logs for a Single Service
docker compose logs -f apiRebuild a Specific Service
docker compose build api
docker compose --profile backend upShell into a Running Container
docker compose exec api shHow Dependency Installation Works
Backend services do not install dependencies themselves. A shared pnpm-install init container runs pnpm install --frozen-lockfile once before any app service starts. App services depend on it via condition: service_completed_successfully.
Installed node_modules are persisted in named volumes (root-node-modules, api-node-modules, etc.) so subsequent starts skip the install step unless the lockfile changes.