Two ways to run CombatX:
- Docker — one command, nothing to install. Best for just running it.
- Local — run the apps on your host with hot reload. Best for day-to-day development.
Docker Desktop (or Docker Engine + the Compose plugin). Nothing else — no Node, no pnpm, no Postgres.
git clone <repo-url> combatX
cd combatX
docker compose up --buildThen open http://localhost:3001.
That's the whole setup. On first boot the stack automatically applies the database schema, seeds the problems, and installs the Python 3.12 runtime into the code sandbox. The app services wait for all of that to finish, so the first request can never hit an unmigrated database or an empty sandbox.
First build takes a few minutes. Subsequent starts are seconds.
To stop:
docker compose down # keep the database
docker compose down -v # wipe the database toodocker compose -f docker-compose.dev.yml up --buildSame stack, but your source is bind-mounted and the servers restart on change — edit a file on your host and the containers pick it up in about a second.
| Service | URL |
|---|---|
| Web | http://localhost:3001 |
| HTTP API | http://localhost:4001 |
| WebSocket | ws://localhost:4002/ws |
| Piston | http://localhost:2000 |
| Postgres | localhost:5432 (loopback) |
| Redis | localhost:6379 (loopback) |
The most common clash is Redis on 6379. Copy .env.docker.example to .env
and remap:
cp .env.docker.example .env
echo "REDIS_PORT=6380" >> .envCompose reads .env automatically. Every value in it already has a working
default, so you only need the lines you actually want to change. The same
applies to POSTGRES_PORT and PISTON_PORT.
Changing
NEXT_PUBLIC_API_URL/NEXT_PUBLIC_WS_URLrequires a rebuild (--build) — they are inlined into the browser bundle at image-build time.
- Node.js ≥ 18 and pnpm 10.19 (
corepack enablewill pin it for you) - PostgreSQL 16 running locally
- Redis 7 running locally
- Piston for sandboxed code execution — see below
git clone <repo-url> combatX
cd combatX
corepack enable
pnpm installThree env files, each with a committed example. Copy them:
cp .env.example .env
cp apps/web/.env.example apps/web/.env.local
cp packages/db/.env.example packages/db/.env| File | Used by |
|---|---|
.env |
http-api, ws-server, judge-worker |
apps/web/.env.local |
the browser bundle |
packages/db/.env |
Prisma CLI (migrate, seed, studio) |
The defaults assume Postgres on localhost:5432 with user/password
postgres/postgres and a database named combateone. Adjust DATABASE_URL
in both .env and packages/db/.env if yours differs — they must match.
Set JWT_SECRET to any long random string for local work.
Create the database, then apply the schema and seed the problems:
createdb combateone
pnpm --filter @repo/db db:push # apply the schema
pnpm --filter @repo/db db:seed # insert the problemsUseful later:
pnpm --filter @repo/db db:studio # browse the data in a GUIThe judge executes submitted code in a Piston sandbox. Easiest is to run just that one piece in Docker:
docker run -d --name piston -p 2000:2000 --privileged \
ghcr.io/engineer-man/piston:latestThen install the Python runtime (once):
curl -X POST http://localhost:2000/api/v2/packages \
-H 'Content-Type: application/json' \
-d '{"language":"python","version":"3.12.0"}'Verify it took:
curl http://localhost:2000/api/v2/runtimes
# -> [{"language":"python","version":"3.12.0", ...}]Without this, submissions will fail to run — the sandbox has no language installed by default.
pnpm devThis runs all four apps together. Open http://localhost:3001.
To run just one:
pnpm --filter web dev
pnpm --filter http-api dev
pnpm --filter ws-server dev
pnpm --filter judge-worker devOpen http://localhost:3001, create a battle, and copy the room code. Open a second browser (or an incognito window), join with that code, seat both players on opposite teams, ready up, and start.
A quicker smoke test:
curl http://localhost:4001/health # -> {"ok":true}
curl http://localhost:4002/health # -> {"ok":true}
curl http://localhost:2000/api/v2/runtimes # -> python 3.12 listedpnpm check-types # TypeScript, all workspaces
pnpm lint # ESLint
pnpm build # production build
pnpm --filter @repo/game test # game-rule unit testsAll four should pass on a clean checkout.
pnpm dev exits immediately, or complains about concurrency.
You need turbo's concurrency raised above the number of persistent dev tasks.
This is already set in turbo.json — if you hit it, you're on an older
checkout. Pull latest.
Submissions hang or every test fails.
Piston has no runtime installed. Run the POST /api/v2/packages call above and
confirm GET /api/v2/runtimes lists Python.
Cannot find module '@repo/db' or similar.
Build the workspace packages first: pnpm build. The apps import compiled
output from packages/*.
Port already in use (Docker). See If a port is already taken.
A file under apps/ is owned by root and you can't build.
An old dev-container run wrote into the bind-mounted source. Delete the
offending directory (e.g. sudo rm -rf apps/web/.next) and rebuild.