Design Amazon - Online Shopping System
![](https://rajat19.github.io/system-design/assets/img/shopping/page.png)
Amazon is the world’s largest online retailer. The company was originally a bookseller but has expanded to sell a wide variety of consumer goods and digital media. For the sake of this problem, we will focus on their online retail business where users can sell/buy their products.
System Requirements
We will be designing a system with the following requirements:
- Users should be able to add new products to sell.
- Users should be able to search for products by their name or category.
- Users can search and view all the products, but they will have to become a registered member to buy a product.
- Users should be able to add/remove/modify product items in their shopping cart.
- Users can check out and buy items in the shopping cart.
- Users can rate and add a review for a product.
- The user should be able to specify a shipping address where their order will be delivered.
- Users can cancel an order if it has not shipped.
- Users should get notifications whenever there is a change in the order or shipping status.
- Users should be able to pay through credit cards or electronic bank transfer.
- Users should be able to track their shipment to see the current state of their order.
Use Case Diagrams
We have four main Actors in our system:
- Admin: Mainly responsible for account management and adding or modifying new product categories.
- Guest: All guests can search the catalog, add/remove items to the shopping cart, as well as become registered members.
- Member: Members can perform all the activities that guests can, in addition to which, they can place orders and add new products to sell.
- System: Mainly responsible for sending notifications for orders and shipping updates.
Here are the top use cases of the Online Shopping System:
- Add/update products; whenever a product is added or modified, we will update the catalog.
- Search for products by their name or category.
- Add/remove product items in the shopping cart.
- Check-out to buy product items in the shopping cart.
- Make a payment to place an order.
- Add a new product category.
- Send notifications to members with shipment updates.
Class Diagrams
Here are the descriptions of the different classes of our Online Shopping System:
- Account: There are two types of registered accounts in the system: one will be an Admin, who is responsible for adding new product categories and blocking/unblocking members; the other, a Member, who can buy/sell products.
- Guest: Guests can search for and view products, and add them in the shopping cart. To place an order they have to become a registered member.
- Catalog: Users of our system can search for products by their name or category. This class will keep an index of all products for faster search.
- ProductCategory: This will encapsulate the different categories of products, such as books, electronics, etc.
- Product: This class will encapsulate the entity that the users of our system will be buying and selling. Each Product will belong to a ProductCategory.
- ProductReview: Any registered member can add a review about a product.
- ShoppingCart: Users will add product items that they intend to buy to the shopping cart.
- Item: This class will encapsulate a product item that the users will be buying or placing in the shopping cart. For example, a pen could be a product and if there are 10 pens in the inventory, each of these 10 pens will be considered a product item.
- Order: This will encapsulate a buying order to buy everything in the shopping cart.
- OrderLog: Will keep a track of the status of orders, such as unshipped, pending, complete, canceled, etc.
- ShipmentLog: Will keep a track of the status of shipments, such as pending, shipped, delivered, etc.
- Notification: This class will take care of sending notifications to customers.
- Payment: This class will encapsulate the payment for an order. Members can pay through credit card or electronic bank transfer.
Activity Diagram
Following is the activity diagram for a user performing online shopping:
Sequence Diagram
-
Here is the sequence diagram for searching from the catalog:
-
Here is the sequence diagram for adding an item to the shopping cart:
-
Here is the sequence diagram for checking out to place an order:
Code
Here is the high-level definition for the classes described above.
- Enums and Constants: Here are the required enums, data types, and constants:
public class Address {
private String streetAddress;
private String city;
private String state;
private String zipCode;
private String country;
}
public enum OrderStatus {
UNSHIPPED, PENDING, SHIPPED, COMPLETED, CANCELED, REFUND_APPLIED
}
public enum AccountStatus {
ACTIVE, BLOCKED, BANNED, COMPROMISED, ARCHIVED, UNKNOWN
}
public enum ShipmentStatus {
PENDING, SHIPPED, DELIVERED, ON_HOLD,
}
public enum PaymentStatus {
UNPAID, PENDING, COMPLETED, FILLED, DECLINED, CANCELLED, ABANDONED, SETTLING, SETTLED, REFUNDED
}
class Address:
def __init__(self, street, city, state, zip_code, country):
self.__street_address = street
self.__city = city
self.__state = state
self.__zip_code = zip_code
self.__country = country
class OrderStatus(Enum):
UNSHIPPED, PENDING, SHIPPED, COMPLETED, CANCELED, REFUND_APPLIED = 1, 2, 3, 4, 5, 6
class AccountStatus(Enum):
ACTIVE, BLOCKED, BANNED, COMPROMISED, ARCHIVED, UNKNOWN = 1, 2, 3, 4, 5, 6
class ShipmentStatus(Enum):
PENDING, SHIPPED, DELIVERED, ON_HOLD = 1, 2, 3, 4
class PaymentStatus(Enum):
UNPAID, PENDING, COMPLETED, FILLED, DECLINED, CANCELLED, ABANDONED, SETTLING, SETTLED, REFUNDED = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
- Account, Customer, Admin, and Guest: These classes represent different people that interact with our system:
// For simplicity, we are not defining getter and setter functions. The reader can
// assume that all class attributes are private and accessed through their respective
// public getter methods and modified only through their public methods function.
public class Account {
private String userName;
private String password;
private AccountStatus status;
private String name;
private Address shippingAddress;
private String email;
private String phone;
private List<CreditCard> creditCards;
private List<ElectronicBankTransfer> bankAccounts;
public boolean addProduct(Product product);
public boolean addProductReview(ProductReview review);
public boolean resetPassword();
}
public abstract class Customer {
private ShoppingCart cart;
private Order order;
public ShoppingCart getShoppingCart();
public bool addItemToCart(Item item);
public bool removeItemFromCart(Item item);
}
public class Guest extends Customer {
public bool registerAccount();
}
public class Member extends Customer {
private Account account;
public OrderStatus placeOrder(Order order);
}
# For simplicity, we are not defining getter and setter functions. The reader can
# assume that all class attributes are private and accessed through their respective
# public getter methods and modified only through their public methods function.
class Account:
def __init__(self, user_name, password, name, email, phone, shipping_address, status=AccountStatus):
self.__user_name = user_name
self.__password = password
self.__name = name
self.__email = email
self.__phone = phone
self.__shipping_address = shipping_address
self.__status = status.ACTIVE
self.__credit_cards = []
self.__bank_accounts = []
def add_product(self, product):
None
def add_productReview(self, review):
None
def reset_password(self):
None
from abc import ABC, abstractmethod
class Customer(ABC):
def __init__(self, cart, order):
self.__cart = cart
self.__order = order
def get_shopping_cart(self):
return self.__cart
def add_item_to_cart(self, item):
None
def remove_item_from_cart(self, item):
None
class Guest(Customer):
def register_account(self):
None
class Member(Customer):
def __init__(self, account):
self.__account = account
def place_order(self, order):
None
- ProductCategory, Product, and ProductReview: Here are the classes related to a product:
public class ProductCategory {
private String name;
private String description;
}
public class ProductReview {
private int rating;
private String review;
private Member reviewer;
}
public class Product {
private String productID;
private String name;
private String description;
private double price;
private ProductCategory category;
private int availableItemCount;
private Account seller;
public int getAvailableCount();
public boolean updatePrice(double newPrice);
}
class ProductCategory:
def __init__(self, name, description):
self.__name = name
self.__description = description
class ProductReview:
def __init__(self, rating, review, reviewer):
self.__rating = rating
self.__review = review
self.__reviewer = reviewer
class Product:
def __init__(self, id, name, description, price, category, seller_account):
self.__product_id = id
self.__name = name
self.__description = description
self.__price = price
self.__category = category
self.__available_item_count = 0
self.__seller = seller_account
def get_available_count(self):
return self.__available_item_count
def update_price(self, new_price):
None
- ShoppingCart, Item, Order, and OrderLog: Users will add items to the shopping cart and place an order to buy all the items in the cart.
public class Item {
private String productID;
private int quantity;
private double price;
public boolean updateQuantity(int quantity);
}
public class ShoppingCart {
private List<Items> items;
public boolean addItem(Item item);
public boolean removeItem(Item item);
public boolean updateItemQuantity(Item item, int quantity);
public List<Item> getItems();
public boolean checkout();
}
public class OrderLog {
private String orderNumber;
private Date creationDate;
private OrderStatus status;
}
public class Order {
private String orderNumber;
private OrderStatus status;
private Date orderDate;
private List<OrderLog> orderLog;
public boolean sendForShipment();
public boolean makePayment(Payment payment);
public boolean addOrderLog(OrderLog orderLog);
}
class Item:
def __init__(self, id, quantity, price):
self.__product_id = id
self.__quantity = quantity
self.__price = price
def update_quantity(self, quantity):
None
class ShoppingCart:
def __init__(self):
self.__items = []
def add_item(self, item):
None
def remove_item(self, item):
None
def update_item_quantity(self, item, quantity):
None
def get_items(self):
return self.__items
def checkout(self):
None
class OrderLog:
def __init__(self, order_number, status=OrderStatus.PENDING):
self.__order_number = order_number
self.__creation_date = datetime.date.today()
self.__status = status
class Order:
def __init__(self, order_number, status=OrderStatus.PENDING):
self.__order_number = 0
self.__status = status
self.__order_date = datetime.date.today()
self.__order_log = []
def send_for_shipment(self):
None
def make_payment(self, payment):
None
def add_order_log(self, order_log):
None
- Shipment, ShipmentLog, and Notification: After successfully placing an order, a shipment record will be created:
public class ShipmentLog {
private String shipmentNumber;
private ShipmentStatus status;
private Date creationDate;
}
public class Shipment {
private String shipmentNumber;
private Date shipmentDate;
private Date estimatedArrival;
private String shipmentMethod;
private List<ShipmentLog> shipmentLogs;
public boolean addShipmentLog(ShipmentLog shipmentLog);
}
public abstract class Notification {
private int notificationId;
private Date createdOn;
private String content;
public boolean sendNotification(Account account);
}
class ShipmentLog:
def __init__(self, shipment_number, status=ShipmentStatus.PENDING):
self.__shipment_number = shipment_number
self.__status = status
self.__creation_date = datetime.date.today()
class Shipment:
def __init__(self, shipment_numbe, shipment_methodr):
self.__shipment_number = shipment_number
self.__shipment_date = datetime.date.today()
self.__estimated_arrival = datetime.date.today()
self.__shipment_method = shipment_method
self.__shipmentLogs = []
def add_shipment_log(self, shipment_log):
None
# from abc import ABC, abstractmethod
class Notification(ABC):
def __init__(self, id, content):
self.__notification_id = id
self.__created_on = datetime.date.today()
self.__content = content
def send_notification(self, account):
None
- Search interface and Catalog: Catalog will implement Search to facilitate searching of products.
public interface Search {
public List<Product> searchProductsByName(String name);
public List<Product> searchProductsByCategory(String category);
}
public class Catalog implements Search {
HashMap<String, List<Product>> productNames;
HashMap<String, List<Product>> productCategories;
public List<Product> searchProductsByName(String name) {
return productNames.get(name);
}
public List<Product> searchProductsByCategory(String category) {
return productCategories.get(category);
}
}
from abc import ABC, abstractmethod
class Search(ABC):
def search_products_by_name(self, name):
None
def search_products_by_category(self, category):
None
class Catalog(Search):
def __init__(self):
self.__product_names = {}
self.__product_categories = {}
def search_products_by_name(self, name):
return self.product_names.get(name)
def search_products_by_category(self, category):
return self.product_categories.get(category)