diff --git a/TODO.md b/TODO.md index aee924a..2688f21 100644 --- a/TODO.md +++ b/TODO.md @@ -18,6 +18,13 @@ The web app logs in with Keycloak; the mobile app still uses the legacy `?userKe - [ ] Delete the unused copy of the WebSocket client in `apps/mobile/src/rtmt` - [ ] Test on a device +### Game history on mobile + +The web app has game history (see `docs/specs/game-history`); the mobile app needs Keycloak login first. + +- [ ] Ongoing-game banner, live and popular games, recent games on the home screen +- [ ] Move list and looking back during a live game; replay of finished games + ### After the mobile release - [ ] Turn off `LEGACY_USERKEY_AUTH` once old app versions are no longer in use; this also removes `/register` @@ -25,10 +32,18 @@ The web app logs in with Keycloak; the mobile app still uses the legacy `?userKe ### Later - [ ] Let guests turn their guest user into an account without changing identity (Keycloak required action) -- [ ] Stats and game history for logged in users (needs a database) +- [ ] Statistics for logged in users (wins, losses), now that games are saved - [ ] Social logins (Keycloak identity providers) - [ ] Restrict the Keycloak admin console in production +## Game history + +- [ ] A page with all of a user's games (the home page shows the last 3) +- [ ] Show games of deleted accounts differently, once accounts can be deleted +- [ ] Live game state, previews and spectators assume a single backend instance; share them (e.g. Valkey pub/sub) + before running more than one +- [ ] If Valkey is unreachable when the backend starts, live games are not restored until the next restart + ## Deployment - [ ] Build the backend and frontend images from the repo root in CI: @@ -37,6 +52,9 @@ The web app logs in with Keycloak; the mobile app still uses the legacy `?userKe - [ ] Deploy Keycloak (`apps/.env` with `KEYCLOAK_DB_PASSWORD`, `KEYCLOAK_ADMIN_PASSWORD`, `KEYCLOAK_HOSTNAME=https://auth.playmancala.app`) and reload nginx with the new `auth.playmancala.app` block - [ ] Deploy the backend before the web app; the new web app needs token auth on the server +- [ ] Back up the Postgres volume (Keycloak and saved games), e.g. a daily `pg_dumpall` +- [ ] Set `MANCALA_DB_PASSWORD` and `POSTGRES_PASSWORD` in `apps/.env` on the server; the `postgres` volume replaces + `keycloak-db`, so Keycloak starts with a fresh database there ## Security @@ -48,16 +66,10 @@ The web app logs in with Keycloak; the mobile app still uses the legacy `?userKe ## Bugs -- [ ] `GameStoreImpl.getSpeactatingGameIdsByUser` loops with `for...in` over an iterator, so it never finds - anything and spectators are never removed on disconnect; use `for...of` -- [ ] Finished and abandoned games are never removed from `gameStore` (`deleteGame` only removes the user - mappings), so they stay in memory until restart - [ ] `PitAnimator.animatePit`: `previousPitIndex > 0` should be `>= 0`; a one-stone move from pit 0 does not empty that pit during the animation - [ ] `PitAnimator.dispose` removes a newly bound function, so the theme listener is never removed - [ ] Sowing puts stones into the opponent's store; check against the intended Mangala rules and add a test -- [ ] `MatchMaker.join` does not check whether the player is already in a game -- [ ] `GameManager.startGame` sends the connection info twice - [ ] `onGameError` broadcasts an `Error`, which serializes to `{}` ## Maintenance @@ -65,7 +77,7 @@ The web app logs in with Keycloak; the mobile app still uses the legacy `?userKe - [ ] The web and mobile apps duplicate components and stores; move shared code into `packages/core` - [ ] Mixed lockfiles: `packages/*` and `apps/mobile` have both `yarn.lock` and `package-lock.json` - [ ] Align TypeScript and Jest versions across packages -- [ ] Tests for `GameManager`, `MatchMaker` and `PitAnimator` +- [ ] Tests for `MatchMaker` and `PitAnimator` - [ ] CI that runs the tests - [ ] Pre-existing type errors: 4 in the frontend, 11 in mobile; the frontend has no `tsconfig.json`, so nothing type-checks it diff --git a/apps/backend/README.md b/apps/backend/README.md index d3ac8e5..970153a 100644 --- a/apps/backend/README.md +++ b/apps/backend/README.md @@ -47,3 +47,25 @@ User ids of Keycloak users are the token subject prefixed with `kc:`. | `KEYCLOAK_JWKS_URL` | issuer + `/protocol/openid-connect/certs` | Where to fetch signing keys, if the backend reaches Keycloak at a different address | | `KEYCLOAK_CLIENT_IDS` | `mancala-web` | Comma-separated clients whose tokens are accepted | | `LEGACY_USERKEY_AUTH` | `true` | Also accept old clients that connect with `?userKey=` and the `/register` endpoint. Turn off once no released client uses it, because a userKey is not a secret the server can check | + +## Saved games and live games + +Finished games are saved in Postgres; live games are copied to Valkey after every change and restored when the +backend starts, so a restart or deploy does not end them. The design is in `docs/specs/game-history`. + +| Variable | Default | Purpose | +|---|---|---| +| `DATABASE_URL` | `postgres://mancala:mancala@localhost:5433/mancala` | Saved games; migrations run on startup | +| `VALKEY_URL` | `redis://localhost:6379` | Live game state and short-lived caches | + +The backend keeps running when either is down: games are still played, finished games are saved once Postgres is +back, and lists are served without the missing data. + +| Route | Auth | Response | +|---|---|---| +| `GET /game/:id` | – | A live game, or `{ status: "finished", record }` | +| `GET /games/popular?limit=5` | – | `{ kind: "live" \| "finished", games }` | +| `GET /games/me/active` | Bearer token | `{ game }` or `{ game: null }` | +| `GET /games/me?limit=3` | Bearer token | `{ games }`, newest first | + +Tests use Docker (testcontainers) for Postgres and Valkey. diff --git a/docs/specs/game-history/requirements.md b/docs/specs/game-history/requirements.md index 23adf54..f6f4462 100644 --- a/docs/specs/game-history/requirements.md +++ b/docs/specs/game-history/requirements.md @@ -1,6 +1,6 @@ # Game history and live games: requirements -Status: approved, in development (branch `feature/game-history`, based on `feature/keycloak-auth`). +Status: implemented on branch `feature/game-history` (based on `feature/keycloak-auth`). Scope: backend and web app. The mobile app is out of scope (see `TODO.md`). ## Goals diff --git a/docs/specs/game-history/tasks.md b/docs/specs/game-history/tasks.md index feaf618..501ba18 100644 --- a/docs/specs/game-history/tasks.md +++ b/docs/specs/game-history/tasks.md @@ -22,4 +22,4 @@ Work through the tasks in order; each ends with its tests passing and a commit. rejection message. - [x] 10. **Live game history**: `MoveList`, review mode with `ReviewBanner` and keyboard, timeout countdown. - [x] 11. **Replay**: `ReplayView` with controls, speed, timeline, `?move=`, own-side orientation, duration. -- [ ] 12. **End to end and docs**: Chrome tests from `design.md`, README and `TODO.md` updates. +- [x] 12. **End to end and docs**: Chrome tests from `design.md`, README and `TODO.md` updates.