# TODO ## Auth ### Mobile login with Keycloak (phase 5) The web app logs in with Keycloak; the mobile app still uses the legacy `?userKey=` login. - [ ] Add a `mancala-mobile` public client to `apps/keycloak/realm/mancala-realm.json` (PKCE S256, redirect `com.mancala_mobile://callback`) and to `KEYCLOAK_CLIENT_IDS` for the backend - [ ] Add `react-native-app-auth` with the redirect scheme set up for Android and iOS - [ ] Log in as a guest on first launch (`guest=true`), with `offline_access`; keep tokens in MMKV - [ ] Connect with `rtmt.connectWebSocket(url, getToken)` instead of `?userKey=` (`apps/mobile/src/App.tsx`) and call `reauthenticate` after refreshing the token - [ ] Log in / sign up / log out in the app, player names on the game screen (`getPlayerDisplayName` in core) - [ ] Decide whether guests may skip the browser tab on first launch (would need a custom grant type in the Keycloak extension) - [ ] 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` ### Later - [ ] Let guests turn their guest user into an account without changing identity (Keycloak required action) - [ ] 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 ## Game clock See `docs/specs/game-clock`. - [ ] Other time controls or time added per move; a long move animates on the next player's time - [ ] Clocks in the home page's live game previews and in the ongoing-game banner - [ ] Try the mobile clocks on a device; only the type check and the bundle were run ## Web redesign See `docs/specs/web-redesign`. - [ ] Bring the new design to the mobile app (themes, board, game screen) - [ ] A rematch button on the game-over card (the design has one; there is no rematch yet) ## Deployment - [ ] Build the backend and frontend images from the repo root in CI: `docker build -f apps/backend/Dockerfile .` and `docker build -f apps/frontend/Dockerfile .` - [ ] Pass `--build-arg KEYCLOAK_URL=https://auth.playmancala.app` when building the frontend image - [ ] 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 - [ ] Release the mobile update with the game clock before or with the backend: older app versions do not show the clock and do not handle `on_game_end`, so a game they lose on time does not end for them - [ ] 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 - [ ] Move the Android signing passwords out of `apps/mobile/release_android.sh` (committed in `bb1c750`) into `~/.gradle/gradle.properties` or environment variables, and consider resetting the upload key - [ ] Add `apps/mobile/mancala-upload-key.jks` to `.gitignore` (only `android/app/mancala-upload-key.jks` is ignored) - [ ] Validate moves before running them instead of treating every invalid move as a crash: each one writes a file to `crashes/` and is broadcast to the players (`GameManager.onGameError`) ## Bugs - [ ] `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 - [ ] `onGameError` broadcasts an `Error`, which serializes to `{}` ## Maintenance - [ ] 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 `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