Skip to main content

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:

ServiceImageHost portContainer portPurpose
postgrespostgres:16-alpine61605432Primary DB
apilocal build (api.Dockerfile)61618787Hono REST API
realtimelocal build61628788WebSocket service
redisredis:7-alpine61636379KV / pub-sub
miniominio/minio:latest61649000S3-compatible object store
minio (console)61659001MinIO web UI
Flutter web (separate)python3 -m http.server6166Static build of the Flutter web client
Docusaurus docs (this site)python3 -m http.server6167This help site
Why uncommon ports

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

TargetPurpose
make up-dStart the stack (detached)
make downStop the stack
make resetWipe DB + restart
make logsTail all service logs
make psqlOpen a psql shell
make typecheckpnpm typecheck across all TS workspaces
make testpnpm test across all TS workspaces
make smoke6-step end-to-end HTTP smoke test
make clientFlutter on macOS
make client-webFlutter on Chrome
make docsDocs dev server on :3000
make docs:buildBuild static site to apps/docs/build/
make docs:serveServe the static build on :6167

Troubleshooting

SymptomLikely cause
make up-d fails with port already in useAnother process is holding 6160–6166; lsof -i :6161 to find it
Login returns 401Re-run make seed — bcrypt hashes are computed at seed time
API can't see new migrationsThe migrate container has the source bind-mounted; re-run make migrate
flutter build macos fails on CocoaPodsHomebrew Ruby 4.x ffi gem issue — see docs/running-the-app.md for workarounds