List the key functional requirements for the system (Ask the AI for hints if stuck)...
Nice-to-haves
List the key non-functional requirements (performance, scalability, reliability, etc.)...
Define the APIs expected from the system. This is your chance to analyze and define the read and write paths so that you can come up with the high-level design...
Item
Auction
Note: max_bid denormalized on Auction is a deliberate choice to avoid expensive MAX() queries and locking the Bids table under contention. This way we only lock one row to read the max bid - the auction.
Bid
1) Creating an auction
POST /auctions -> Auction
request body
{
itemId,
startPrice,
startTime,
endTime
}
2) Get an auction's details
GET /auctions/:auction_id -> Auction
3) Get an auction's bid (paginated as it can have hundreds of bids)
GET /auctions/:auction_id/bids?page={page}&limit={limit} -> Bid[]
Paginated endpoint for bid history
4) Place a bid
POST /auctions/:auction_id/bids -> Bid
request body {
amount
}
// Bid has status 'Accepted' or 'Rejected'
Describe the overall system architecture. Identify the main components needed to solve the problem end-to-end. Use the diagramming tool to create a block diagram.
Client
API Gateway: authentication, rate limiting, request routing
Auction Service: create auction, read auction details, list all auctions
Bid Service: Place bid, validate, pessimistic locking
Notification Service: SSE connections, subscribe to Redis channel
Redis Pub/Sub: channel per auction_id
Bid Service publishes bids to Redis Pub/Sub
Notification Service subscribe to Pub/Sub
Database: PostgreSQL; holds Items, Auctions, Bids, Users
Why separate the Bid Service vs Auction Service?
Data Flows:
1) Create auction
Client -> API Gateway -> Auction Service -> PostgreSQL
2) View auction
Client -> API Gateway -> Auction Service -> PostgreSQL
3) Place a bid
Client -> API Gateway -> Bid Service -> PostgreSQL (pessimistic locking FOR UPDATE) -> Redis Pub/Sub publish
Notification Service -> SSE -> Client
Deep dive into 2-3 key components. Explain how they work, how they scale, discuss tradeoffs, capacity, and any relevant algorithms or data structures.
1) How do we know we have a winning Bid?
The Auction has an end_time. After that time, no new Bid should be accepted.
Option 1: Cron job that runs periodically and queries the db to close Auctions.
Pros: Simple
Cons: Query load on DB
Option 2: When the auction is created, a scheduled task for exactly the end time
Pros: No polling
Cons: More infra (need reliable task scheduled, can also fail)
After the auction is closed, we publish to an SNS/Kafka durable queue which handles multi-protocol fan out
2) What happens if during the final 30 seconds of a hot auction you have 100 bids/seconds hitting the same row?
Use queue-based serialisation: Kafka