Local development setup for the web app, data layer and judge worker with Docker, tests and CI.
After ./dev-deploy.sh web, use this page to work on individual services.
Prerequisites
Section titled “Prerequisites”| Tool | Version | For |
|---|---|---|
| Docker | 20.10+ | Compose stacks |
| Go | 1.21+ | Data layer |
| Node / Bun | 18+ | Web |
| Python | 3.10+ | Judge + Tavern tests |
| Git | any | PRs |
Layout
Section titled “Layout”NextJudge/├── compose/ # docker-compose.*.yml├── scripts/ # run-e2e-tests.sh, run-data-layer-tests.sh, start-e2e-stack.sh, …├── src/│ ├── data-layer/src/ # Go handlers (users.go, problems.go, …)│ ├── judge/ # languages.toml, nsjail, app.py│ ├── web/src/app/ # Next.js routes│ ├── cli/ # nextjudge command│ └── docs/ # this site├── deploy.sh # prod-ish local stack├── dev-deploy.sh # hot reload + SEED_DATA└── fully-reset.sh # wipe local data and volumesFiles you’ll edit
Section titled “Files you’ll edit”| Task | Start here |
|---|---|
| API bug / new endpoint | src/data-layer/src/*.go, then tests/test_data_layer.tavern.yaml |
| Wrong verdict / TLE | src/judge/src/, languages.toml |
| UI / editor | src/web/src/app/, src/web/src/components/ |
| Server state / polling | src/web/src/hooks/queries/, src/web/src/providers/query-provider.tsx |
| Editor UI state | src/web/src/lib/stores/editor-store.ts |
| Problem form validation | src/web/src/lib/schemas/problem-form.ts |
| Types shared with API | src/web/src/lib/types.ts, src/web/src/lib/api.ts |
| Schema change | src/data-layer/src/models.go, maybe schema_updates.sql |
Web (Playwright — isolated local docker stack, not production):
# Smoke tests only (no judge build) — matches most CI web PRsE2E_WITH_JUDGE=0 ./scripts/run-e2e-tests.sh
# Full suite including code run/submit (needs judge image)E2E_WITH_JUDGE=1 ./scripts/run-e2e-tests.sh
# Pull a prebuilt judge image instead of building locally (~3 min saved)E2E_WITH_JUDGE=1 E2E_JUDGE_USE_PULL=1 ./scripts/run-e2e-tests.sh
# Local iteration — start once, rerun only what you changed./scripts/start-e2e-stack.sh./scripts/run-e2e-playwright.sh --grep-invert @judgeE2E_WITH_JUDGE=1 ./scripts/start-e2e-stack.sh./scripts/run-e2e-playwright.sh --grep @judge./scripts/stop-e2e-stack.sh
# Or from src/web when the stack is already up:PLAYWRIGHT_BASE_URL=http://127.0.0.1:8080 npm run test:e2e:smokePLAYWRIGHT_BASE_URL=http://127.0.0.1:8080 npm run test:e2e:judgeConstants and stack config live in src/web/e2e/ (constants.ts, test-stack.config.sh, docker-compose.yml). The @judge tag marks specs that need the judge worker (platform.spec.ts).
Data layer:
./scripts/run-data-layer-tests.sh# or manually:cd src/data-layerpip install -r tests/requirements.txtpytest tests/ -p no:warningsTavern API tests hit an isolated docker stack on port 5050 (tests/constants.py, tests/test_data_layer.tavern.yaml). Configure the host with TAVERN_HOST or the default in constants.py.
Judge:
cd src/judge && python -m pytest tests/# or ./tests.shCI (what runs on your PR)
Section titled “CI (what runs on your PR)”Path-filtered jobs in .github/workflows/ci.yml:
| Change in | Runs |
|---|---|
src/web/** | lint, Playwright smoke (no judge), Playwright judge E2E (pull prebuilt image), Docker build |
src/data-layer/** | Go unit tests, Tavern API tests (local stack), Docker image build |
src/judge/** | Judge tests (cached image build), judge image build for Playwright @judge specs |
src/docs/** | Docs build |
Changes confined to one service usually trigger only that job.
Common tasks
Section titled “Common tasks”New API endpoint
Section titled “New API endpoint”- Handler in the right
*.gofile - Route registration in the same file’s
add*Routes AuthRequired,AdminRequired, orAtLeastJudgeRequired- Tavern stage in
tests/ - API reference update
New language
Section titled “New language”See Judge service: Add a language. Rebuild basejudge:dev or the production target after Dockerfile changes.
Database migration
Section titled “Database migration”Edit models.go. AutoMigrate runs on the next data layer start. For destructive changes, add SQL to schema_updates.sql and test with ./fully-reset.sh locally before production.
Debugging
Section titled “Debugging”| Service | Try |
|---|---|
| Data layer | go run src/main.go -d -p 5000 |
| Judge | docker logs $(docker ps -qf name=judge) |
| Web | DevTools + terminal running npm run dev |
| Postgres | docker exec -it $(docker ps -qf name=postgres) psql -U postgres nextjudge |
| RabbitMQ | http://localhost:15672 (creds from .env.dev) |
Env sources: config.go, judge app.py, web .env.example.
Go: gofmt, early returns. TypeScript: strict, no any. Python: PEP 8, type hints on new code.
Contributing
Section titled “Contributing”Branch from main, test locally, open a PR. See CONTRIBUTING.md.
Build all images: docker buildx bake -f docker-bake.hcl