Data Models - mukular/food-delivery-feastfast--architecture GitHub Wiki

Data Models Documentation

This document describes all major MongoDB (Mongoose) data models used in the Food Delivery Platform, including their purpose, relationships, and design decisions.

Note: This document intentionally lists only the most important and behavior-defining fields required to understand system design, data relationships, and business logic.

Implementation-specific, operational, security-related, or auxiliary fields (such as location tracking, authentication helpers, defaults, and internal flags) are intentionally omitted and live in the actual Mongoose schema files.


1. User Model

Purpose

Represents all authenticated users in the system, including:

  • Customers
  • Sellers (restaurant owners)
  • Delivery partners
  • Admins

Key Responsibilities

  • Authentication & authorization
  • Role-based access
  • Wallet management
  • Session ownership

Fields

User {
  _id: ObjectId  
  fullName: String  
  email: String (unique)  
  phone: String  
  password: String (hashed)  
  role: "customer" | "seller" | "delivery" | "admin"  

  wallet: Number  
  isDeleted: Boolean  

  createdAt: Date  
  updatedAt: Date  
}

Notes

  • Single user table for all roles β†’ simpler auth & session logic
  • Wallet is stored here for atomic updates
  • Role determines dashboard & permissions

2. Shop (Restaurant) Model

Purpose

Represents a restaurant owned by a seller.

Relationships

  • One seller β†’ One shop
  • One shop β†’ Many items
  • One shop β†’ Many shopOrders (embedded in orders)

Fields

Shop {
  _id: ObjectId  
  owner: ObjectId (User)  

  name: String  
  image: { url, publicId }  

  cuisineType: [String]  
  city: String  
  state: String  

  location: {
    type: "Point",
    coordinates: [lng, lat]
  }

  serviceRadiusMeters: Number  

  openingHours: [{
    open: String   // "09:00"
    close: String  // "23:00"
  }]

  rating: {
    average: Number
    count: Number
  }

  isActive: Boolean  
  isApproved: Boolean  
  isDeleted: Boolean  

  createdAt: Date  
}

Design Decisions

  • GeoJSON Point used for $geoNear
  • serviceRadiusMeters protects sellers from far orders
  • Ratings are denormalized for fast reads

3. Item (Menu Item) Model

Purpose

Represents individual menu items sold by a restaurant.

Fields

Item {
  _id: ObjectId  
  shop: ObjectId (Shop)  

  name: String  
  description: String  
  image: { url, publicId }  

  price: Number  
  category: String  
  foodType: "veg" | "nonveg"  

  rating: {
    average: Number
    count: Number
  }

  available: Boolean  
  isDeleted: Boolean  

  createdAt: Date  
}

Notes

  • Items are queried frequently β†’ indexed fields
  • Availability allows temporary disabling without deletion

4. Order Model (Core Model)

Purpose

Represents a customer order, which may contain multiple shop orders.

Why this model is important

This is the heart of the system.

Fields

Order {
  _id: ObjectId  
  user: ObjectId (User)  

  status: "created" | "confirmed" | "completed" | "cancelled"  

  paymentMethod: "wallet" | "cod" | "online"  
  paymentStatus: "pending" | "paid" | "refunded"  

  couponCode: String | null  

  subtotal: Number  
  tax: Number  
  deliveryFee: Number  
  totalAmount: Number  

  deliveryStats: {
    latitude: Number
    longitude: Number
    address: String
  }

  shopOrders: [ShopOrder]  

  razorpayOrderId: String  
  razorpayPaymentId: String  

  createdAt: Date  
}

5. ShopOrder (Embedded Subdocument)

Purpose

Represents one restaurant’s portion of an order.

Why embedded?

  • Orders are always fetched with shopOrders
  • Atomic updates per order
  • Faster reads

Fields

ShopOrder {
  _id: ObjectId  
  shop: ObjectId (Shop)  
  owner: ObjectId (User)  

  status: "pending" | "preparing" |
          "ready" | "out_for_delivery" |
          "delivered" | "cancelled"  

  shopOrderItems: [{
    item: ObjectId (Item)
    name: String
    price: Number
    quantity: Number
  }]

  subtotal: Number  
  deliveryFee: Number  
  tax: Number  
  payableAmount: Number  

  acceptedAt: Date  
  preparedAt: Date  
  deliveredAt: Date  
}

Design Notes

  • Order lifecycle is tracked per shop
  • Timestamps allow:
    • Analytics
    • Time-to-deliver calculations
    • Seller performance metrics

6. ShopCoupon Model

Purpose

Represents promotional offers created by sellers.

Fields

ShopCoupon {
  _id: ObjectId  
  code: String (unique)  
  shop: ObjectId (Shop)  

  title: String  
  description: String  

  discountType: "percentage" | "fixed" | "free_item"  
  discountValue: Number  
  maxDiscountAmount: Number  

  freeItem: {
    id: ObjectId (Item)
    name: String
  }

  minOrderAmount: Number  

  startDate: Date  
  endDate: Date  

  isActive: Boolean  

  usageLimitPerUser: Number  
  usageLimitTotal: Number  
  usedCount: Number  

  applicableCategories: [String]  
  excludedItems: [{ id, name }]  

  userUsed: [{
    userId: ObjectId
    usedCount: Number
    lastUsed: Date
  }]

  createdAt: Date  
}

Notes

  • Designed for complex real-world rules
  • User usage stored inside coupon for fast validation
  • Trade-off: document grows β†’ acceptable for coupon scale

7. DeliveryAssignment Model

Purpose

Links delivery partners to specific shop orders.

Fields

DeliveryAssignment {
  _id: ObjectId  
  order: ObjectId (Order)  
  shopOrderId: ObjectId  

  shop: ObjectId (Shop)  
  assignedTo: ObjectId (User)  

  status: "assigned" | "picked_up" | "delivered"  

  assignedAt: Date  
  pickedUpAt: Date  
  deliveredAt: Date  
}

Why separate model?

  • Delivery lifecycle is independent
  • Cleaner tracking for delivery partners
  • Easier future scaling (batch deliveries, routing)

8. Redis Data (Non-Persistent)

Stored Data Types

a) Sessions
session:{sessionId} β†’ user data

b) Cached Queries
restaurants:{lat}:{lng}:{filters}
menu:{shopId}:{filters}

Why Redis?

  • Fast reads
  • Reduces DB load
  • Centralized session control

9. Relationships Summary

User  
 β”œβ”€β”€ Shop (seller)  
 β”‚    β”œβ”€β”€ Item  
 β”‚    β”œβ”€β”€ Coupon  
 β”‚  
 β”œβ”€β”€ Order  
 β”‚    β”œβ”€β”€ ShopOrder (embedded)  
 β”‚    β”‚     └── Items  
 β”‚  
 └── DeliveryAssignment (delivery partner)  

10. Key Data Design Principles Used

  • Denormalization for performance
  • Embedded documents for atomicity
  • Read-heavy optimization
  • Geo-spatial indexing
  • TTL-based caching
  • Real-world trade-offs documented

11. Why This Data Model is Strong

This schema supports:

  • High read throughput
  • Complex order flows
  • Real-time updates
  • Scalable analytics
  • Clean separation of concerns

It closely mirrors production systems used in large-scale delivery platforms.