2026-10-16 11:00:44 +03:00
|
|
|
# Quarkus backend: requirements
|
|
|
|
|
|
2026-10-16 11:53:13 +03:00
|
|
|
Status: implemented on branch `feature/quarkus-backend`; checked in Chrome against the local stack.
|
2026-10-16 11:00:44 +03:00
|
|
|
Scope: `apps/backend`, its Docker image, `apps/compose.yaml` and the docs.
|
|
|
|
|
|
|
|
|
|
## Goals
|
|
|
|
|
|
|
|
|
|
The backend is rewritten in Java with Quarkus on the latest Java LTS (Java 25). Players, the web app and the mobile
|
|
|
|
|
app notice nothing: the WebSocket protocol, the HTTP API and the stored data stay as they are, and the new backend
|
|
|
|
|
can replace the Node backend in a running deployment without ending live games.
|
|
|
|
|
|
|
|
|
|
## Terms
|
|
|
|
|
|
|
|
|
|
- **Node backend**: the Express + `ws` backend in `apps/backend` before this change.
|
|
|
|
|
- **Java backend**: its replacement.
|
|
|
|
|
- **Wire format**: the JSON sent over the WebSocket and the HTTP API, as the clients in `packages/core`,
|
|
|
|
|
`apps/frontend` and `apps/mobile` read it.
|
|
|
|
|
|
|
|
|
|
## Requirements
|
|
|
|
|
|
|
|
|
|
### R1. Platform
|
|
|
|
|
- R1.1 The backend is a Quarkus application (the latest stable 3.x release) compiled for and run on Java 25.
|
|
|
|
|
- R1.2 It is built with Maven; dependencies have exact versions (the Quarkus platform BOM pins the extensions).
|
|
|
|
|
- R1.3 It runs in JVM mode. A native image is out of scope.
|
|
|
|
|
- R1.4 It no longer depends on `packages/core` or `packages/mancala.js`; the game rules it needs are part of the
|
|
|
|
|
Java backend.
|
|
|
|
|
|
|
|
|
|
### R2. Game rules
|
|
|
|
|
- R2.1 The Java backend plays games by exactly the rules of `packages/mancala.js`: the same moves are allowed, the
|
|
|
|
|
same errors are raised, and every move produces the same board, the same history entry (board snapshot and game
|
|
|
|
|
steps with their data) and the same next player.
|
|
|
|
|
- R2.2 A test replays games recorded with the TypeScript engine and compares every result, including the JSON a
|
|
|
|
|
client receives, so the two engines cannot drift apart unnoticed. The recording can be regenerated with a script.
|
|
|
|
|
|
|
|
|
|
### R3. WebSocket protocol
|
|
|
|
|
- R3.1 Clients connect to the server's root path, as now (`ws://localhost:5005`, `wss://api.playmancala.app`).
|
|
|
|
|
- R3.2 Every channel in `packages/core/src/rtmt/channel_names.ts` behaves as in the Node backend: the same messages
|
|
|
|
|
are sent to the same users in the same order, with the same JSON. This covers authentication (`auth`, `on_auth`,
|
|
|
|
|
`on_auth_error`, close code 4001, the 5 second timeout, token refresh), matchmaking, moves, leaving, spectating,
|
|
|
|
|
connection changes, live game previews and the ping/pong keep-alive.
|
|
|
|
|
- R3.3 Legacy clients that connect with `?userKey=<uuid>` work while `LEGACY_USERKEY_AUTH` is on.
|
|
|
|
|
- R3.4 A user can be connected from several sockets; the user is offline when the last one closes.
|
|
|
|
|
|
|
|
|
|
### R4. HTTP API
|
|
|
|
|
- R4.1 `GET /`, `GET /register/` (only with legacy auth), `GET /game/:id`, `GET /games/popular`,
|
|
|
|
|
`GET /games/me/active` and `GET /games/me` answer with the same status codes and JSON as in the Node backend.
|
|
|
|
|
- R4.2 CORS allows every origin, as now.
|
|
|
|
|
- R4.3 Requests are written to `access.log` in the common log format, as now.
|
|
|
|
|
|
|
|
|
|
### R5. Data
|
|
|
|
|
- R5.1 The Java backend uses the existing Postgres schema and the `schema_migrations` table: on a database the Node
|
|
|
|
|
backend migrated, it applies nothing; on an empty one it creates the same tables.
|
|
|
|
|
- R5.2 It restores live games that the Node backend saved in Valkey (snapshot versions 1 and 2), and writes snapshots
|
|
|
|
|
the Node backend can restore, so a rollback also keeps live games.
|
|
|
|
|
- R5.3 It saves finished games that the Node backend left pending in Valkey, and pending records it leaves can be
|
|
|
|
|
saved by the Node backend.
|
|
|
|
|
- R5.4 Saved games and cached lists have the same JSON as before; a game saved by either backend reads the same.
|
|
|
|
|
|
|
|
|
|
### R6. Behaviour when a dependency is down
|
|
|
|
|
Unchanged from `game-history` and `game-clock`:
|
|
|
|
|
- R6.1 Games are played while Postgres or Valkey is down. Finished games are kept and saved once Postgres is back;
|
|
|
|
|
lists are served without the missing data.
|
|
|
|
|
- R6.2 The backend starts while Postgres is down (migrations are retried) and while Valkey is down (live games are
|
|
|
|
|
then not restored).
|
|
|
|
|
- R6.3 Live games survive a restart; the time the backend is down is not charged to the clock.
|
|
|
|
|
|
|
|
|
|
### R7. Configuration and deployment
|
|
|
|
|
- R7.1 The settings stay environment variables with the same names and defaults (`PORT`, `KEYCLOAK_*`,
|
|
|
|
|
`LEGACY_USERKEY_AUTH`, `VALKEY_URL`, `GAME_CLOCK_MS`), except the database: `DATABASE_URL` is replaced by
|
|
|
|
|
`DATABASE_JDBC_URL`, `DATABASE_USERNAME` and `DATABASE_PASSWORD`. `apps/.env` needs no change.
|
|
|
|
|
- R7.2 The Docker image is still built from the repo root with `docker build -f apps/backend/Dockerfile .`, listens
|
|
|
|
|
on port 6000 in the container and runs under `apps/compose.yaml` as before.
|
|
|
|
|
- R7.3 `mvn quarkus:dev` runs the backend locally on port 5005 against the compose services, like `yarn dev` did.
|
|
|
|
|
|
|
|
|
|
### R8. Tests and docs
|
|
|
|
|
- R8.1 The Node backend's tests are ported: game manager, live games, clock scheduler, token verifier, WebSocket
|
|
|
|
|
server, HTTP API, Postgres repository and Valkey store and cache. Tests that need Postgres or Valkey run them in
|
|
|
|
|
Docker, as now.
|
|
|
|
|
- R8.2 The web app is played against the Java backend in Chrome: login, a full game between two users, a spectator,
|
|
|
|
|
live previews, reconnecting, the game clock, restart with a live game, and the replay of the saved game.
|
|
|
|
|
- R8.3 `README.md`, `apps/backend/README.md`, `AGENTS.md` and `TODO.md` describe the Java backend.
|
|
|
|
|
|
|
|
|
|
## Out of scope
|
|
|
|
|
|
|
|
|
|
- Changes to the protocol, the API or the stored data, including fixing their known quirks (e.g. `on_game_crashed`
|
|
|
|
|
sending `{}`).
|
|
|
|
|
- Running more than one backend instance.
|
|
|
|
|
- Publishing the Java engine as a library, or replacing the TypeScript engine in the clients.
|