Learning pathsA
GUIDED PRACTICE

Online Chess

Design turn-based online chess with authoritative legal moves, clocks, reconnects, and game history.

Interview scope and guarantees

Create a game, match players, accept legal moves, maintain clocks, reconnect and display spectators. The server decides move legality, turn order and result. Client animations may be optimistic; client clocks cannot determine the winner.

Capacity worksheet

Assume 100,000 concurrent games with a move every 5 seconds per game: 20,000 moves/s. At 200 bytes/move that is 4 MB/s raw. A famous match can have far more spectators than players, so separate authoritative game commands from spectator fanout.

Concrete API contract

Contract / pseudocode
POST /games {opponentId,timeControl}
POST /games/{id}/moves {clientMoveId,expectedPly,from,to,promotion?}
GET /games/{id}?afterPly=...
POST /games/{id}/resign

Data model and access paths

Contract / pseudocode
games(id PK,white_id,black_id,position,ply,state,owner_epoch,turn_started_at,remaining_times,version)
moves(game_id,ply,actor_id,client_move_id,request_hash,notation,accepted_at); UNIQUE(game_id,ply); UNIQUE(game_id,actor_id,client_move_id)
results(game_id UNIQUE,winner,reason,rating_version)

Evolve a solution and explain each change

Three architecture decisions for Online Chess, including the pressure each introduces.
Scroll to inspect the diagram, or open it at full size.

Figure — Three architecture decisions for Online Chess, including the pressure each introduces.

Step 1: Authoritative game state

Validate moves against the current board and player turn. Two clients cannot both define the next legal state.

Step 2: Order moves and clocks

Apply move identity, expected position version, and server clock rules together. Client timestamps and duplicated packets can corrupt turn order.

Step 3: Recover sessions

Replay committed moves after reconnect and separate spectators from players. Socket presence is not proof that a player forfeited.

Responsibility overview

Connected responsibilities for Online Chess. Trace the authoritative and derived paths separately.
Scroll to inspect the diagram, or open it at full size.

Figure — Connected responsibilities for Online Chess. Trace the authoritative and derived paths separately.

Worked end-to-end scenario

White sends move e2-e4 at board version 12, then retries after a lost response. The authority validates legality, turn, version, and remaining time and records one move identity. The retry returns version 13 rather than consuming a second turn. Black reconnects and replays from version 12. Clock accounting uses a defined server admission instant and monotonic elapsed time, with a stated lag/timeout policy. A late move received after expiry cannot be accepted based solely on the player’s device clock. Spectator delivery can lag without changing the authoritative result.

Why these access paths matter

Store game ID, players, board version, clock state, outcome, and ordered moves. Use game as the serialization domain and actor/client move ID for retries. A board snapshot plus move suffix supports recovery; both need a consistent version boundary. Presence, chat, and spectator subscriptions are independent from legal move state.

Build the baseline first

Online Chess: baseline request paths.
Scroll to inspect the diagram, or open it at full size.
  1. Player move → game owner → legality and clock check.
  2. Atomic position update → durable move → opponent.
  3. Reconnect → position snapshot and move suffix.

Evolve the design under load

Online Chess: additional scaling and recovery paths.
Scroll to inspect the diagram, or open it at full size.
  1. Game-key routing → independent state owners.
  2. Spectator stream → regional gateways.
  3. Completed games → rating jobs and analysis queue.

Defend the hardest decision

Validate expected ply, player identity, legal movement and remaining time in one authoritative transition. Persist the clock baseline rather than decrementing a database row every millisecond. A server process uses a monotonic clock for elapsed time within its lifetime; failover needs a documented persisted-time policy and synchronized server clocks. The chosen lag-compensation rule must be explicit and abuse-resistant.

Failure and recovery analysis

A move commits but its response is lost. A retry with the same clientMoveId returns the committed move. A different move for the old ply is rejected. An old game owner returning after failover must be fenced from committing moves. Spectator lag can grow without delaying the players, provided buffers are bounded.

Security and privacy boundary

Authorize player actions, protect matchmaking from abuse, and separate anti-cheat analysis from the low-latency move path.

Interview follow-ups with reasoning

Question: How do you resolve simultaneous resign and move?

Show answer and explanation

Answer: Serialize commands at the game owner.

Question: How do you rebuild a board?

Show answer and explanation

Answer: Replay validated moves from a versioned initial position.

Question: How do you update ratings safely?

Show answer and explanation

Answer: Deduplicate by completed game and rating algorithm version.

Operate and verify the design

Move latency, stale-ply rejections, clock anomalies and duplicate rating jobs.

Fail over the game owner during a move and verify one committed ply and a consistent clock baseline.

A second scenario to test transfer

White and Black both submit moves against version 40 due to a client bug. Only White is side to move. The game authority validates White’s move and commits version 41. Black’s stale command fails with current version and board. If White retries after losing the response, the same request ID returns the committed ply rather than applying another move.

White’s move request commits, but the response is lost. What happens when the client retries and Black submits against the old version?

Show answer and explanation

Answer: White retries with the same request ID and receives the already committed ply. Black’s command is checked against the authoritative side and version; it cannot overwrite White’s move. The next valid move uses the new version. This provides idempotent command handling and one game order.

Compare alternatives

EventAuthoritative?Recovery
Board animationNoReplace with snapshot/event
Committed plyYesReplay by ply cursor
Displayed clockApproximationServer turn deadline
PresenceEphemeralReconnect and refresh

A design-changing exercise

Both clients say their clocks had time remaining. Which timestamp decides the result?

Show answer and explanation

Answer: Use the defined authoritative server admission and clock policy. Client clocks are not trustworthy enough to own the game outcome.

Design workshop: moves, clocks, and owner recovery

Core scope is standard chess, matchmaking, timed games, reconnect and spectators. Variants and anti-cheat model training are extensions. Use a tested rules library for legality; a client move is a proposal. Choose server admission time as the clock boundary with no latency compensation in this teaching baseline, and disclose that policy. Client animation and displayed clocks remain estimates.

Store FEN-like board state plus move history, castling rights, en-passant state, side to move, half-move counter and repetition evidence. Piece locations alone cannot reconstruct all legal state. Validate check, promotion, castling and en-passant under the selected rules; distinguish claimable and automatic draws using documented rules. Do not turn every repeated board diagram into a draw without comparing legal-position state.

The move identity is unique(game,actor,client_move_id) with fingerprint. Before rejecting expectedPly, check whether that exact command already committed and return its original ply. Then lock game state, validate actor/turn/version/owner epoch/time/legality and atomically append the move with updated board and clock. A retry cannot consume a second turn.

Lost response returns the already committed move. White to Game authority: e2-e4 request m7 at expected ply 12; Game authority to Move log: Commit m7 as ply 13 with updated clock; Game authority to White: Response lost; Black to Game authority: Move using stale expected ply 12; Game authority to Black: Conflict; return current ply 13; White to Game authority: Retry m7; request lookup returns original ply 13
Scroll to inspect the diagram, or open it at full size.

Figure — Lost response returns the already committed move.

With 60 seconds remaining, White starts at monotonic t=100 and the server admits a legal move at t=104. Charge four seconds and add a two-second increment, leaving 58 seconds. The increment applies only after an accepted legal move. A rejected illegal request does not pause the clock. If a move arrives after the declared remaining time expires, reject under the selected policy; claimed device send time cannot override it.

Clock accounting and failover policy. White starts at t=100 / 60 seconds remaining / Durable owner epoch and turn anchor; Legal move admitted t=104 / 60 - 4 + 2 increment / 58 seconds for White; Black's turn starts; Illegal move / No board/turn commit / Current player's clock continues; Owner crashes / Monotonic clock cannot transfer directly / Fence old owner; recover durable deadline under declared pause/failover policy
Scroll to inspect the diagram, or open it at full size.

Figure — Clock accounting and failover policy.

For this baseline choose an explicit operational pause while game authority recovery is uncertain, recording the pause event and resuming with persisted remaining time adjusted to the last trusted clock checkpoint. This trades fairness precision for transparent recovery; it cannot claim submillisecond time accuracy after losing an unpersisted interval. An alternative is a trusted durable wall deadline with bounded skew and owner epochs, but its error must be stated and tested. Never subtract one machine's monotonic timestamp from another's.

Matchmaking stores region/rating/time-control queues and uses an atomic pair claim to prevent one player entering two games. A declared expanding rating band reduces long waits. Ratings update once under unique(game,rating_version). An illustrative Elo update uses expected score E=1/(1+10^((opponent−player)/400)), then R_new=R+K(S−E); equal ratings with K=20 and a win gain 10. This is a chosen teaching policy, not a claim about a chess platform's real rating algorithm.

Spectator gateways consume committed ply events separately from player commands. A reconnect supplies afterPly; return suffix or board snapshot+cursor when history no longer supports it. Bound spectator buffers and never let a million watchers exhaust move authority. Privacy/authorization still applies to private games.

Exercise: White's request committed ply 13 but response was lost. Its retry carries expectedPly=12. Reject as stale or replay?

Show answer and explanation

Answer: Look up the stable actor/request identity first and return committed ply 13. Only an unseen command with old expectedPly conflicts. This ordering is part of the API contract, not just a uniqueness constraint.

FIDE rules are the source for chess legality/draw distinctions; the online clock and recovery policy above is a separate system choice.

Technical references

PostgreSQL transaction isolation and concurrent updates.

11:00Self-guided practice timer
The timer resets when you leave this page. Save your design separately.
Your challenge

White’s move request commits, but the response is lost. What happens when the client retries and Black submits against the old version?

Your design draft

Clarify assumptions, explain your approach, and test the difficult cases. Save your draft, then compare it with the study notes.

Read study notes

Self-review checklist

Self-guided practice. Automated AI feedback and code execution are not connected.