FR
Item Search: Users can search for available products across nearby stores.
Cart Management: Users can add items to their cart and proceed to checkout.
Store Selection: The system automatically identifies the nearest store that can fulfill the order in the shortest time.
Fast Delivery: Orders must be delivered within 10 minutes or less.
Flexible Payment: Users can choose to pay either at the time of ordering or after delivery.
Delivery Assignment: The system assigns the nearest available delivery agent from the selected store to ensure the fastest delivery.
NFR
High Availability: The system should be designed for 99.99% uptime, ensuring continuous service with minimal downtime.
Low Latency:
Search, cart updates, and order placement should have millisecond-level response times.
Order fulfillment and store assignment should happen in real-time to meet the 10-minute delivery SLA.
Consistency:
Strong Consistency: Order details and cart operations must be strongly consistent to prevent discrepancies in pricing, item availability, and checkout.
Eventual Consistency: Store inventory updates can be eventually consistent to optimize performance and avoid write bottlenecks.
Fault Tolerance: The system should gracefully handle server failures, network issues, and database crashes with automatic failovers and retries.
Scalability: The architecture should support auto-scaling to handle sudden spikes in demand, especially during peak hours or flash sales.
Storage
capacity: 100M DAU
on avg : 10M users are placing order
1 user place 3 orders per day
10M*3= 30M total orders
TPS: 30M/10^5= 300 rps (write qps)
storage = 500bytes
30M*500B=30*10^6*500*400*5B=300*10^11=30TB storage (5 yrs)
API’s
1.1. POST /app/v1/zepto/user
request {
"user_id": "string", // Unique user identifier
"name": "string", // User's name
"email": "string", // User's email address
"phone_number": "string", // User's phone number
"address": "string" // User's delivery address
}
response {
"status": "success", // Status of the operation
"user_id": "string" // The unique ID of the user
}
2. POST /app/v1/zepto/order
Description: Create a new order based on cart details and delivery preferences.
request {
"user_id": "string", // User placing the order
"cart_id": "string", // Reference to the user's cart
"delivery_address": "string", // Address where the order should be delivered
"payment_method": "string", // 'prepaid' or 'postpaid'
"preferred_store_id": "string" // Store from where the order should be fulfilled
}
resposne {
"status": "success", // Status of the order creation
"order_id": "string", // Unique order ID
"estimated_delivery_time": "string" // Estimated time for delivery (e.g., 10 minutes)
}
3. GET /app/v1/zepto/order?order_id=<order_id>
Description: Get the status and details of an order.
Request:
Query Parameters:
order_id
(required): Unique ID of the order to fetch details for.
{
"status": "success", // Status of the operation
"order_id": "string", // Unique order ID
"user_id": "string", // User who placed the order
"cart_id": "string", // Reference to the cart used for the order
"delivery_address": "string", // Delivery address for the order
"payment_status": "string", // Payment status (e.g., "paid", "pending")
"order_status": "string", // Status of the order (e.g., "pending", "dispatched", "delivered")
"estimated_delivery_time": "string" // Estimated delivery time
}
4. POST /app/v1/zepto/cart/add
Description: Add items to the cart.
request {
"user_id": "string", // User adding items to the cart
"items": [
{
"item_id": "string", // Unique item identifier
"name": "string", // Item name
"qty": "integer", // Quantity to add
"price": "number" // Price per item
}
]
}
resposne {
"user_id": "string", // User adding items to the cart
"items": [
{
"item_id": "string", // Unique item identifier
"name": "string", // Item name
"qty": "integer", // Quantity to add
"price": "number" // Price per item
}
]
}
5. GET /app/v1/zepto/cart
Description: Get the details of the current user's cart.
Request:
Query Parameters:
user_id
(required): Unique ID of the user whose cart is being fetched.
{
"status": "success", // Status of the operation
"cart_id": "string", // Unique cart ID
"user_id": "string", // User ID associated with the cart
"items": [
{
"item_id": "string", // Unique item identifier
"name": "string", // Item name
"qty": "integer", // Quantity in the cart
"price": "number" // Price per item
}
],
"total_price": "number" // Total price of items in the cart
}
6. POST /app/v1/zepto/order/payment
Description: Process payment for an orde
request {
"order_id": "string", // Unique order ID
"payment_method": "string", // Payment method (e.g., "credit_card", "debit_card", "wallet")
"payment_amount": "number" // Amount to be paid
}
resposne {
"status": "success", // Status of the payment operation
"payment_status": "string", // Payment status (e.g., "success", "failed")
"order_id": "string" // Unique order ID for the processed payment
}
Databases
1. Choosing the Right Database Type
Since the system requires low latency, high availability, and scalability, a mix of databases would be ideal:
Relational Database (SQL - PostgreSQL/MySQL)
Used for structured data that requires strong consistency (e.g., Users, Orders, Payments).
NoSQL Database (Cassandra/DynamoDB/Redis)
Used for high-read and write throughput with eventual consistency (e.g., Inventory, Cart, Order Tracking).
Search Engine (Elasticsearch)
Used for fast item search and recommendations.
2. Schema Design and DB Mapping
User Table (SQL - PostgreSQL/MySQL)
Reason: User details require strong consistency (e.g., login, profile).
CREATE TABLE Users (
user_id UUID PRIMARY KEY,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
phone_number VARCHAR(20) UNIQUE NOT NULL,
location VARCHAR(255) NOT NULL,
city VARCHAR(100) NOT NULL,
user_type ENUM('customer', 'delivery_person') NOT NULL
);
Inventory Table (NoSQL - Cassandra/DynamoDB)
Reason: Inventory is frequently updated and requires high availability and partitioning.
{
"inv_id": "uuid",
"store_id": "uuid",
"items": [
{
"item_id": "uuid",
"qty": "integer"
}
]
}
Items Table (SQL - PostgreSQL)
Reason: Items have structured information and relationships (category, seller).
CREATE TABLE Items (
item_id UUID PRIMARY KEY,
name VARCHAR(255) NOT NULL,
description TEXT,
category VARCHAR(100),
seller UUID REFERENCES Users(user_id),
price DECIMAL(10,2) NOT NULL
);
Cart Table (NoSQL - Redis)
Reason: Carts are frequently updated and need low-latency access (key-value store).
{
"cart_id": "uuid",
"user_id": "uuid",
"items": [
{
"item_id": "uuid",
"qty": "integer"
}
]
}
Order Table (SQL - PostgreSQL)
Reason: Orders need strong consistency and transactional integrity.
CREATE TABLE Orders (
order_id UUID PRIMARY KEY,
user_id UUID REFERENCES Users(user_id),
order_amt DECIMAL(10,2) NOT NULL,
creation_date TIMESTAMP DEFAULT NOW(),
modified_date TIMESTAMP DEFAULT NOW() ON UPDATE NOW(),
status ENUM('pending', 'dispatched', 'delivered', 'cancelled') NOT NULL,
deliver_id UUID REFERENCES Users(user_id),
items JSONB NOT NULL -- Stores list of items and their qty
);
Order Tracking (NoSQL - Cassandra/DynamoDB)
Reason: Order tracking is read-heavy and requires high availability.
{
"tracking_no": "uuid",
"order_id": "uuid",
"status_updates": [
{
"timestamp": "datetime",
"status": "string"
}
]
}
HLD
Hey,
I guess adding list of items should be done in one api call,but at the same time after some time I want to add another item then need to make another call.That's the reason I have made separate call for adding each item to cart.
Hi shashank do we really need to make api call for every item addition ? Isn’t it too frequent