Skip to main content

Design an E-commerce/Online Shopping system

Problem Statement

Design an e-commerce system where users can browse products, add items to cart, and place orders. The system should support sellers, inventory management, order processing, and payment handling. Each order goes through multiple states like created, paid, shipped, delivered, and cancelled.


Functional Requirements

  • Users should be able to add products to cart
  • Users can place an order from cart
  • Each product belongs to a seller
  • Inventory should track stock per product
  • Orders should support multiple items
  • Order should go through different statuses
  • Payments should be processed and tracked

Objects Required

  • User
  • Cart
  • CartItem
  • Product
  • Seller
  • Order
  • OrderItem
  • Payment
  • Inventory
  • EcommerceService
  • PaymentService
  • InventoryService
  • OrderStatus
  • PaymentStatus

OrderStatus Enum


public enum OrderStatus {
    CREATED,
    PAID,
    SHIPPED,
    DELIVERED,
    CANCELLED
}

This enum tracks the lifecycle of an order. Every order starts in CREATED state and moves forward as it is processed, shipped, and delivered. If something goes wrong, it can also be cancelled.


PaymentStatus Enum


public enum PaymentStatus {
    SUCCESS,
    FAILED,
    PENDING
}

This enum represents the status of a payment transaction. It helps the system decide whether an order can move forward or should be rolled back.


User Class


public class User {

    private String userId;
    private String name;

    public User(String userId, String name) {
        this.userId = userId;
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

The User class holds basic user identity information. It acts as the primary actor who places orders in the system.


Cart Class


import java.util.*;

public class Cart {

    private String cartId;
    private List items = new ArrayList<>();

    public Cart(String cartId) {
        this.cartId = cartId;
    }

    public void addItem(CartItem item) {
        items.add(item);
    }

    public void removeItem(CartItem item) {
        items.remove(item);
    }

    public List getItems() {
        return items;
    }
}

The cart temporarily stores products selected by the user before placing an order.

The addItem() method adds a product to the cart. The removeItem() method removes unwanted items. The getItems() method is used during checkout to convert cart items into an order.


CartItem Class


public class CartItem {

    private int quantity;
    private Product product;

    public CartItem(Product product, int quantity) {
        this.product = product;
        this.quantity = quantity;
    }

    public Product getProduct() {
        return product;
    }

    public int getQuantity() {
        return quantity;
    }
}

Each CartItem represents a product along with the quantity selected by the user.

The getter methods are used during order creation and inventory validation.


Product Class


public class Product {

    private String productId;
    private String name;
    private double price;

    public Product(String productId, String name, double price) {
        this.productId = productId;
        this.name = name;
        this.price = price;
    }

    public double getPrice() {
        return price;
    }
}

Product represents an item available in the marketplace. It contains basic details like price and name.


Seller Class


public class Seller {

    private String sellerId;
    private String name;

    public Seller(String sellerId, String name) {
        this.sellerId = sellerId;
        this.name = name;
    }
}

Seller represents the owner of products. A single seller can list multiple products in the system.


OrderItem Class


public class OrderItem {

    private Product product;
    private int quantity;
    private double price;

    public OrderItem(Product product, int quantity) {
        this.product = product;
        this.quantity = quantity;
        this.price = product.getPrice() * quantity;
    }

    public double getPrice() {
        return price;
    }
}

OrderItem is created during checkout. It freezes product price at that moment so later changes in product price do not affect past orders.


Inventory Class


public class Inventory {

    private Product product;
    private int stock;

    public Inventory(Product product, int stock) {
        this.product = product;
        this.stock = stock;
    }

    public boolean isAvailable(int qty) {
        return stock >= qty;
    }

    public void reduceStock(int qty) {
        stock -= qty;
    }
}

Inventory tracks stock for each product. It ensures we never sell more items than available.

The isAvailable() method checks stock before order placement. The reduceStock() method updates inventory after successful payment.


Payment Class


public class Payment {

    private String paymentId;
    private double amount;
    private PaymentStatus status;

    public Payment(String paymentId, double amount) {
        this.paymentId = paymentId;
        this.amount = amount;
        this.status = PaymentStatus.PENDING;
    }

    public void markSuccess() {
        this.status = PaymentStatus.SUCCESS;
    }

    public void markFailed() {
        this.status = PaymentStatus.FAILED;
    }

    public PaymentStatus getStatus() {
        return status;
    }
}

Payment stores transaction details for an order. It starts as PENDING and later moves to SUCCESS or FAILED depending on gateway response.


PaymentService Class


import java.util.UUID;

public class PaymentService {

    public Payment processPayment(double amount) {

        Payment payment =
                new Payment(UUID.randomUUID().toString(), amount);

        if (Math.random() > 0.2) {
            payment.markSuccess();
        } else {
            payment.markFailed();
        }

        return payment;
    }
}

This service simulates payment gateway behavior. It creates a payment object and randomly decides success or failure (like a real external API response).


InventoryService Class


public class InventoryService {

    public boolean checkStock(Inventory inventory, int qty) {
        return inventory.isAvailable(qty);
    }

    public void reduceStock(Inventory inventory, int qty) {
        inventory.reduceStock(qty);
    }
}

InventoryService acts as a controller over inventory operations. It validates stock before order and updates stock after payment.


Order Class


import java.util.*;

public class Order {

    private String orderId;
    private User user;
    private List items;
    private OrderStatus status;
    private Payment payment;

    public Order(String orderId, User user, List items) {
        this.orderId = orderId;
        this.user = user;
        this.items = items;
        this.status = OrderStatus.CREATED;
    }

    public void markPaid(Payment payment) {
        this.payment = payment;
        this.status = OrderStatus.PAID;
    }

    public void markShipped() {
        this.status = OrderStatus.SHIPPED;
    }

    public void markDelivered() {
        this.status = OrderStatus.DELIVERED;
    }

    public void cancelOrder() {
        this.status = OrderStatus.CANCELLED;
    }
}

Order tracks full lifecycle of a purchase. It starts as CREATED and moves through multiple states.

The methods clearly represent real-world transitions: payment confirmation, shipping, delivery, and cancellation.


EcommerceService Class


import java.util.*;

public class EcommerceService {

    private PaymentService paymentService = new PaymentService();
    private InventoryService inventoryService = new InventoryService();

    public Order placeOrder(User user, Cart cart, Inventory inventory) {

        List orderItems = new ArrayList<>();

        for (CartItem item : cart.getItems()) {

            if (!inventoryService.checkStock(inventory, item.getQuantity())) {
                throw new RuntimeException("Out of stock");
            }

            orderItems.add(
                    new OrderItem(item.getProduct(), item.getQuantity())
            );
        }

        Order order = new Order(
                UUID.randomUUID().toString(),
                user,
                orderItems
        );

        double total = 0;
        for (OrderItem item : orderItems) {
            total += item.getPrice();
        }

        Payment payment =
                paymentService.processPayment(total);

        if (payment.getStatus() == PaymentStatus.SUCCESS) {
            order.markPaid(payment);

            for (CartItem item : cart.getItems()) {
                inventoryService.reduceStock(inventory, item.getQuantity());
            }
        } else {
            order.cancelOrder();
        }

        return order;
    }

    public void cancelOrder(Order order) {
        order.cancelOrder();
    }
}

This is the core orchestration layer. It converts cart into order, validates stock, processes payment, and updates inventory.

If payment succeeds, order is marked PAID and stock is reduced. If it fails, the order is cancelled immediately.


Main Class


public class Main {

    public static void main(String[] args) {

        User user = new User("U1", "Prasanna");

        Product p1 = new Product("P1", "Laptop", 50000);
        Product p2 = new Product("P2", "Phone", 20000);

        Cart cart = new Cart("C1");
        cart.addItem(new CartItem(p1, 1));
        cart.addItem(new CartItem(p2, 2));

        Inventory inventory = new Inventory(p1, 10);

        EcommerceService service = new EcommerceService();

        Order order =
                service.placeOrder(user, cart, inventory);

        System.out.println("Order Status: " + order);
    }
}

Main method simulates full e-commerce flow from cart creation to order placement and final status update.


Class Diagram

UseruserId : Stringname : StringCartcartId : Stringitems : List<CartItem>CartItemquantity : intproduct : ProductProductproductId : Stringname : Stringprice : doubleSellersellerId : Stringname : StringOrderorderId : Stringuser : Useritems : List<OrderItem>status : OrderStatuspayment : PaymentOrderItemproduct : Productquantity : intprice : doublePaymentpaymentId : Stringamount : doublestatus : PaymentStatusInventoryproduct : Productstock : intOrderStatusCREATEDPAIDSHIPPEDDELIVEREDCANCELLEDPaymentStatusSUCCESSFAILEDPENDINGEcommerceServiceplaceOrder(user : User, cart : Cart) : OrdercancelOrder(order : Order) : voidPaymentServiceprocessPayment(order : Order) : PaymentInventoryServicecheckStock(product : Product, qty : int) : booleanreduceStock(product : Product, qty : int) : void

Also See

Comments

Popular posts from this blog

Designing a Parking Lot - Low Level Design

Problem Statement Design a parking lot that can handle vehicles entering and leaving while managing parking across multiple floors. Each vehicle should be assigned a suitable parking spot based on its type, and the spot should be freed once the vehicle exits. The design should also support generating a ticket at entry and optionally calculating the parking fee based on the duration of stay. Asked In Companies Amazon Google Microsoft Uber Walmart Flipkart Meta PayPal Oracle Salesforce Adobe Apple Intuit LinkedIn Atlassian Functional Requirements The design should support multiple vehicle types such as bikes, cars, and trucks A vehicle must be assigned a parking spot compatible with its type A parking spot cannot be assigned to more than one vehicle at a time The parking lot should support multiple levels (floors) The design should search and allocate an availa...

Most Frequently Asked Low Level Design(LLD) Interview Questions

Below are the curated list of most commonly asked Low Level Design (LLD) interview problems. Each problem includes a short description and a link to the complete solution with code and class diagrams. Design Parking Lot System The system should handle parking for different vehicle types such as bikes, cars, and trucks. It should manage slot allocation, availability tracking, and entry/exit flow. The design also ensures efficient usage of parking space under varying load conditions. View Solution Design Elevator / Lift System The system should support multiple elevators operating across floors with request handling logic. It focuses on scheduling algorithms to minimize wait time and optimize movement. It also manages direction control and concurrent floor requests. View Solution Design Movie Ticket Booking System The system should allow users to browse movies, select shows, and book seats. It handles seat ...

Software Design Patterns for LLD Interviews: A Complete Guide

Software Design Patterns for LLD Interviews: A Complete Guide In Software Development Engineer (SDE) interviews—especially for mid-level and senior roles—low-level design (LLD) rounds assess your ability to write clean, reusable, maintainable, and extensible code. The foundation of resolving these architectural challenges lies in the standard Gang of Four (GoF) Design Patterns. Rather than memorizing theoretical definitions, interviewers expect you to apply these patterns to real-world scenarios, identifying the trade-offs of each. Below is a comprehensive guide to the 12 most frequently asked design patterns in LLD interviews, categorized by their classification (Creational, Structural, and Behavioral). Each pattern contains a concrete, real-world Java implementation and a detailed breakdown of design decisions. Creational Design Patterns Creational design patterns deal with object creation mechanisms. They abstract the instantiation process, making a system independent of how...