mancala/TODO.md
Halit Aksoy 6f88658c60 feat(frontend): simplify the header as in the updated design
The header is now the logo, the page's actions, how to play, settings
and the account. The theme swatches move into a settings menu; the
account shows the player's initials and is on every page through an
AuthUserContext. On phones the home page's actions leave the header for
a row of two buttons. Checked menu items get a check at their end.
2026-10-17 02:59:26 +03:00

7.8 KiB

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)
  • Keycloak email theme in the game's look (password reset emails still use Keycloak's)
  • 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

Game bot

See docs/specs/game-bot.

  • Play against the bot without a connection (a bot in the TypeScript engine on the device)
  • Keep bot games apart once there are statistics or ratings
  • Hints or move analysis for players, with the same search
  • Rebuild MancalaGame on Position, or use Position to check moves before running them (see Security)
  • Tune the levels from real games (games.bot holds each game's level, strength and seed)
  • Try the bot on a mobile device; only the type check and the bundle were run

Tutorial

See docs/specs/tutorial.

  • Lessons and hints in the mobile app, once it has the new design (it has the rules screen)
  • Hints that look ahead, e.g. a warning when a move lets the opponent capture (the bot's search could do it)
  • Strategy lessons beyond the rules
  • Tutorial progress per account instead of per device
  • If the end-of-game rule changes (Game rules below), update RuleEndOfGameText2 in en.ts and tr.ts

Web redesign

See docs/specs/web-redesign.

  • Bring the new design to the mobile app (themes, board, game screen)
  • The design's "Sound effects" switch in the settings menu, once the app has sounds

Rematch

See docs/specs/rematch.

  • Rematch and the series strip in the mobile app, with its new design; until then a web player's request to a mobile player ends after a minute
  • Series of a fixed length ("best of 3") and a series winner
  • Group series in the game history and on the home page (games.series_id)
  • Take spectators along to the next game of a series
  • Leaving the game page does not answer a request; the opponent waits for the minute to pass

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
  • The backend is now Java (Quarkus, see docs/specs/quarkus-backend); the compose file passes the database as DATABASE_JDBC_URL/DATABASE_USERNAME/DATABASE_PASSWORD built from the same MANCALA_DB_PASSWORD, so apps/.env needs no change. It reads the Node backend's database and live games, so it can replace it (and be rolled back) without ending games
  • 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
  • Last step: publish a new mancala.js to npm (it is at 0.0.2-beta.3 from 2022), so the published engine skips the opponent's store when sowing. The apps do not need it; they use packages/mancala.js through link:

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, kept as it was in the Node backend)

Game rules

  • Decide who gets the remaining stones when a move empties the opponent's side (e.g. a capture takes their last stones). Now the player whose side is empty always gets the other side's stones (GRClearBoardAtEnd), even when the opponent emptied it; some Mangala rules give them only to a player who emptied their own side. Analyse the rule first, then decide

Bugs

  • PitAnimator.dispose removes a newly bound function, so the theme listener is never removed
  • onGameError broadcasts {} instead of the error (the Java backend sends {} on purpose, as the Node backend did)

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; PitAnimator is only tested for the first frame of a move
  • CI that runs the tests (the backend's need a JDK 25 and Docker)
  • The rules exist twice, in packages/mancala.js and in the backend's Java port; a parity test keeps them alike, but every rule change has to be made in both
  • Pre-existing type errors: 1 in the frontend (react-dom/client), 11 in mobile; the frontend has no tsconfig.json, so nothing type-checks it