data models - mukular/food-delivery-feastfast--architecture GitHub Wiki
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.
Represents all authenticated users in the system, including:
- Customers
- Sellers (restaurant owners)
- Delivery partners
- Admins
- Authentication & authorization
- Role-based access
- Wallet management
- Session ownership
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
}
- Single user table for all roles β simpler auth & session logic
- Wallet is stored here for atomic updates
- Role determines dashboard & permissions
Represents a restaurant owned by a seller.
- One seller β One shop
- One shop β Many items
- One shop β Many shopOrders (embedded in orders)
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
}
- GeoJSON Point used for $geoNear
- serviceRadiusMeters protects sellers from far orders
- Ratings are denormalized for fast reads
Represents individual menu items sold by a restaurant.
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
}
- Items are queried frequently β indexed fields
- Availability allows temporary disabling without deletion
Represents a customer order, which may contain multiple shop orders.
This is the heart of the system.
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
}
Represents one restaurantβs portion of an order.
- Orders are always fetched with shopOrders
- Atomic updates per order
- Faster reads
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
}
- Order lifecycle is tracked per shop
- Timestamps allow:
- Analytics
- Time-to-deliver calculations
- Seller performance metrics
Represents promotional offers created by sellers.
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
}
- Designed for complex real-world rules
- User usage stored inside coupon for fast validation
- Trade-off: document grows β acceptable for coupon scale
Links delivery partners to specific shop orders.
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
}
- Delivery lifecycle is independent
- Cleaner tracking for delivery partners
- Easier future scaling (batch deliveries, routing)
a) Sessions
session:{sessionId} β user data
b) Cached Queries
restaurants:{lat}:{lng}:{filters}
menu:{shopId}:{filters}
- Fast reads
- Reduces DB load
- Centralized session control
User
βββ Shop (seller)
β βββ Item
β βββ Coupon
β
βββ Order
β βββ ShopOrder (embedded)
β β βββ Items
β
βββ DeliveryAssignment (delivery partner)
- Denormalization for performance
- Embedded documents for atomicity
- Read-heavy optimization
- Geo-spatial indexing
- TTL-based caching
- Real-world trade-offs documented
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.