The UI reads participant/standings fields from the native-server twin
(nativeOverlay), but bot join only wrote the NowChess participant list,
so bots never appeared in replicated/native-published tournaments. On
join, register the bot on the native server by name and join the twin
as that bot. Also run this for the AlreadyJoined case so bots stuck in
the NowChess list (but missing on native) get reconciled, and return
200 instead of 409 for it.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bots joining a published tournament directly on the native server were not
reflected in NowChess (0 players) and the tournament could not be started,
because create() kept a local copy plus a separate native copy whose id was
discarded — leaving the two records disconnected.
- Capture the native tournament id: createNative/publishNative now return the
id instead of Boolean; persist it on Tournament.nativeTournamentId.
- Reverse-sync on read: get()/list() overlay nbPlayers/standing/status/round/
winner from the native twin (with a fullName backfill for tournaments created
before the id was captured).
- start(): proxy to the native twin (director token via authFor) so the native
participants are used; mirror the started status locally.
- Skip the native server in the replicate loop (it has no /replicate endpoint),
removing the per-create "Failed to replicate" warning.
- Isolate native integration in tournament unit tests (native-server-url no
longer defaults to the live server).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Janis Eccarius <eccariusjanis@gmail.com>
Reviewed-on: #78
The tournament-server only accepts HS256 tokens it issued; forwarding a
NowChessSystems RS256 user token caused "unsupported algorithm". Proxied
calls (start/join/withdraw/stream) targeting the native server now swap in
the director token registered on that server.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Official bots now poll the external tournament server and auto-join every
created tournament with the hardest bot (expert). Tournaments created in
NowChessSystems are forwarded to the native tournament server so the bots
can see and join them.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reviewed-on: #77
Empty string config value caused DeploymentException when injected as String.
Optional[String] handles absent/empty cleanly without defaultValue workaround.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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