What an interviewer expects you to nail down before drawing a single box.
GET /v1/events/{id}/seats → { seats: [{ id, status, price }] }POST /v1/events/{id}/holds { seat_ids, session } → { hold_id, expires_at }POST /v1/holds/{id}/checkout { payment, idempotency_key } → { order_id, status }GET /v1/queue/{event_id}/position → { position, eta }Think about the moment a Taylor Swift tour goes on sale and ten million people slam the site in the same thirty seconds, all reaching for the same few thousand seats. Two of them must never both walk away with seat 42A, and the site has to stay up. That collision of extreme contention and a wave of traffic is the whole problem.
Here is the whole thing in plain terms. When a hot drop goes live, users do not hit the booking flow directly. A virtual queue puts them in a waiting room and drips them onto the real system at a rate it can actually handle, handing each one a position number and an honest ETA. The API gateway checks for a signed 'queue passed' token so nobody can sneak around the line. Once admitted, a user picks a seat and the booking service grabs a short-lived lock on it in Redis with a SETNX, holds it for about five minutes, calls Stripe for payment, and only on success commits the seat as sold.
The Redis lock has a TTL, and that detail does the heavy lifting. It is like a store clerk holding an item at the counter for five minutes: if you wander off, it goes back on the shelf automatically. Without that auto-expiry, abandoned carts would lock seats forever and a venue would 'sell out' at thirty percent capacity. The TTL has to roughly match real checkout time, since too short loses buyers and too long ties up inventory.
The lock layer is fast but it is not the source of truth. When payment succeeds, the booking service runs a single atomic transaction in Postgres that marks the seat sold and writes the order together. Either both commit or neither does, so you never end up with a charged customer holding no ticket. Redis owns the transient hold, Postgres owns the durable allocation that actually prevents double-sells.
This system teaches the lock-plus-TTL pattern for holding limited inventory, why a virtual queue beats plain rate-limiting on user experience while protecting the backend just as well, atomic transactions for money-adjacent writes, and the split between a fast transient lock layer and a durable transactional source of truth.