CASE STUDY

Daily Puzzle Platform (Wordle-style)

3 min read·507 words·Beginner

How to use this case study

SDE-2 / Mid

Design the APIs and data model for daily puzzles, attempts, scoring and streaks, with server-side answer checking.

SDE-3 / Senior

Handle the release spike (everyone plays at midnight), time zones, anti-cheating (never send the answer), and leaderboards.

Staff / Principal

Discuss content scheduling, statistics at scale, and extending to multiple puzzle types and competitive modes.


0) Problem Restatement

Design a platform for a daily puzzle (asked at Uber), like Wordle or a daily crossword. Every day, all users get the same new puzzle. They submit attempts, the server checks them and gives feedback, and a solved puzzle earns a score. Users keep streaks (days in a row solved), see statistics, and compare on leaderboards (global and friends).

Asked at: Uber — 1 candidate report between Apr 2026 and Apr 2026.

1) Requirements

  • Publish one puzzle per day (scheduled in advance).
  • Submit guesses and get feedback (e.g., which letters are right), with limited attempts.
  • Scoring (fewer attempts or faster = better), streaks and personal stats.
  • Leaderboards: daily global and friends.
  • Fair play: answers never leak to the client ahead of time.

1.1 Scale

  • 10M daily players, most within a few hours of release. Peak ~50K guesses/sec right after release.


2) APIs

GET  /v1/puzzles/today?tz=Asia/Kolkata     → { puzzle_id, date, type, board (no answer), max_attempts }
POST /v1/puzzles/{id}/guesses  { guess }    → { feedback, attempts_left, solved, score? }
GET  /v1/me/stats                            → { streak, max_streak, played, win_rate, distribution }
GET  /v1/puzzles/{id}/leaderboard?scope=global|friends&cursor=

3) Architecture

Architecture Diagram

flowchart LR
    U["Players"] --> CDN["CDN - puzzle metadata (no answers)"]
    U --> API["Game API - stateless"]
    API --> PZ[("Puzzle store - answers encrypted")]
    API --> AT[("Attempts - by user, puzzle")]
    API --> LB[("Redis sorted sets - leaderboards")]
    API --> K[("Events")]
    K --> ST["Stats + streak updater"]
    ST --> SDB[("User stats")]
    ADM["Editors"] --> SCH["Puzzle scheduler"]
    SCH --> PZ

4) Key Design Points

  • Server-side checking: the client never receives the answer. Each guess is checked on the server, and feedback is returned. (Wordle originally shipped the answer list in JavaScript, which was easy to cheat.)
  • Attempts are stored per (user_id, puzzle_id) with a count, the guesses and solved status. The server enforces max_attempts, and a unique key prevents double-submits from racing (use a conditional update on the attempt count).
  • Time zones: "today" depends on the user's local date (release at local midnight) or a single global release time. Pick one. Local midnight spreads the load across the day, which is good for spikes.
  • Scoring: e.g., score = base − attempts_used × penalty − time_bonus. Store it when solved.
  • Streaks: update on solve. If the last solved date = yesterday (in the user's time zone), streak + 1, otherwise reset to 1. The streak "expires" if a day is missed, which is checked lazily when the user plays or reads stats.
  • Leaderboards: a Redis sorted set per puzzle lb:{puzzle_id} (score → user). Friends leaderboard = fetch friends' scores for that puzzle (a small set) and sort. Persist final results to the DB.


5) Handling the Spike

  • Puzzle metadata (without the answer) is cached at the CDN, since it's identical for everyone.
  • The game API is stateless and pre-scaled before release. Answers are cached in memory on API servers (loaded securely at release time).
  • Attempts are written to a partitioned store (by user), which spreads writes evenly.
  • Stats updates are asynchronous via events, so the guess path stays fast.


6) Wrap-Up

Schedule puzzles in advance and serve today's puzzle (without the answer) from a CDN, check every guess on the server with enforced attempt limits stored per user and puzzle, and compute scores on solve. Update streaks and stats asynchronously with time-zone-aware day logic, keep leaderboards in Redis sorted sets (with friends' boards computed from small friend lists), and spread or pre-scale for release spikes.

More Case Studies

Practice with a Mock Interview

Apply what you learned in a live system design mock interview with our AI interviewer.

Start System Design Interview →