My Solution for Design a Food Delivery Service

by nectar4678

System requirements


Functional:

  1. User can search different restaurant based on his/her location
  2. User can select a restaurant
  3. User can see the menu of selected restraunt
  4. Restraunt can change the menu any time
  5. User selects restraunt and add different food items from the menu
  6. User orders the food by selecting different online payment modes
  7. User can track the order in real time
  8. The restaurant process the orders by preparing the meal and packaging the orders.
  9. The restaurant contacts the delivery service or their personnel delivery staff to deliver.


Non-Functional:

  1. No. of orders = 10,000 orders per minute
  2. No. of cities and towns operational = 500
  3. Total number of restraunts listed on the application = 140,000
  4. Total active delivery partners = 2,00000
  5. Total number of order cancellations = 1,500 daily
  6. System should be highly scalable and available.
  7. User should be able to get all features with minimal latency.


Capacity estimation

Traffic Estimates

System is expecting 10,000 orders per minute. So, order requests per second will be:

10, 000 orders per minute/60 = ~ 167 Orders /Second


Storage Estimates

Since we are expecting 10,000 orders per minute so, per day will be:

Orders per day = 10, 000 orders/minute * 60 * 24 = 14,400,000 orders/day

Total expected orders in 5 years = 14,400,000 orders/day * 12 Months * 5 Years = 864,000,000

Lets assume the size of object = 500 bytes

Total storage in 5 years = 432 GB


Food delivery system can be devided into three major components:

  1. Customer's Application
  2. Delivery guy's application
  3. Admin Panel


Customer's Application

  1. Selection of city and listing of restraunts
  2. Searching menu: Allow users to search for different restaurants, cafes, pubs, and bars by location and cuisines. Users can go through the menus and choose an item from using the search filter; users can easily find their favorite eating places.
  3. Order placement/Cancellation: The user can place an order of selected dishes and food with just a few simple taps on the screen. User can cancel order with a given allowed time.
  4. Tracking Drivers: Users can check how much time a driver will take to reach their food parcel.
  5. Payment gateway integration: It will be required for the payment by users. It will have multiple options of payment.


Delivery guy's application

  1. Driver's profile - Driver can update his profile details like his name, email, address, phone number, photos, or any other details.
  2. Notification for orders: Through push notifications, drivers can get constant updates & alerts for new food orders online. It will help in the accurate delivery service of your restaurant.
  3. Map for the delivery route: Integrate Google Map or Waze and allow drivers to choose the shortest and fastest routes to reach the location.


Admin Panel

  1. Restaurant management: Being on the admin panel, one can directly manage all the restaurants by adding, updating, and removing any eating joint from the list. He can also check active restaurant status and also menu pricing.
  2. Analytics & report generation: Using the analysis and report feature, you can get real-time insights of reports and other accounting information, which helps you to identify the growth and opportunities to expand reach.
  3. Monitoring every action: Monitor all the drivers, changes in the menu, deliveries, ratings & reviews of drivers, canceled orders, and other important data related to the driver’s performance.
  4. Payment and commission management: Allow owners to set payment and commission rates and manage it directly from the panel with every single partner and make payments.


API design

Customer's Application APIs

  • List Restaurants by Location
GET /restaurants Params: city, cuisine, rating Response: { "restaurants": [ {"id": "123", "name": "Pizza Place", "cuisine": "Italian", "rating": 4.5}, {"id": "124", "name": "Sushi Bar", "cuisine": "Japanese", "rating": 4.8} ] }


  • Get Restaurant Menu
GET /restaurants/{restaurantId}/menu Response: { "menuItems": [ {"id": "501", "name": "Margherita Pizza", "price": 15.00}, {"id": "502", "name": "Veggie Pizza", "price": 13.50} ] }


  • Place Order
POST /orders Body: { "userId": "90210", "restaurantId": "123", "items": [{"itemId": "501", "quantity": 2}], "paymentMethodId": "3456" } Response: {"orderId": "1001", "status": "processing"}
  • Track Order
GET /orders/{orderId}/track Response: {"orderId": "1001", "status": "en route", "estimatedDeliveryTime": "15 mins"}


Delivery Personnel's Application APIs

  • Driver Order Notification
GET /driver/{driverId}/orders Response: { "orders": [ {"orderId": "1001", "restaurant": "Pizza Place", "destination": "123 Main St"} ] }


  • Update Driver Status
POST /driver/{driverId}/status Body: {"status": "available"} Response: {"success": true}


Admin Panel APIs

  • Update Restaurant Menu
POST /admin/restaurants/{restaurantId}/menu` Body: {"menuItems": [{"name": "Cheese Pizza", "price": 12.00}]} Response: {"success": true}
  • Restaurant Performance Report
GET /admin/reports/{restaurantId} Response: {"ordersToday": 150, "revenueToday": 1400.00}


Database design

We need to design a data model that efficiently handles the interactions between customers, restaurants, orders, and drivers. Let’s begin with an Entity-Relationship (ER) diagram to illustrate the relationships between different entities.


Entities and Relationships

Users: Represents both customers and drivers with their respective details.

Restaurants: Stores information about restaurant partners.

Menu Items: Represents the dishes available at each restaurant.

Orders: Details of customer orders, including which items were ordered, from which restaurant, by which customer, and their delivery status.

Payments: Tracks payment details associated with each order.



High-level design

Frontend Applications: Customer app and driver app.

Backend Services:

  • User Service: Manages user registration, login, and profiles.
  • Restaurant Service: Manages restaurant listings, menus, and availability.
  • Order Service: Handles order placement, tracking, and status updates.
  • Payment Service: Processes payments and manages payment methods.
  • Delivery Service: Assigns orders to drivers and tracks delivery status.

Data Stores: Databases for users, restaurants, orders, etc.

External Integrations:

  • Payment Gateway: For processing payments.
  • Mapping Service: For navigation and optimal route calculation.



Request flows

I'll describe the request flow for a common scenario: a customer placing an order, which is then processed and delivered.


  1. Customer Places an Order
  2. The customer opens the customer app and selects their city and restaurant.
  3. The customer browses the menu and adds items to their cart.
  4. The customer proceeds to checkout, enters payment details, and submits the order.
  5. The order details are sent to the backend order service.
  6. The order service validates the order, interacts with the restaurant service to confirm the order with the restaurant, and reserves inventory.
  7. The payment service processes the payment and confirms the transaction.
  8. The order service updates the order status to "Confirmed" and notifies the customer via the frontend application.
  9. Order Preparation and Pickup
  10. The restaurant prepares the order. Once ready, the restaurant updates the order status via the restaurant management interface.
  11. The delivery service assigns the order to a nearby driver, who is notified via the driver app.
  12. The driver accepts the order and updates their status to "en route to restaurant".
  13. Delivery to Customer
  14. The driver picks up the order and updates the status to "en route to customer".
  15. The customer can track the driver’s progress via the tracking feature in the customer app.
  16. Upon arrival, the driver updates the order status to "delivered".
  17. The customer confirms receipt of the order through the app, which triggers the order service to close the order and process any necessary payments to the restaurant.



Detailed component design


User Service

Scalability: The User Service is built on a microservices architecture, allowing it to scale independently based on demand. This service can be horizontally scaled by adding more instances as the number of users grows. Load balancers distribute incoming requests across these instances to ensure even load distribution and high availability.


Relevant Algorithms/Data Structures:

  1. Hash Tables: Used for efficient retrieval and storage of user data, such as usernames and passwords, which ensures quick login and registration processes.
  2. Caching: Utilizing Redis or Memcached to cache frequent queries such as user profile data to reduce load on the primary database.


Restaurant Service

Scalability: Similar to the User Service, the Restaurant Service can also scale horizontally. The use of database sharding can help manage the vast amount of restaurant data, particularly useful in a system with tens of thousands of restaurants.


Relevant Algorithms/Data Structures:

  1. Trie: A trie (or prefix tree) could be particularly effective for auto-completing restaurant names or filtering restaurants based on cuisines or locations quickly.
  2. Geo Hashing: Utilized for storing and querying restaurants based on geographical locations, which facilitates efficient searches by location.


Order Service

Scalability: The Order Service handles high volumes of transactions, especially during peak times. It can scale horizontally, and using message queues (such as RabbitMQ or Kafka) ensures that order placements and updates are processed in a fail-safe, scalable manner.


Relevant Algorithms/Data Structures:

  1. Priority Queues: To manage the processing of orders based on certain criteria, such as delivery time or priority of the customer (e.g., Swiggy one, Zomato gold customers).
  2. Consistent Hashing: Used for distributing orders across different nodes (servers) to balance the load without frequent rehashing when nodes are added or removed.


Payment Service

This service is critical and sensitive, requiring high reliability and security. Scalability can be achieved by using a combination of internal load balancing and external payment gateways that can handle large volumes of transactions.


Relevant Algorithms/Data Structures:

  1. Blockchain: Although complex, integrating blockchain could offer a future-proof structure for handling transactions transparently and securely, especially in a distributed environment.
  2. Finite State Machines (FSM): For tracking the state of each payment process, ensuring that all steps from initiation to completion are followed accurately.


Delivery Service

Scalability: Delivery Service requires real-time capability and high responsiveness. Scalability can be managed by geographic sharding where drivers and orders are matched based on their locations, and by using scalable real-time data processing frameworks.


Relevant Algorithms/Data Structures:

  1. Graph Algorithms: Such as Dijkstra's or A* for calculating the shortest paths for delivery routes, optimizing delivery times and fuel consumption.
  2. Dynamic Programming: Used for route optimization and to solve the traveling salesman problem when one driver has to deliver multiple orders in one trip.


Trade offs/Tech choices

Order Service

  • Microservices Architecture vs. Monolithic: Choosing a microservices architecture increases complexity in deployment and inter-service communication but significantly enhances scalability and fault isolation compared to a monolithic architecture.
  • Database Sharding: While sharding improves performance and scalability, it complicates the database management and transaction consistency across shards.
  • Node.js: Chosen for its non-blocking I/O model which handles concurrent requests efficiently, crucial for high-load environments like order processing.
  • PostgreSQL: Provides robust transaction support and complex query capabilities, essential for the integrity of order data.


Payment Service

  • Java with Spring Boot: While Java is more resource-intensive than languages like Python or Node.js, its extensive ecosystem and strong type-checking reduce runtime errors and improve security, which is paramount for payment processing.
  • Distributed Transactions: These ensure data consistency across services but add latency and complexity to transaction processing.
  • Stripe and PayPal: Integrating with established payment gateways minimizes development risk and ensures compliance with financial regulations.


Delivery Service

  • Python with Flask vs. More Performant Alternatives: Python is less performant than languages like Go; however, its vast library support and ease of integration with data analytics and machine learning tools for route optimization make it a favorable choice.
  • Dynamic Dispatch System: Optimizes delivery efficiency but requires real-time data processing and sophisticated algorithms, increasing system complexity.
  • Google Maps API: Provides reliable and detailed geospatial data essential for route optimization. This choice prioritizes accuracy and up-to-date information over the potential cost of using a commercial API.


Failure scenarios/bottlenecks

Bottlenecks

  • Database Load: High transaction volumes during peak times could overload the database. Using read replicas and implementing more aggressive caching strategies could mitigate this.
  • API Rate Limiting: External APIs, particularly payment and mapping services, could impose rate limits, affecting scalability.


Failure Scenarios

  • Service Downtime: Microservices could fail, leading to partial system downtime. Implementing robust health checks, failovers, and a well-designed service mesh can address this.
  • Data Consistency Issues: In a distributed setup, ensuring data consistency across microservices and database shards is challenging. Employing distributed transaction management techniques like two-phase commit or eventual consistency models can help.


Future improvements

  • Implementing a Service Mesh: To better handle service-to-service communications, improve security with mTLS, and provide more fine-grained observability.
  • Adoption of Serverless Architectures: For certain components like the Payment Service, where demand can be highly variable, transitioning to serverless can improve cost-efficiency and scalability.
  • Enhanced Data Analytics: Integrating more advanced predictive analytics for order time estimations and delivery optimizations using machine learning models.