This is the practical guide for running FlipCup locally and figuring out where to start when you want to change something.
The quickest full-stack loop is Docker Compose:
docker-compose up -dThat uses:
game-server/Dockerfilewith thedevtargetui/Dockerfilewith thedevtarget
Important: local Compose does not use the repo-root Dockerfile. That root image exists for deployment packaging, not for your normal inner loop.
Backend:
cd game-server
go run cmd/flipcup/main.goFrontend:
cd ui
npm install
npm run devUseful local URLs:
- backend:
http://localhost:8080 - frontend:
http://localhost:5173
The frontend runtime URL logic lives in:
ui/src/lib/utils/config.ts
Behavior summary:
- local dev usually uses
VITE_WS_URL=localhost:8080 - deployed environments can leave
VITE_WS_URLunset - when unset, the UI falls back to the current browser host and builds HTTP/WS URLs from there
That lets staging/Fly avoid hardcoding a specific deploy hostname into the frontend build.
If you are new to the repo:
- read
architecture.md - read
gameplay.md - skim
../gameflow.mdif you are changing WebSocket behavior - use
testing.mdbefore changing anything risky
Start in:
game-server/internal/game/game-server/internal/quiz/
Start in:
game-server/internal/transport/api/game-server/internal/transport/ws/
Start in:
ui/src/components/ui/src/lib/
Start in:
deploy/nomad/flipcup.nomad.hcl.github/workflows/deploy-staging.ymlDockerfilefly.toml
- game state is in memory, so be careful about assumptions around scaling or multiple replicas
- if you touch reconnect logic, validate both frontend state and backend session handling
- if you touch deployment packaging, make sure you are not accidentally changing local Compose behavior
- if you touch gameplay, think through multiplayer side effects instead of only the happy path
There are two different workflows in this repo:
- developer workflow — Docker Compose or direct app commands
- deployment workflow — build the shared root
Dockerfilefor staging/Fly
Keeping those separate is intentional. It preserves a fast dev loop while still letting staging and production share one deployable image.