# el3ab-player — WTF-to-Ship Roadmap

**Goal:** All 4 games (chess, ludo, domino, backgammon) multiplayer-ready
**Team:** Solo director + AI development
**Timeline:** Quality-first, no hard deadline
**Workflow:** Fix and push immediately per fix

---

## Phase 0: Foundation (Security + DB Integrity)
> Nothing else matters if any user can cheat any match.

| # | Task | WTFs Fixed | Est. Effort |
|---|------|-----------|-------------|
| 0.1 | Add auth checks to `game.php` — verify userId is a player in the match before move/resign/complete | #1-4 | 30 min |
| 0.2 | Validate `$winners` in `complete_match` RPC — verify UUIDs are actual match participants | #4, schema | 20 min |
| 0.3 | Fix `accept-invite` / `decline-invite` — verify accepting user is the target | #5-6 | 20 min |
| 0.4 | Sanitize PostgREST filter inputs in `friends.php` (search, profiles) | #10-11 | 15 min |
| 0.5 | Restrict CORS to actual app domains | #9 | 10 min |
| 0.6 | Move secrets to env vars (constants.php → server env) | #7-8 | 20 min |
| 0.7 | Validate `time_control` and `result` against enum values before DB writes | schema #2-3 | 15 min |
| 0.8 | Add missing DB indexes (matches, matchmaking_queue, notifications, friendships) | schema perf | 15 min |
| 0.9 | Add missing `reward_config` rows (chess XP, backgammon all) | schema #5-6 | 10 min |
| 0.10 | Fix `handleDraw` — use `merge_game_state` RPC instead of raw PATCH | #46, schema | 15 min |

**Phase 0 result:** No exploits possible. DB performance sane. Rewards work for all games.

---

## Phase 1: Chess Multiplayer Bulletproof
> Chess already works for random. Fix friend invites + eliminate race conditions.

| # | Task | WTFs Fixed | Est. Effort |
|---|------|-----------|-------------|
| 1.1 | Fix friend invite color assignment — ensure `friends.php` returns proper color, lobby passes it correctly | #18 | 30 min |
| 1.2 | Fix lobby desync — add handshake (both players confirm ready before entering game) | #28-30 | 45 min |
| 1.3 | Fix `multiplayer.js:79` — show real error on friend request failure instead of fake success | #15 | 10 min |
| 1.4 | Fix emote/rematch — use `merge_game_state` RPC, don't overwrite via `action:'move'` | #16-17 | 30 min |
| 1.5 | Fix `match-session.js` — remove visibility change listener on destroy, fix null dereference | #24, #37 | 15 min |
| 1.6 | Add concurrency guard to match polling (prevent overlapping requests) | #34 | 15 min |
| 1.7 | Fix `onConnectionRestored` firing on every poll (only after actual disconnect) | #35 | 10 min |
| 1.8 | Fix `net.js` — handle non-JSON responses gracefully | #23 | 10 min |
| 1.9 | Fix modal stacking — support concurrent modals or queue them | #22 | 20 min |
| 1.10 | Fix `opponentRating` using botElos in live mode | #47 | 5 min |
| 1.11 | Fix rematch always sending `rapid_10_0` — pass actual time control | #54 | 5 min |
| 1.12 | Remove dead `chess/logic/live.js` file | #19 | 2 min |
| 1.13 | Fix clock/board singleton issues — cleanup on unmount | #48, #19 | 20 min |

**Phase 1 result:** Chess fully works — random match + friend invites + rematch + draw offers.

---

## Phase 2: Ludo Multiplayer
> Bring ludo from bot-only to working multiplayer.

| # | Task | WTFs Fixed | Est. Effort |
|---|------|-----------|-------------|
| 2.1 | Fix `isLoser` undefined — use proper placement check | #25 | 5 min |
| 2.2 | Fix bot indicator grabbing wrong `<span>` | #55 | 5 min |
| 2.3 | Wire up ludo multiplayer using same `match-session.js` pattern as chess | — | 2 hr |
| 2.4 | Fix `api/multiplayer.php` table routing — chess shouldn't write to `ludo_matches` | #45 | 10 min |
| 2.5 | Fix room code uniqueness — add retry on collision | #98 | 10 min |
| 2.6 | Fix join_room race condition — use atomic DB operation | #32 | 20 min |
| 2.7 | Add friend invite flow for ludo (reuse fixed chess pattern) | — | 30 min |
| 2.8 | Remove dead `ludo/logic/live.js` | #150 | 2 min |
| 2.9 | Test full flow: create room → invite friend → play → result | — | 30 min |

**Phase 2 result:** Ludo works 2-4 player multiplayer with friend invites.

---

## Phase 3: Domino Multiplayer
> Domino has more MP code than ludo but has sync issues.

| # | Task | WTFs Fixed | Est. Effort |
|---|------|-----------|-------------|
| 3.1 | Fix `dealAndSyncToServer` error handling — don't swallow sync failure | #100 | 10 min |
| 3.2 | Fix `syncPassToServer` — don't pre-increment moveCount before network call | #41 | 10 min |
| 3.3 | Fix `drawFromBoneyard` rapid sync — debounce or serialize | #42 | 20 min |
| 3.4 | Fix `winners` array using potentially empty `state.players` | #209 | 10 min |
| 3.5 | Wire friend invite flow for domino (reuse fixed pattern) | — | 30 min |
| 3.6 | Fix `check-invites` full table scan — add player filter | #81-82 | 15 min |
| 3.7 | Test full flow: create → invite → deal → play rounds → result | — | 30 min |

**Phase 3 result:** Domino works 2-player multiplayer with proper sync.

---

## Phase 4: Backgammon Multiplayer
> Backgammon has game-breaking logic bugs to fix first.

| # | Task | WTFs Fixed | Est. Effort |
|---|------|-----------|-------------|
| 4.1 | Fix `VARIANTS.standard` crash — use proper fallback | #26 | 5 min |
| 4.2 | Fix `getPipCount` — accept variant parameter | #27 | 10 min |
| 4.3 | Fix `Object.assign(game, data.game_state)` clobbering local state | #56 | 15 min |
| 4.4 | Add quit confirmation dialog (match other games) | #76 | 10 min |
| 4.5 | Fix XSS in `params.opponentName` innerHTML injection | #113 | 5 min |
| 4.6 | Wire multiplayer using `match-session.js` pattern | — | 2 hr |
| 4.7 | Wire friend invite flow (reuse pattern) | — | 30 min |
| 4.8 | Sync chat messages to server (currently local-only) | #77 | 20 min |
| 4.9 | Test full flow: create → invite → play → doubling → result | — | 30 min |

**Phase 4 result:** Backgammon works multiplayer across all 3 variants.

---

## Phase 5: Core UX Fixes
> Make the app usable beyond just playing games.

| # | Task | WTFs Fixed | Est. Effort |
|---|------|-----------|-------------|
| 5.1 | Fix notifications — add click handlers that navigate to source | #65 | 30 min |
| 5.2 | Fix "My Games" — route to correct game's history | #61 | 5 min |
| 5.3 | Fix tournament "Play Now" — route based on game_key | #58 | 5 min |
| 5.4 | Fix chat scroll — remove `|| true`, only auto-scroll on new messages | #68 | 5 min |
| 5.5 | Fix chat incremental fetch — send `lastTime` to server | #69 | 15 min |
| 5.6 | Fix notifications marking all read on mount — wait for user action | #66 | 10 min |
| 5.7 | Fix queue — add timeout (60s default) with "retry or cancel" prompt | #156 | 15 min |
| 5.8 | Fix spectate routing — domino/backgammon shouldn't go to chess-spectate | #57 | 10 min |
| 5.9 | Fix shop `canAfford` — check gems too | #59 | 5 min |
| 5.10 | Fix shop — add "owned" indicator | #80 | 15 min |
| 5.11 | Fix profile — show "unrated" instead of 1200 for new players | #159 | 5 min |
| 5.12 | Fix scene.js — call unmount on current scene before clearing | #71 | 15 min |

**Phase 5 result:** No dead ends. Users can navigate the full app without confusion.

---

## Phase 6: Stability & Polish
> Eliminate race conditions, memory leaks, and architectural debt.

| # | Task | WTFs Fixed | Est. Effort |
|---|------|-----------|-------------|
| 6.1 | Unify disconnect detection — remove `multiplayer.js:startDisconnectWatch`, use only `match-session.js` | #87, #107 | 20 min |
| 6.2 | Fix all module-level singleton leaks — reset on unmount (friends timers, lobby state, queue) | #63, #91, #204-206 | 30 min |
| 6.3 | Fix token refresh race — add mutex so only one refresh runs at a time | #38 | 20 min |
| 6.4 | Add request timeout to `net.js` (10s default) | #175 | 10 min |
| 6.5 | Fix `scene.js` transition lock — use animation end event instead of hardcoded 300ms | #190 | 15 min |
| 6.6 | Fix duplicate disconnect systems, remove redundant `match-live.js` logic | #229 | 15 min |
| 6.7 | Fix N+1 queries in chat.php — batch unread counts and last messages | #83-84 | 30 min |
| 6.8 | Fix auth.php double token verification | #86 | 10 min |
| 6.9 | Fix `deleteAccount` — cascade delete related data | #94 | 20 min |
| 6.10 | Fix `rewards/achievements.js` recursive mount | #43 | 10 min |

**Phase 6 result:** App is stable. No memory leaks. No race conditions in core flows.

---

## Phase 7: i18n + Theming Compliance
> Make the app fully brandable and properly localized.

| # | Task | WTFs Fixed | Est. Effort |
|---|------|-----------|-------------|
| 7.1 | Replace all hardcoded Arabic strings with `t()` calls | #117-122 | 30 min |
| 7.2 | Replace all hardcoded emojis with `emoji()` calls | #123-135 | 45 min |
| 7.3 | Replace hardcoded colors in chess/game.js, challenge.js, lobby.js, modal.js with CSS vars | #101-105 | 1 hr |
| 7.4 | Replace magic numbers with configurable values or named constants | #136-148 | 30 min |
| 7.5 | Remove dead code (live.js, disabled const, unused functions) | #149-153 | 10 min |
| 7.6 | Fix `object-fit: contain` on all remaining images/icons | — | 15 min |

**Phase 7 result:** Full theme compliance. All text localizable. Zero hardcoded visuals.

---

## Phase Summary

| Phase | Focus | WTFs Resolved | Cumulative |
|-------|-------|---------------|------------|
| 0 | Security + DB | ~25 | 25 |
| 1 | Chess MP bulletproof | ~20 | 45 |
| 2 | Ludo MP | ~10 | 55 |
| 3 | Domino MP | ~10 | 65 |
| 4 | Backgammon MP | ~10 | 75 |
| 5 | Core UX | ~15 | 90 |
| 6 | Stability | ~20 | 110 |
| 7 | i18n + Theming | ~40 | 150 |

**Remaining ~90 minor issues** (polish, edge cases, performance) can be fixed incrementally during/after these phases.

---

## Success Criteria — "Shippable"

- [ ] Any user can play all 4 games against random opponent via matchmaking
- [ ] Any user can invite a friend and play all 4 games together
- [ ] No security exploits — users cannot tamper with others' matches
- [ ] No game state corruption — emotes, draws, reconnects all work
- [ ] No dead-end screens — every button leads somewhere meaningful
- [ ] App works offline-gracefully (shows errors, doesn't crash)
- [ ] All rewards credited correctly for all games
- [ ] Theme system fully applied — admin can rebrand without code changes
