Design Food Delivery App
A food delivery app enables users to browse restaurants, place orders, and get meals delivered to their doorstep with features like real-time tracking, multiple payment options.
FR
1.Users must be able to sign up/login using email, phone number, or social media.
2.User should be able to onboard restaurant
3.Search restaurants by name, cuisine, or specific dishes.
4.Register and authenticate delivery agents.
5.System should be able to view delivery tasks assigned to them.
6.Notify delivery agents about new delivery requests.
7.Allow customers to track the status of their order (order placed, accepted, being prepared, out for delivery, delivered).
8.Notify customers about order status, special offers, and restaurant updates.
9.Allow customers to rate and review
10.Suppor multiple payment system
NFR
1.The system should be highly available( 99.99% of the time) to handle orders without downtime.
2.Search results for restaurants should load within 2 seconds. and Order placement and payment processing should complete within 3-5 seconds(low latency system)
3.System should be highly scalable to support thousands of concurrent users, restaurants, and delivery agents.
4.System should be strongly consistent
5.System should be fault tolerant
Estimates
Total users=1B
DAU=100M users
Each user makes 5 searches per day
total searches =100M*5=500M
Search QPS=500M/10^5=5k QPS
For peak = 5k*10=50k QPS
For write assume only 10% place orders=100M*10/100*5(per day 5 orders)=50M
write QPS=50M/10^5=500 QPS
Read:write=10:1
Storage
For users table =1B*1kB
For orders table = 50M*1KB=50 GB
for 1 years=50GB*400(~365) =20000GB=20TB
For 10 years=20TB*10=200TB
Number of restaurants= 100k*1MB(image for s3)=100GB
for metadata = 100k *100KB=10GB
API’s
POST /api/v1/users/register
request { "name": "John Doe", "email": "johndoe@example.com", "phone": "+1234567890", "password": "securepassword123" } response { "status": "success", "message": "User registered successfully", "user_id": "12345" }
2.POST /api/v1/users/login
request {
"email": "johndoe@example.com",
"password": "securepassword123"
}
response {
"status": "success",
"message": "Login successful",
"auth_token": "abcdef1234567890",
"user_profile": {
"user_id": "12345",
"name": "John Doe",
"email": "johndoe@example.com",
"phone": "+1234567890",
"addresses": ["123 Street, City, Country"]
}
}
3.PUT /api/v1/users/{userId}
request {
"name": "John Updated",
"email": "johnupdated@example.com",
"addresses": ["456 Avenue, City, Country"],
"phone": "+9876543210"
}
response {
"status": "success",
"message": "Profile updated successfully",
"updated_profile": {
"user_id": "12345",
"name": "John Updated",
"email": "johnupdated@example.com",
"phone": "+9876543210",
"addresses": ["456 Avenue, City, Country"]
}
}
4.GET /api/v1/users/{userId}
{
"user_id": "12345",
"name": "John Updated",
"email": "johnupdated@example.com",
"phone": "+9876543210",
"addresses": ["456 Avenue, City, Country"],
"payment_methods": [
{"type": "Credit Card", "last_four": "1234"},
{"type": "PayPal", "email": "johnupdatedpaypal@example.com"}
]
}
5.POST /api/v1/restaurants/register
request {
"restaurant_name": "Food Paradise",
"location": "123 Restaurant Street, City, Country",
"contact_email": "contact@foodparadise.com",
"contact_phone": "+9876543210",
"menu": [
{"name": "Pizza", "price": 12.99, "description": "Cheese pizza with toppings"},
{"name": "Pasta", "price": 10.99, "description": "Spaghetti with tomato sauce"}
]
}
response {
"status": "success",
"message": "Restaurant registered successfully",
"restaurant_id": "7890"
}
6.POST /api/v1/restaurants/login
request {
"email": "admin@foodparadise.com",
"password": "adminsecurepassword"
}
response {
"status": "success",
"message": "Login successful",
"auth_token": "abcdef9876543210",
"restaurant_profile": {
"restaurant_id": "7890",
"restaurant_name": "Food Paradise",
"contact_email": "contact@foodparadise.com",
"contact_phone": "+9876543210",
"menu": [
{"name": "Pizza", "price": 12.99, "description": "Cheese pizza with toppings"},
{"name": "Pasta", "price": 10.99, "description": "Spaghetti with tomato sauce"}
]
}
}
7.PUT /api/v1/restaurants/{restaurantId}/menu
request {
"menu": [
{"name": "Burger", "price": 8.99, "description": "Beef burger with cheese"},
{"name": "Salad", "price": 5.99, "description": "Mixed greens with dressing"}
]
}
response {
"status": "success",
"message": "Menu updated successfully",
"updated_menu": [
{"name": "Burger", "price": 8.99, "description": "Beef burger with cheese"},
{"name": "Salad", "price": 5.99, "description": "Mixed greens with dressing"}
]
}
8.POST /api/v1/delivery-partners/register
request {
"name": "Sarah Conner",
"phone": "+9876543211",
"vehicle_type": "Bike",
"vehicle_number": "AB123CD"
}
response {
"status": "success",
"message": "Delivery partner registered successfully",
"delivery_partner_id": "4567"
}
9.POST /api/v1/delivery-partners/login
request {
"phone": "+9876543211",
"password": "deliverypassword"
}
resposne {
"status": "success",
"message": "Login successful",
"auth_token": "abcdef6543210",
"delivery_partner_profile": {
"delivery_partner_id": "4567",
"name": "Sarah Conner",
"phone": "+9876543211",
"vehicle": {
"type": "Bike",
"number": "AB123CD"
},
"assigned_orders": [
{"order_id": "112233", "status": "Out for delivery", "pickup_location": "Restaurant XYZ"}
]
}
}
10.POST /api/v1/orders
request {
"user_id": "12345",
"restaurant_id": "7890",
"items": [
{"menu_item_id": "1", "quantity": 2},
{"menu_item_id": "2", "quantity": 1}
],
"delivery_address": "456 Avenue, City, Country",
"payment_method": "Credit Card",
"payment_details": {"card_number": "4111111111111111", "expiry": "12/23", "cvv": "123"}
}
response {
"status": "success",
"message": "Order placed successfully",
"order_id": "98765",
"order_status": "Pending"
}
11.PUT /api/v1/orders/{orderId}/status
request {
"status": "Out for delivery"
}
response {
"status": "success",
"message": "Order status updated successfully",
"order": {
"order_id": "98765",
"status": "Out for delivery",
"assigned_delivery_partner": "Sarah Conner"
}
}
12.GET /api/v1/orders/{orderId}
response {
"order_id": "98765",
"status": "Out for delivery",
"items": [
{"menu_item_name": "Pizza", "quantity": 2, "price": 12.99},
{"menu_item_name": "Pasta", "quantity": 1, "price": 10.99}
],
"total_price": 36.97,
"delivery_address": "456 Avenue, City, Country",
"assigned_delivery_partner": "Sarah Conner"
}
13.POST /api/v1/reviews
request {
"user_id": "12345",
"restaurant_id": "7890",
"rating": 4,
"review": "Great food, quick delivery!"
}
resposne {
"status": "success",
"message": "Review added successfully",
"review_id": "5678"
}
14.POST /api/v1/payments/initiate
request {
"order_id": "98765",
"user_id": "12345",
"amount": 36.97,
"payment_method": "Credit Card",
"payment_details": {
"card_number": "4111111111111111",
"expiry": "12/23",
"cvv": "123"
}
}
response {
"status": "success",
"message": "Payment initiated successfully",
"payment_id": "abcd1234",
"payment_status": "pending"
}
GET /api/v1/payments/{paymentId}
{
"payment_id": "abcd1234",
"order_id": "98765",
"payment_status": "completed",
"payment_method": "Credit Card",
"transaction_id": "txn_5678",
"amount": 36.97,
"currency": "USD"
}
Databases
1. Relational Databases (RDBMS)
Use Case: Managing structured and transactional data (e.g., user profiles, orders, payments).
DB Options: MySQL, PostgreSQL, Amazon RDS.
Schema Design
1. Users Table
CREATE TABLE Users (
user_id UUID PRIMARY KEY,
name VARCHAR(255),
email VARCHAR(255) UNIQUE,
phone VARCHAR(15) UNIQUE,
password_hash VARCHAR(255),
addresses JSONB, -- Multiple addresses in JSON format
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
2. Restaurants Table
CREATE TABLE Restaurants (
restaurant_id UUID PRIMARY KEY,
name VARCHAR(255),
location VARCHAR(255),
contact_email VARCHAR(255),
contact_phone VARCHAR(15),
menu JSONB, -- Stores menu details
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
3. Orders Table
CREATE TABLE Orders (
order_id UUID PRIMARY KEY,
user_id UUID REFERENCES Users(user_id),
restaurant_id UUID REFERENCES Restaurants(restaurant_id),
total_amount DECIMAL(10, 2),
order_status ENUM('Pending', 'Confirmed', 'Out for Delivery', 'Delivered', 'Cancelled'),
delivery_address TEXT,
payment_id UUID,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
4. Payments Table
CREATE TABLE Payments (
payment_id UUID PRIMARY KEY,
order_id UUID REFERENCES Orders(order_id),
user_id UUID REFERENCES Users(user_id),
amount DECIMAL(10, 2),
payment_status ENUM('Pending', 'Completed', 'Failed', 'Refunded'),
payment_method ENUM('Credit Card', 'UPI', 'Net Banking', 'Wallet'),
transaction_id VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
2. NoSQL Databases
Use Case: Storing unstructured or semi-structured data and real-time operations (e.g., menu updates, user sessions).
DB Options: MongoDB, DynamoDB, Couchbase.
Schema Design
1. Menu Collection (MongoDB)
{
"restaurant_id": "7890",
"menu": [
{
"menu_item_id": "1",
"name": "Pizza",
"price": 12.99,
"description": "Cheese pizza with toppings",
"availability": true
},
{
"menu_item_id": "2",
"name": "Pasta",
"price": 10.99,
"description": "Spaghetti with tomato sauce",
"availability": true
}
]
}
2. User Sessions Collection
{
"user_id": "12345",
"session_token": "abcdef1234567890",
"created_at": "2025-01-03T10:30:00Z",
"expires_at": "2025-01-03T12:30:00Z"
}
3. Real-Time Orders (Redis for caching)
Key-Value structure:
Order:98765
{
"order_id": "98765",
"user_id": "12345",
"status": "Out for delivery",
"assigned_delivery_partner": "Sarah Conner",
"restaurant_name": "Food Paradise"
}
3. Search Databases
Use Case: Search functionalities like finding restaurants, menu items, or orders based on keywords or locations.
DB Options: Elasticsearch, Apache Solr.
Schema Design
Restaurant Index (Elasticsearch)
{
"restaurant_id": "7890",
"name": "Food Paradise",
"location": {
"latitude": 40.7128,
"longitude": -74.0060
},
"menu_items": ["Pizza", "Pasta", "Burger", "Salad"],
"rating": 4.5
}
Menu Items Index
{
"menu_item_id": "1",
"restaurant_id": "7890",
"name": "Pizza",
"price": 12.99,
"description": "Cheese pizza with toppings",
"tags": ["cheese", "toppings", "vegetarian"]
}
4. Analytics Databases
Use Case: Tracking trends, user behavior, and order analytics.
DB Options: Apache Cassandra, Google BigQuery, Snowflake, Amazon Redshift.
Schema Design
Order Analytics
Partition Key:
restaurant_id
Clustering Key:
order_date
CREATE TABLE OrderAnalytics (
restaurant_id UUID,
order_date DATE,
total_orders INT,
total_revenue DECIMAL(10, 2),
PRIMARY KEY (restaurant_id, order_date)
);
User Activity Logs (Cassandra)
Partition Key:
user_id
Clustering Key:
activity_timestamp
CREATE TABLE UserActivityLogs (
user_id UUID,
activity_timestamp TIMESTAMP,
activity_type TEXT,
metadata MAP<TEXT, TEXT>, -- E.g., {"order_id": "98765"}
PRIMARY KEY (user_id, activity_timestamp)
);
5. Time-Series Databases
Use Case: Tracking delivery partner locations or performance metrics over time.
DB Options: InfluxDB, TimescaleDB.
Schema Design
Delivery Partner Location Tracking
CREATE TABLE DeliveryLocations (
delivery_partner_id UUID,
timestamp TIMESTAMPTZ,
latitude DECIMAL(9, 6),
longitude DECIMAL(9, 6),
PRIMARY KEY (delivery_partner_id, timestamp)
);
6. Graph Databases
Use Case: Capturing relationships between entities (e.g., users, orders, restaurants, delivery partners).
DB Options: Neo4j, Amazon Neptune.
Schema Design
Graph Schema
Nodes: Users, Restaurants, Delivery Partners, Orders
Edges: "PLACED" (User → Order), "DELIVERED_BY" (Order → Delivery Partner), "FULFILLED_BY" (Order → Restaurant)
Example Query (Neo4j): Find all orders delivered by a specific delivery partner.
MATCH (dp:DeliveryPartner)-[:DELIVERED_BY]->(o:Order)
WHERE dp.delivery_partner_id = "4567"
RETURN o;
7. Message Queues for Event-Driven Architecture
Use Case: Real-time communication for order status updates, notifications, and asynchronous processing.
Options: Apache Kafka, RabbitMQ, Amazon SQS.
Schema for Kafka Topics
Topic:
order_events
{
"event_type": "OrderPlaced",
"order_id": "98765",
"user_id": "12345",
"restaurant_id": "7890",
"timestamp": "2025-01-03T10:30:00Z"
}
Topic: delivery_updates
{
"event_type": "OrderOutForDelivery",
"order_id": "98765",
"delivery_partner_id": "4567",
"timestamp": "2025-01-03T11:00:00Z"
}
1. Caching
Redis is ideal for caching frequently accessed data to reduce database load and improve response times.
Examples:
Restaurant Menus: Cache menu details of popular restaurants.
Key: "restaurant_menu:12345"
Value: {
"menu_items": [
{"id": "1", "name": "Pizza", "price": 12.99},
{"id": "2", "name": "Burger", "price": 8.99}
]
}
HLD