Security Notes
System Design

Design an Online Auction System

3 min read 6 sections

DifficultyMedium | HelloInterview: problem breakdown


Problem Statement

Design an online auction system where sellers list items, bidders place bids, and the highest bidder at auction close wins the item.

๐Ÿ“–

Real-world: Auctions are a consistency + correctness problem dressed as a real-time one โ€” money and fairness are on the line, so two bids arriving at nearly the same instant must be serialized deterministically (process bids per-item through a single ordered path, often a per-auction queue or optimistic concurrency with version checks) or you get the classic bug: two people both "win." The famous real-world wrinkle is sniping โ€” bidders firing winning bids in the final second, which eBay studied extensively and which led some sites to adopt anti-snipe auto-extensions (any bid in the last minute pushes the close out). Live price updates fan out over WebSocket/pub-sub, but the bid-acceptance path needs strong consistency. Security/integrity angles: shill bidding (sellers using fake accounts to inflate prices) and auction fraud are core trust problems, and the auction-close event is a scheduled-job correctness concern (exactly-once close, no missed auctions) โ€” tying back to the job scheduler patterns.


Requirements

Functional

  • Create auction listing (item, starting price, duration)
  • Place a bid (must exceed current highest bid)
  • Real-time current price display
  • Auction close: notify winner, charge payment, notify seller
  • Bid history

Non-Functional

  • Bid acceptance latency: < 500ms
  • Bids cannot be duplicated or lost
  • Bidding during last seconds is high-concurrency (auction sniping)
  • Consistent: only one winner; price must not be undercut by a lower bid

Core Design

Bid Consistency: The Hard Part

Accepting a bid requires:

  1. Check if bid > current highest bid (conditional)
  2. Write new bid if condition is true (update)

This is a compare-and-swap (CAS) operation. Under concurrent bids, two bidders may both check the price simultaneously and both think they've won.

Solution: optimistic locking in the DB

sql
-- Atomic: only update if current_price hasn't changed
UPDATE auctions
SET current_price = $new_bid, winning_bidder_id = $bidder_id, version = version + 1
WHERE auction_id = $id AND version = $expected_version AND current_price < $new_bid
-- Check affected rows: if 0, someone else won the CAS โ†’ return "outbid"

Alternative: Redis atomic operations

lua
-- Lua script in Redis: atomic check-and-set
local current = redis.call('GET', 'auction:' .. auction_id .. ':price')
if current < new_bid then
    redis.call('SET', 'auction:' .. auction_id .. ':price', new_bid)
    redis.call('SET', 'auction:' .. auction_id .. ':winner', bidder_id)
    return 1  -- accepted
else
    return 0  -- outbid
end

Auction Sniping (Last-Second Bids)

In the final seconds, many bids arrive simultaneously. Solutions:

Extend auction on late bid

if bid arrives in last 2 minutes, extend by 2 minutes. Prevents sniping; eBay doesn't do this, but art auction houses do.

Queue + serialize

all bids in final period go into a per-auction queue, processed in order.

Auction Close

Scheduled job (or timer service):
  At auction.end_time:
    - Query highest bid (already in DB)
    - Mark auction as CLOSED, winner = highest bidder
    - Charge winner's payment method
    - Notify winner + seller
    - Update inventory

Real-time broadcast: SSE/WebSocket to all watching the auction for current price updates.


Architecture

Bid API โ†’ Bid Validator โ†’ Redis (atomic CAS) โ†’ Bid DB (Cassandra: all bids history)
                                 โ†“ (if accepted)
                         Auction DB (Postgres: current state)
                                 โ†“
                         Pub/Sub (broadcast price update)
                                 โ†“
                         WebSocket โ†’ all watchers

Auction Close Service (scheduled):
  Timer โ†’ Check auctions.end_time โ†’ Close โ†’ Payment Service โ†’ Notification

Security Considerations

ThreatMitigation
Bid manipulation (fake bids)Account verification; payment method on file before bidding
Seller shill bidding (seller bids on own item)Block bids from seller's account/IP on their own auctions
Price manipulation via CAS raceDB optimistic locking ensures only one valid winner per price
Payment fraud3DS2; payment authorization hold at bid, charge on win
Auction extension abuseRate limit bids in final window; CAPTCHA for suspicious velocity

Interview Tips

The CAS/concurrency problem is the core

optimistic locking in DB is the clean answer.

Auction sniping

mention extend-on-bid as one policy option; shows you've thought about the business rules.

Two storage tiers

Redis for the hot auction state (current price, winner) + Postgres for auction metadata + Cassandra for all bid history.