Servers are now configured via TOURNAMENT_EXTERNAL_SERVERS env var.
POST /api/tournament/servers and DELETE /api/tournament/servers/{id}
are removed; only GET (list) remains for the bot's fetchRemoteServers call.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
TOURNAMENT_EXTERNAL_SERVERS (comma-separated URLs) is loaded into
TournamentServerRegistry at startup so the bot can park on all servers
and replication targets are known without manual API calls after each restart.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replicate newly created tournaments to all registered remote servers,
persisting them with originServerUrl so the remote can proxy mutations back
- Route all mutation endpoints (join/start/terminate/withdraw) through
originServerUrl when set, instead of trying local state first
- Fix tournament event stream to proxy remote tournaments (was 404 before)
- Official bot now routes all calls through TOURNAMENT_SERVICE_URL (local
tournament service) instead of calling remote cluster directly
- Bot parks on local account service + all registered remote servers on startup
- Add TOURNAMENT_SELF_URL env var so each cluster knows its own public URL
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
GraalVM native image fails when scala.util.Random companion object (a static
singleton with cached seed) is reachable from the image heap. UUID.randomUUID()
is always runtime-initialized and safe.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
## Summary
- Implements the full tournament lifecycle (create, join, withdraw, start,
round progression, finish) as a standalone Quarkus module
- All 11 endpoints from the OpenAPI spec (`docs/tournament-openapi.yaml`) are covered
- Swiss pairing algorithm with Buchholz tiebreak and bye support
- Per-bot NDJSON event stream with targeted `gameStart` events carrying
the correct `color` field
- Game results ingested via Redis writeback stream (`GameResultStreamListener`)
## Known gaps (deferred)
- `GET /results` `nb` param defaults to 100 instead of all
- `PairingDto` exposes an internal `id` field not in the spec
- `GameExport.moves` emits PGN instead of UCI (upstream `GameWritebackEventDto`
does not carry UCI moves)
- `Pairing.white` can be `null` for bye rounds (spec has no bye concept)
## Test plan
- [x] 23 `TournamentResourceTest` integration tests (H2, mocked core client) — all pass
- [x] 5 `SwissPairingServiceTest` unit tests — all pass
- [x] Redis listener excluded in test/dev profiles; no Docker required to run tests
---------
Co-authored-by: LQ63 <lkhermann@web.de>
Co-authored-by: Lala, Shahd <Shahd.Lala@sybit.de>
Reviewed-on: #55