Handbooks / System Design Case Studies / Chapter 12
Design a Food Delivery App like Zomato
11 pages · ~16 min✓ Reviewed
Builds on Design a Payment System. Next up: Design a Ride-Hailing App like Uber.
Problem, Scope and Requirements (Food Delivery App)
1. Scope and Features
browse, order, pay
track, rate
accept orders
menu and stock
accept offers
share GPS
- 1Search
- 2Menu
- 3Cart
- 4Order
- 5Pay
- 6Assign partner
- 7Track
- 8Notify
- 9Rate
- Out of scope: grocery delivery
High-Level Architecture (Food Delivery App)
1. Edge and Core Services
- CDN: serves images and menus close to the user
- API gateway: auth, rate limit and routing to services
- Clients never call a core service directly
- Appscustomer, restaurant, partner
- CDNimages, menus
- API gatewayauth, rate limit, routing
- 8 core servicesbehind the gateway
Restaurant Search and Discovery (Food Delivery App)
1. Responsibilities and Design
- Find open, deliverable restaurants and dishes near the user
- Rank by relevance, ETA, rating and offers
- One Elasticsearch index, sharded by a city-region geo cell
- Query =
geo_distancefilter + textmatch+ ranking score - Shard by city-region so a 5-8 km query hits one shard
Menu and Cart (Food Delivery App)
1. What the Service Owns
- Serve menus: read-heavy, about 100:1 reads to writes
- Peak figures: about 7,000 menu reads/s vs 70 writes/s
- Track item availability and current prices
- One cart per user, bound to one restaurant
- Cart holds intent only; the price is never final until checkout
2. Design and Caching
- Restaurant appstock flag, price
- Catalog DBPostgres / MongoDB
- Redis60s TTL
- CDN60s TTL
- Customer appmenu screen
Order Service and State Machine (Food Delivery App)
1. Responsibilities and States
- Be the single source of truth for order status
- Validate every transition; reject illegal jumps
- Emit an event on each change (Kafka)
- Side exits:
CANCELLED,REJECTED,REFUNDED - Other services react to events, they never write
orders
- CREATEDorder saved
- PAYMENT_PENDINGawaiting PSP
- PAIDwebhook ok
- RESTAURANT_ACCEPTEDwithin 3 min
- PREPARINGkitchen
- READYpacked
- PICKED_UPpartner has it
- DELIVEREDterminal
Payments (Food Delivery App)
1. Responsibilities and Design
- Charge once: no double charge, ever
- Methods: UPI, cards, wallet, COD
- COD: collected at delivery, no PSP charge
- Also owns refunds and restaurant settlements
- Order Serviceasks to charge
- Payment Serviceone PSP interface
- Razorpayprimary PSP
- Paytmfallback on gateway error
Delivery Partner Assignment (Food Delivery App)
1. Goal and Candidate Matching
- Goal: pickup time = food-ready time for every order
- Minimise partner idle wait at the restaurant and total delivery time
- Locations live in Redis GEO or an in-memory H3 cell index
- Candidates: status
AVAILABLEwithin 3 km, expand to 5 km - Score = distance + load + rating + predicted prep time
| Score factor |
|---|
Live Order Tracking (Food Delivery App)
1. Responsibilities and Ingest
- Ingest partner GPS from the delivery app
- Show a live map + ETA to the customer
- Keep trip history per order (track points)
| Input | Estimate |
|---|---|
| Ping interval | every 5 s per partner |
| Transport | MQTT, or HTTP batch of several points |
Notifications (Food Delivery App)
1. Responsibilities and Design
- Tell the customer, restaurant and delivery partner about each order event
- Channels: push, SMS, in-app, email
- Transactional (order updates, OTP) always beats promotional: it never waits behind promos
- Kafka consumersorder events
- Template + preferencerender, opt-outs
- Channel workersone pool per channel
- FCM / APNs / SMS / emailexternal providers
Scaling, Failure Handling and Interview Questions (Food Delivery App)
1. Peak Hours and Sharding
- Lunch/dinner is 3x: 230 orders/s avg → 700 orders/s peak, 7,000 search/menu reads/s
- Spikes are predictable, so pre-scale autoscaling groups on a schedule, not on CPU alone
- Shed non-critical load first: recommendations, promos. Never shed order or payment paths
- Rate-limit per user at the API gateway so one client cannot eat the peak
| Data | Shard key |
|---|
Check yourself
A customer taps Pay, the network times out, and they tap Pay again. The client sends POST /orders twice. What stops a double charge, and where does it hold?
- Both requests carry the same
Idempotency-Key, so Order Service returns the same order for the second call instead of creating another. - The payments row also stores an
idempotency_key, so the PSP is asked to charge only once. - If the PSP webhook arrives twice, the duplicate is dropped by matching
psp_ref. - One check is not enough. The key has to be enforced at order creation, at the charge and at the webhook.