📅Week-6 (Day-1) - Build Zepto - Quick Commerce and Inventory Management System Design


NOTE: - I started my 8-week system design journey with Coder Army. I will be journaling every day, recording what I learn, reflecting on it, and sharing it with my network to help newcomers to system design.
💠 Functional Requirements
✅ Add/Remove inventory items (CRUD) ✅ Support replenish strategies (threshold, weekly) ✅ Scalable + support multiple inventory stores (like DBInventoryStore, in-memory) ✅ View items from all dark stores within 5 km radius ✅ If one dark store can't fulfill order, split it into multiple dark stores and fulfill via multiple delivery agents
💠 Core Components
1️⃣ ProductFactory
(🛠️ Factory Pattern)
Create different types of products dynamically.
💡 Like Amazon seller adding new product types via admin panel.
(Hindi: Jab naye product add karne hote hain toh factory pattern se har product ka object dynamically banate hain.)
2️⃣ InventoryStore
+ DbInventoryStore
Interfaces to store/query stock 🗃️
Can be extended to support NoSQL, in-memory etc 🔌
3️⃣ InventoryManager
(📦 Facade Pattern)
- Unified layer to manage inventory: Add, Remove, Query, Replenish
💠 What is Facade Pattern?
The Facade Pattern provides a simplified, unified interface to a set of complex subsystems.
(Hindi: Facade Pattern ek simplified aur unified interface provide karta hai jo kai complex subsystems ke upar kaam karta hai.)
4️⃣ ReplenishmentStrategy
(🧠 Strategy Pattern)
Threshold strategy: Replenish when item count goes below X
Weekly strategy: Replenish weekly
💡 Plug in new strategies without changing main system logic.
5️⃣ DarkStoreManager
(📍 Singleton)
Coordinates multiple dark stores
Maintains geo-location logic (like nearest store within 5km)
(Hindi: Ek hi system se saare stores manage karne ke liye Singleton banate hain.)
6️⃣ Cart & Order Fulfillment 🛒➡️📦
Handle cart operations
If one store can’t fulfill → Split order across multiple dark stores
(Hindi: Agar ek store mein pura maal nahi mila, toh order split ho kar multiple stores se aata hai.)
7️⃣ Zepto
Class (📍 Glue Everything Together)
Orchestrator that ties all components
From product to cart → to inventory check → to delivery planning
import java.util.*;
import java.lang.Math;
/////////////////////////////////////////////
// Product & Factory
/////////////////////////////////////////////
class Product {
private int sku;
private String name;
private double price;
public Product(int id, String nm, double pr) {
sku = id;
name = nm;
price = pr;
}
// Getters & Setters
public int getSku() {
return this.sku;
}
public String getName() {
return this.name;
}
public double getPrice() {
return this.price;
}
}
class ProductFactory {
public static Product createProduct(int sku) {
// In reality product comes from DB
String name;
double price;
if (sku == 101) {
name = "Apple";
price = 20;
}
else if (sku == 102) {
name = "Banana";
price = 10;
}
else if (sku == 103) {
name = "Chocolate";
price = 50;
}
else if (sku == 201) {
name = "T-Shirt";
price = 500;
}
else if (sku == 202) {
name = "Jeans";
price = 1000;
}
else {
name = "Item" + sku;
price = 100;
}
return new Product(sku, name, price);
}
}
/////////////////////////////////////////////
// InventoryStore (Interface) & DbInventoryStore
/////////////////////////////////////////////
interface InventoryStore {
void addProduct(Product prod, int qty);
void removeProduct(int sku, int qty);
int checkStock(int sku);
List<Product> listAvailableProducts();
}
class DbInventoryStore implements InventoryStore {
private Map<Integer,Integer> stock; // SKU -> quantity
private Map<Integer,Product> products; // SKU -> Product
public DbInventoryStore() {
stock = new HashMap<>();
products = new HashMap<>();
}
@Override
public void addProduct(Product prod, int qty) {
int sku = prod.getSku();
if (!products.containsKey(sku)) {
products.put(sku, prod);
}
// else drop the extra prod instance
stock.put(sku, stock.getOrDefault(sku, 0) + qty);
}
@Override
public void removeProduct(int sku, int qty) {
if (!stock.containsKey(sku))
return;
int currentQuantity = stock.get(sku);
int remainingQuantity = currentQuantity - qty;
if (remainingQuantity > 0) {
stock.put(sku, remainingQuantity);
} else {
stock.remove(sku);
products.remove(sku);
}
}
@Override
public int checkStock(int sku) {
return stock.getOrDefault(sku, 0);
}
@Override
public List<Product> listAvailableProducts() {
List<Product> available = new ArrayList<>();
for (Map.Entry<Integer,Integer> it : stock.entrySet()) {
int sku = it.getKey();
int qty = it.getValue();
if (qty > 0 && products.containsKey(sku)) {
available.add(products.get(sku));
}
}
return available;
}
}
/////////////////////////////////////////////
// InventoryManager
/////////////////////////////////////////////
class InventoryManager {
private InventoryStore store;
public InventoryManager(InventoryStore store) {
this.store = store;
}
public void addStock(int sku, int qty) {
Product prod = ProductFactory.createProduct(sku);
store.addProduct(prod, qty);
System.out.println("[InventoryManager] Added SKU " + sku + " Qty " + qty);
}
public void removeStock(int sku, int qty) {
store.removeProduct(sku, qty);
}
public int checkStock(int sku) {
return store.checkStock(sku);
}
public List<Product> getAvailableProducts() {
return store.listAvailableProducts();
}
}
/////////////////////////////////////////////
// Replenishment Strategy (Strategy Pattern)
/////////////////////////////////////////////
interface ReplenishStrategy {
void replenish(InventoryManager manager, Map<Integer,Integer> itemsToReplenish);
}
class ThresholdReplenishStrategy implements ReplenishStrategy {
private int threshold;
public ThresholdReplenishStrategy(int threshold) {
this.threshold = threshold;
}
@Override
public void replenish(InventoryManager manager, Map<Integer,Integer> itemsToReplenish) {
System.out.println("[ThresholdReplenish] Checking threshold...");
for (Map.Entry<Integer,Integer> it : itemsToReplenish.entrySet()) {
int sku = it.getKey();
int qtyToAdd = it.getValue();
int current = manager.checkStock(sku);
if (current < threshold) {
manager.addStock(sku, qtyToAdd);
System.out.println(" -> SKU " + sku + " was " + current
+ ", replenished by " + qtyToAdd);
}
}
}
}
class WeeklyReplenishStrategy implements ReplenishStrategy {
public WeeklyReplenishStrategy() {}
@Override
public void replenish(InventoryManager manager, Map<Integer,Integer> itemsToReplenish) {
System.out.println("[WeeklyReplenish] Weekly replenishment triggered for inventory.");
}
}
/////////////////////////////////////////////
// DarkStore (formerly Warehouse)
/////////////////////////////////////////////
class DarkStore {
private String name;
private double x, y; // location coordinates
private InventoryManager inventoryManager;
private ReplenishStrategy replenishStrategy;
public DarkStore(String n, double x_coord, double y_coord) {
name = n;
x = x_coord;
y = y_coord;
// We could have made another factory called InventoryStoreFactory to get
// DbInventoryStore by enum and hence make it loosely coupled.
inventoryManager = new InventoryManager(new DbInventoryStore());
}
public double distanceTo(double ux, double uy) {
return Math.sqrt((x - ux)*(x - ux) + (y - uy)*(y - uy));
}
public void runReplenishment(Map<Integer,Integer> itemsToReplenish) {
if (replenishStrategy != null) {
replenishStrategy.replenish(inventoryManager, itemsToReplenish);
}
}
// Delegation Methods
public List<Product> getAllProducts() {
return inventoryManager.getAvailableProducts();
}
public int checkStock(int sku) {
return inventoryManager.checkStock(sku);
}
public void removeStock(int sku, int qty) {
inventoryManager.removeStock(sku, qty);
}
public void addStock(int sku, int qty) {
inventoryManager.addStock(sku, qty);
}
// Getters & Setters
public void setReplenishStrategy(ReplenishStrategy strategy) {
this.replenishStrategy = strategy;
}
public String getName() {
return this.name;
}
public double getXCoordinate() {
return this.x;
}
public double getYCoordinate() {
return this.y;
}
public InventoryManager getInventoryManager() {
return this.inventoryManager;
}
}
/////////////////////////////////////////////
// DarkStoreManager (Singleton)
/////////////////////////////////////////////
class DarkStoreManager {
private static DarkStoreManager instance;
private List<DarkStore> darkStores;
private DarkStoreManager() {
darkStores = new ArrayList<>();
}
public static DarkStoreManager getInstance() {
if (instance == null) {
instance = new DarkStoreManager();
}
return instance;
}
public void registerDarkStore(DarkStore ds) {
darkStores.add(ds);
}
public List<DarkStore> getNearbyDarkStores(double ux, double uy, double maxDistance) {
List<Pair<Double,DarkStore>> distList = new ArrayList<>();
for (DarkStore ds : darkStores) {
double d = ds.distanceTo(ux, uy);
if (d <= maxDistance) {
distList.add(new Pair<>(d, ds));
}
}
distList.sort(Comparator.comparing(Pair::getKey));
List<DarkStore> result = new ArrayList<>();
for (Pair<Double,DarkStore> p : distList) {
result.add(p.getValue());
}
return result;
}
}
// Simple helper Pair class (since JavaFX/Android Pair might not be available)
class Pair<K,V> {
private K key; private V value;
public Pair(K k, V v) { key = k; value = v; }
public K getKey() { return key; }
public V getValue() { return value; }
}
/////////////////////////////////////////////
// User & Cart
/////////////////////////////////////////////
class Cart {
public List<Pair<Product,Integer>> items = new ArrayList<>();
public void addItem(int sku, int qty) {
Product prod = ProductFactory.createProduct(sku);
items.add(new Pair<>(prod, qty));
System.out.println("[Cart] Added SKU " + sku + " (" + prod.getName()
+ ") x" + qty);
}
public double getTotal() {
double sum = 0.0;
for (Pair<Product,Integer> it : items) {
sum += (it.getKey().getPrice() * it.getValue());
}
return sum;
}
public List<Pair<Product,Integer>> getItems() {
return items;
}
}
class User {
public String name;
public double x, y;
private Cart cart; // User owns a cart
public User(String n, double x_coord, double y_coord) {
name = n;
x = x_coord;
y = y_coord;
cart = new Cart();
}
public Cart getCart() {
return cart;
}
}
/////////////////////////////////////////////
// DeliveryPartner
/////////////////////////////////////////////
class DeliveryPartner {
public String name;
public DeliveryPartner(String n) {
name = n;
}
}
/////////////////////////////////////////////
// Order & OrderManager (Singleton)
/////////////////////////////////////////////
class Order {
private static int nextId = 1;
public int orderId;
public User user;
public List<Pair<Product,Integer>> items = new ArrayList<>();
public List<DeliveryPartner> partners = new ArrayList<>();
public double totalAmount;
public Order(User u) {
orderId = nextId++;
user = u;
totalAmount = 0.0;
}
}
class OrderManager {
private static OrderManager instance;
private List<Order> orders;
private OrderManager() {
orders = new ArrayList<>();
}
public static OrderManager getInstance() {
if (instance == null) {
instance = new OrderManager();
}
return instance;
}
public void placeOrder(User user, Cart cart) {
System.out.println("\n[OrderManager] Placing Order for: " + user.name);
List<Pair<Product,Integer>> requestedItems = cart.getItems();
// 1) Find nearby dark stores within 5 KM
double maxDist = 5.0;
List<DarkStore> nearbyDarkStores =
DarkStoreManager.getInstance().getNearbyDarkStores(user.x, user.y, maxDist);
if (nearbyDarkStores.isEmpty()) {
System.out.println(" No dark stores within 5 KM. Cannot fulfill order.");
return;
}
// 2) Check if closest store has all items
DarkStore firstStore = nearbyDarkStores.get(0);
boolean allInFirst = true;
for (Pair<Product,Integer> item : requestedItems) {
int sku = item.getKey().getSku();
int qty = item.getValue();
if (firstStore.checkStock(sku) < qty) {
allInFirst = false;
break;
}
}
Order order = new Order(user);
// One delivery partner required...
if (allInFirst) {
System.out.println(" All items at: " + firstStore.getName());
for (Pair<Product,Integer> item : requestedItems) {
int sku = item.getKey().getSku();
int qty = item.getValue();
firstStore.removeStock(sku, qty);
order.items.add(new Pair<>(item.getKey(), qty));
}
order.totalAmount = cart.getTotal();
order.partners.add(new DeliveryPartner("Partner1"));
System.out.println(" Assigned Delivery Partner: Partner1");
}
// Multiple delivery partners required
else {
System.out.println(" Splitting order across stores...");
Map<Integer,Integer> allItems = new HashMap<>();
for (Pair<Product,Integer> item : requestedItems) {
allItems.put(item.getKey().getSku(), item.getValue());
}
int partnerId = 1;
for (DarkStore store : nearbyDarkStores) {
if (allItems.isEmpty()) break;
System.out.println(" Checking: " + store.getName());
List<Integer> toErase = new ArrayList<>();
for (Map.Entry<Integer,Integer> entry : allItems.entrySet()) {
int sku = entry.getKey();
int qtyNeeded = entry.getValue();
int availableQty = store.checkStock(sku);
if (availableQty <= 0) continue;
int takenQty = Math.min(availableQty, qtyNeeded);
store.removeStock(sku, takenQty);
System.out.println(" " + store.getName() + " supplies SKU " + sku
+ " x" + takenQty);
order.items.add(new Pair<>(ProductFactory.createProduct(sku), takenQty));
if (qtyNeeded > takenQty) {
allItems.put(sku, qtyNeeded - takenQty);
} else {
toErase.add(sku);
}
}
for (int sku : toErase) {
allItems.remove(sku);
}
if (!toErase.isEmpty()) {
String pname = "Partner" + partnerId++;
order.partners.add(new DeliveryPartner(pname));
System.out.println(" Assigned: " + pname + " for " + store.getName());
}
}
if (!allItems.isEmpty()) {
System.out.println(" Could not fulfill:");
for (Map.Entry<Integer,Integer> entry : allItems.entrySet()) {
System.out.println(" SKU " + entry.getKey()
+ " x" + entry.getValue());
}
}
double sum = 0;
for (Pair<Product,Integer> it : order.items) {
sum += it.getKey().getPrice() * it.getValue();
}
order.totalAmount = sum;
}
// Printing Order Summary
System.out.println("\n[OrderManager] Order #" + order.orderId + " Summary:");
System.out.println(" User: " + user.name + "\n Items:");
for (Pair<Product,Integer> item : order.items) {
System.out.println(" SKU " + item.getKey().getSku()
+ " (" + item.getKey().getName() + ") x" + item.getValue()
+ " @ ₹" + item.getKey().getPrice());
}
System.out.println(" Total: ₹" + order.totalAmount + "\n Partners:");
for (DeliveryPartner dp : order.partners) {
System.out.println(" " + dp.name);
}
System.out.println();
orders.add(order);
}
public List<Order> getAllOrders() {
return orders;
}
}
/////////////////////////////////////////////
// Zepto Initialization & Main
/////////////////////////////////////////////
class ZeptoHelper {
public static void showAllItems(User user) {
System.out.println("\n[Zepto] All Available products within 5 KM for " + user.name + ":");
DarkStoreManager dsManager = DarkStoreManager.getInstance();
List<DarkStore> nearbyStores = dsManager.getNearbyDarkStores(user.x, user.y, 5.0);
Map<Integer,Double> skuToPrice = new HashMap<>();
Map<Integer,String> skuToName = new HashMap<>();
for (DarkStore ds : nearbyStores) {
for (Product product : ds.getAllProducts()) {
int sku = product.getSku();
if (!skuToPrice.containsKey(sku)) {
skuToPrice.put(sku, product.getPrice());
skuToName.put(sku, product.getName());
}
}
}
for (Map.Entry<Integer,Double> entry : skuToPrice.entrySet()) {
System.out.println(" SKU " + entry.getKey() + " - "
+ skuToName.get(entry.getKey())
+ " @ ₹" + entry.getValue());
}
}
public static void initialize() {
DarkStoreManager dsManager = DarkStoreManager.getInstance();
// DarkStore A.......
DarkStore darkStoreA = new DarkStore("DarkStoreA", 0.0, 0.0);
darkStoreA.setReplenishStrategy(new ThresholdReplenishStrategy(3));
System.out.println("\nAdding stocks in DarkStoreA....");
darkStoreA.addStock(101, 5);
darkStoreA.addStock(102, 2);
// DarkStore B.......
DarkStore darkStoreB = new DarkStore("DarkStoreB", 4.0, 1.0);
darkStoreB.setReplenishStrategy(new ThresholdReplenishStrategy(3));
System.out.println("\nAdding stocks in DarkStoreB....");
darkStoreB.addStock(101, 3);
darkStoreB.addStock(103, 10);
// DarkStore C.......
DarkStore darkStoreC = new DarkStore("DarkStoreC", 2.0, 3.0);
darkStoreC.setReplenishStrategy(new ThresholdReplenishStrategy(3));
System.out.println("\nAdding stocks in DarkStoreC....");
darkStoreC.addStock(102, 5);
darkStoreC.addStock(201, 7);
dsManager.registerDarkStore(darkStoreA);
dsManager.registerDarkStore(darkStoreB);
dsManager.registerDarkStore(darkStoreC);
}
}
public class ZeptoClone {
public static void main(String[] args) {
// 1) Initialize.
ZeptoHelper.initialize();
// 2) A User comes on Platform
User user = new User("Aditya", 1.0, 1.0);
System.out.println("\nUser with name " + user.name + " comes on platform");
// 3) Show all available items via Zepto
ZeptoHelper.showAllItems(user);
// 4) User adds items to cart
System.out.println("\nAdding items to cart");
Cart cart = user.getCart();
cart.addItem(101, 4);
cart.addItem(102, 3);
cart.addItem(103, 2);
// 5) Place Order
OrderManager.getInstance().placeOrder(user, cart);
System.out.println("\n=== Demo Complete ===");
}
}
💠 Real-Life Flow Example:
User adds Bread & Milk to cart
Zepto checks nearest dark stores
Bread from Store A, Milk from Store B
Inventory updated + replenishment scheduled
Delivery agents dispatched
✅Summary Recap
ProductFactory → Naye product banao
InventoryStore + DbInventoryStore → Stock manage karo
InventoryManager → Facade jo sab kuch control karta hai
Strategy Pattern → Replenishment logic alag se plug karo
DarkStoreManager → Saare stores ka ek controller
Zepto → Sabko jodne wali main class
Week - 6 (Day-1) Completed ✅ System Design
NOTE : - A big thanks to my mentors Rohit Negi Sir and Aditya Sir for launching this amazing 8-week course absolutely free on YouTube via CoderArmy9 :- youtube.com/@CoderArmy9 . 🙌
👉 Share this blog with your connections! Let’s keep learning, growing, and supporting one another on this journey. 🚀
✍️ Payal Kumari 👩💻
Jai Hind 🇮🇳 | #CoderArmy #LearningInPublic #SystemDesign #TechForAll #MentorshipMatters #8weeksLLdChallenge #LowLevelDesign #LLD 👩💻
Subscribe to my newsletter
Read articles from Payal Kumari directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Payal Kumari
Payal Kumari
I'm a passionate full-stack developer with a strong foundation in the MERN stack—building and maintaining scalable web applications using React.js, Node.js, and Next.js. My journey in open source began with Hacktoberfest 2023, where I made four impactful pull requests that sparked a love for collaborative coding, global learning, and open knowledge sharing. Since then, I’ve contributed to and mentored projects in top open source programs like GSSoC’24, SSOC’24, and C4GT’24. As a Google Gen AI Exchange Hackathon ’24 Finalist and Google’s Women Techmakers (WTM) Ambassador, I’ve been privileged to support diverse communities in building meaningful tech solutions. My work as a Top 50 Mentor for GSSoC ’24 reflects my commitment to nurturing new talent in tech. Beyond development, I serve as a Student Career Guide, Profile Building Expert & Evangelist at Topmate.io, where I conduct workshops, guide students through resume building and career strategy, and help mentees navigate open source and tech careers. Recognized among the Top 5% of mentors and featured on “Topmate Discover,” I take pride in making mentorship accessible and impactful. My technical voice has also been acknowledged by LinkedIn, where I’ve earned the Top Voice badge seven times in domains like web development, programming, and software engineering. In addition, I hold LinkedIn Golden Badges for Research Skills, Interpersonal Skills, Critical Thinking, and Teamwork—signaling a well-rounded approach to both individual contribution and team collaboration. Graduating with an MCA from Chandigarh University in 2023, I’ve continued to fuel my curiosity by writing technical articles and sharing practical MERN stack insights across platforms. Whether it’s building polished UIs, optimizing backend performance, or guiding a mentee through their first pull request, I’m driven by the power of community and continuous learning. Let’s connect! I'm open to collaborations, mentorship, or building something impactful together. Reach out to me at kumaripayal7488@gmail.com or visit my profile on Topmate.io.