Local Development
How to bring up the full Race Platform stack on your laptop.
Prerequisites
- Docker Desktop 4.30+ (or Docker Engine on Linux)
- Node 20 LTS + pnpm 9
- Flutter 3.24+ (for the client)
- ~6 GB free RAM, 10 GB disk
The docker-compose stack
The full stack lives in infra/docker/docker-compose.yml and
runs five services:
| Service | Image | Host port | Container port | Purpose |
|---|---|---|---|---|
postgres | postgres:16-alpine | 6160 | 5432 | Primary DB |
api | local build (api.Dockerfile) | 6161 | 8787 | Hono REST API |
realtime | local build | 6162 | 8788 | WebSocket service |
redis | redis:7-alpine | 6163 | 6379 | KV / pub-sub |
minio | minio/minio:latest | 6164 | 9000 | S3-compatible object store |
minio (console) | 6165 | 9001 | MinIO web UI | |
| Flutter web (separate) | python3 -m http.server | 6166 | — | Static build of the Flutter web client |
| Docusaurus docs (this site) | python3 -m http.server | 6167 | — | This help site |
The 6160–6167 range was chosen because the default Postgres/Hono
ports (5432 / 8787) collided with other dev services. See the
"Host port collisions are common" learning in .context/progress.md.
Bring it up
The fastest path is the one-shot script at the repo root:
./setup.sh # boots Docker, migrates, seeds, uploads demo plugin,
# builds Flutter web, builds docs, runs smoke test
./teardown.sh # stops everything (add --wipe to nuke data volumes)
setup.sh is idempotent — re-run it after a pull and it'll
re-bootstrap whatever it needs. Use ./setup.sh --reset to wipe
the database first.
If you'd rather run the steps individually:
make up-d # docker-compose up -d
make migrate # run Drizzle migrations
make seed # IMSA Sebring sample data
make smoke # end-to-end smoke test
make client # launch Flutter on macOS
After make seed (or after setup.sh), log in with:
- Email:
jamie@apexracing.io - Password:
race2026 - Account slug:
apex-endurance
Docs site (this site)
From the repo root:
make docs # docusaurus start on port 3000
# OR
make docs:build # static build → apps/docs/build/
make docs:serve # python3 -m http.server 6167
After changing the schema
Drizzle migrations are append-only. To add a column:
cd apps/api
DATABASE_URL=postgres://race:race@localhost:6160/race \
pnpm exec drizzle-kit generate
make migrate
After adding a TS dependency to api or realtime
You must rebuild the Docker image because node_modules/ is
baked in at build time:
docker-compose -f infra/docker/docker-compose.yml down
docker-compose -f infra/docker/docker-compose.yml build api realtime
make up-d
Source-code changes are picked up automatically by tsx watch —
no rebuild needed.
Useful Make targets
| Target | Purpose |
|---|---|
make up-d | Start the stack (detached) |
make down | Stop the stack |
make reset | Wipe DB + restart |
make logs | Tail all service logs |
make psql | Open a psql shell |
make typecheck | pnpm typecheck across all TS workspaces |
make test | pnpm test across all TS workspaces |
make smoke | 6-step end-to-end HTTP smoke test |
make client | Flutter on macOS |
make client-web | Flutter on Chrome |
make docs | Docs dev server on :3000 |
make docs:build | Build static site to apps/docs/build/ |
make docs:serve | Serve the static build on :6167 |
Troubleshooting
| Symptom | Likely cause |
|---|---|
make up-d fails with port already in use | Another process is holding 6160–6166; lsof -i :6161 to find it |
| Login returns 401 | Re-run make seed — bcrypt hashes are computed at seed time |
| API can't see new migrations | The migrate container has the source bind-mounted; re-run make migrate |
flutter build macos fails on CocoaPods | Homebrew Ruby 4.x ffi gem issue — see docs/running-the-app.md for workarounds |