Intellidine is a SaaS restaurant ordering system that lets customers order food from their table using QR codes and helps restaurants manage operations from kitchen to payment.
Key Innovation: AI-powered dynamic pricing that optimizes revenue by suggesting discounts based on demand patterns and inventory levels.
┌──────────────────────────────────────────────────────────────────┐
│ CUSTOMERS (Mobile Web) │
│ Scan QR → Browse Menu → Add to Cart → Place Order → Pay │
└──────────────┬───────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────┐
│ API Gateway (Port 3100) │
│ - Route requests │
│ - JWT validation │
│ - Rate limiting │
└─────────────────────────────┘
│
┌──────────┼──────────┬──────────────┬──────────────┬──────────────┐
│ │ │ │ │ │
▼ ▼ ▼ ▼ ▼ ▼
┌────────┐┌─────────┐┌────────┐┌──────────┐┌──────────┐┌─────────┐
│ Auth ││ Menu ││ Order ││ Payment ││ Discount ││Inventory│
│Service ││Service ││Service ││Service ││Engine ││Service │
│3101 ││3102 ││3104 ││3107 ││3106 ││3105 │
│ ││ ││ ││ ││ ││ │
│OTP ││Browse ││Create ││Razorpay ││ML Price ││Reserve │
│Staff ││Items ││Track ││Cash ││Rules ││Stock │
│Login ││ ││ ││ ││ ││ │
└────────┘└─────────┘└────────┘└──────────┘└─────────┘└─────────┘
▲ ▲ ▲ ▲ ▲
│ │ │ │ │
└──────────┴──────────┴──────────────┴──────────────┘
│
▼
┌─────────────────────────────┐
│ PostgreSQL (Port 5432) │
│ - Persistent data │
│ - Multi-tenant │
│ - 11 tables │
└─────────────────────────────┘
│
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
┌────────┐┌────────┐┌──────────┐
│ Redis ││ Kafka ││Prometheus│
│3006 ││9092 ││9090 │
│ ││ ││ │
│OTP ││Events ││Metrics │
│Cache ││Queue ││ │
└────────┘└────────┘└──────────┘
What it does: Authenticates users (customers via OTP, staff via username/password)
Key Features:
- Customer OTP generation (SMS via Twilio/SNS)
- Staff login with JWT tokens
- Session management in Redis
- Token expiry (8 hours)
Real Scenario:
Customer arrives:
1. Opens phone camera → scans QR at table
2. Frontend calls: POST /api/auth/customer/otp
Body: { phone_number: "9876543210" }
3. Auth Service generates 6-digit OTP
4. SMS sent: "Your Intellidine OTP is 123456. Valid for 5 min"
5. Customer enters OTP in app
6. Frontend verifies: POST /api/auth/customer/verify-otp
Body: { phone_number, otp: "123456" }
7. Auth Service returns JWT token (8hr expiry)
8. Frontend stores token, uses for all future requests
Endpoints:
POST /api/auth/customer/otp- Generate OTPPOST /api/auth/customer/verify-otp- Verify & get JWTPOST /api/auth/staff/login- Staff loginPOST /api/auth/logout- Invalidate session
What it does: Manages restaurant menu (items, categories, pricing, dietary info)
Key Features:
- Menu categories (Appetizers, Mains, Sides, Desserts, Drinks)
- Menu items with descriptions, images, prices
- Dietary tags (vegan, gluten-free, spicy, etc.)
- Preparation time per item
Data Structure:
Category
├── Menu Item 1 (Paneer Tikka, ₹280, 15 min prep)
├── Menu Item 2 (Butter Chicken, ₹380, 20 min prep)
└── Menu Item 3 (Garlic Naan, ₹50, 5 min prep)
Real Scenario:
Customer opens phone:
1. Frontend calls: GET /api/menu/categories?tenant_id=...
Response: [
{ id: "cat-1", name: "Appetizers", items: 8 },
{ id: "cat-2", name: "Mains", items: 12 },
{ id: "cat-3", name: "Bread", items: 4 }
]
2. User clicks "Mains"
3. Frontend calls: GET /api/menu/items?category_id=cat-2
Response: [
{
id: "item_001",
name: "Paneer Tikka",
price: 280,
description: "Marinated cottage cheese, grilled",
image: "...",
tags: ["vegetarian", "spicy"],
prep_time: 15
},
...
]
Endpoints:
GET /api/menu/categories- List all categoriesGET /api/menu/items?category_id=...- Items in categoryPOST /api/menu/items- Add new item (staff only)PATCH /api/menu/items/{id}- Update item (staff only)
What it does: Handles order creation, tracking, and status updates
Key Features:
- Create orders (items + table + customer)
- Track order status (PENDING → PREPARING → READY → SERVED → COMPLETED)
- Store order items with prices captured at order time
- Handle order modifications & cancellations
- Calculate GST (18%)
Order Lifecycle:
Customer places order (PENDING)
↓
Kitchen starts cooking (PREPARING)
↓
Kitchen finishes (READY)
↓
Waiter delivers (SERVED)
↓
Customer pays (COMPLETED)
↓
Order done ✅
Real Scenario:
1. Customer places order (2 Paneer Tikka, 1 Naan):
POST /api/orders?tenant_id=...
Body: {
"table_id": "tbl-001",
"items": [
{ "menu_item_id": "item_001", "quantity": 2 },
{ "menu_item_id": "item_005", "quantity": 1 }
]
}
2. Order Service:
- Validates items exist
- Calculates: Subtotal ₹610, GST ₹109.80, Total ₹719.80
- Creates order in database (status: PENDING)
- Publishes Kafka event: order.created
3. Multiple systems react:
- Kitchen Display System: Shows order
- Notification Service: Sends "Order received" SMS
- Inventory Service: Reserves stock
- Analytics: Records sale
4. Staff marks as PREPARING when they start cooking
5. Customer checks order status:
GET /api/orders/{order_id}?tenant_id=...
Response: { status: "PREPARING", estimated_time: "15 mins" }
6. When ready, staff updates:
PATCH /api/orders/{order_id}/status
Body: { status: "READY" }
7. Customer gets notification: "Your order is ready!"
Endpoints:
POST /api/orders- Create orderGET /api/orders/{id}- Get order detailsGET /api/orders?status=...- List ordersPATCH /api/orders/{id}/status- Update status (staff)PATCH /api/orders/{id}/cancel- Cancel order (staff)
What it does: Processes payments (online via Razorpay or cash)
Key Features:
- Razorpay integration for card/UPI payments
- Cash payment handling
- Payment status tracking
- Change management for cash payments
Real Scenario - Online Payment:
1. Order complete, customer clicks "Pay Online"
2. Frontend calls: POST /api/payments/razorpay-order
Body: { order_id: "ord-123", amount: 719.80 }
3. Payment Service:
- Creates Razorpay order
- Returns order_id + payment_key
4. Frontend opens Razorpay checkout modal
- Customer enters card details
- Pays ₹719.80
5. Payment Service receives webhook from Razorpay:
- Verifies payment signature
- Updates payment status: COMPLETED
- Publishes Kafka event: payment.completed
6. Order Service reacts:
- Updates order status: COMPLETED
- Order finalized ✅
Real Scenario - Cash Payment:
1. Order ready, customer wants to pay cash
2. Staff opens app: GET /api/payments/{order_id}
3. Payment dialog shows:
- Total: ₹719.80
- Amount received: [input field]
4. Staff enters amount received (e.g., ₹750)
5. Staff clicks "Confirm"
6. Payment Service calculates:
- Amount received: ₹750
- Change to give: ₹30.20
7. Payment recorded, order completed
Endpoints:
POST /api/payments/razorpay-order- Create online paymentPOST /api/payments/verify- Verify Razorpay paymentPOST /api/payments/cash- Record cash paymentGET /api/payments/{order_id}- Check payment status
What it does: Applies dynamic pricing based on demand and inventory
Key Features:
- Calls ML Service for discount predictions
- Stores pricing rules (manual overrides)
- Applies discounts automatically to orders
- Tracks discount history
Real Scenario:
1. It's 8 PM (dinner peak), inventory 85% full
→ ML says: "No discount needed" (0%)
2. It's 3 PM (off-peak), Paneer Tikka inventory 22%
→ ML says: "Critical inventory" (22% discount)
→ Price: ₹280 → ₹218
3. Order Service creates order with:
- Original price: ₹280
- Discount applied: 22%
- Final price: ₹218
4. Customer gets discount automatically!
Integration:
- Called before order creation
- Uses ML Service predictions
- Discount applied transparently to customer
What it does: Tracks ingredient stock and menu item availability
Key Features:
- Track ingredient quantities & reorder levels
- Link recipes to menu items
- Reserve stock when order placed
- Update stock when order completed
- Alert when stock low
Real Scenario:
Stock tracking:
- Paneer (Cottage Cheese): 10 kg in stock, min 5 kg
- Butter: 3 kg in stock, min 2 kg
- Tomato: 25 kg in stock, min 10 kg
When order placed (2 Paneer Tikka):
1. Order Service emits: order.created
2. Inventory Service receives event
3. Looks up recipe: Paneer Tikka needs 150g Paneer
4. Calculates: 2 × 150g = 300g needed
5. Reserves 300g from 10 kg
6. Updates: Paneer now 9.7 kg
When stock drops below minimum:
- Alert sent to manager: "Paneer low stock (4.2 kg remaining)"
Endpoints:
GET /api/inventory/status?items=...- Check stockPOST /api/inventory/adjust- Manual adjustment (staff)GET /api/inventory/alerts- Low stock warningsPOST /api/inventory/recipes- Define recipe ingredients
What it does: Sends notifications to customers and staff
Key Features:
- SMS notifications via SNS/Twilio
- Order status updates
- Payment confirmations
- Low stock alerts
Real Scenario:
Customer journey notifications:
7:30 PM - Order placed:
→ SMS: "Order received! 2 Paneer Tikka, 1 Naan. ETA 15 mins."
7:35 PM - Kitchen starts:
→ SMS: "Your order is being prepared. ETA 12 mins."
7:45 PM - Ready:
→ SMS: "Your order is ready! Please collect from table."
7:50 PM - Paid:
→ SMS: "Payment received. Thank you for dining!"
Endpoints:
POST /api/notifications/send- Send notification (internal)- Mostly event-driven via Kafka
What it does: Collects metrics and generates reports
Key Features:
- Track total sales, order count, revenue
- Average order value
- Popular items
- Peak hours analysis
- Staff performance
Real Scenario:
Manager checks dashboard:
Today's Summary (Oct 22, 2025):
- Total Orders: 142
- Total Revenue: ₹18,540
- Average Order Value: ₹130.56
- Top Item: Butter Chicken (28 orders)
- Peak Hour: 1-2 PM (47 orders)
Peak Hours vs Off-Peak:
- 12-2 PM (Lunch): ₹8,240 (63 orders)
- 7-10 PM (Dinner): ₹7,850 (58 orders)
- 3-5 PM (Off-peak): ₹2,450 (21 orders)
Endpoints:
GET /api/analytics/daily- Daily summaryGET /api/analytics/items- Item popularityGET /api/analytics/peak-hours- Peak time analysisGET /api/analytics/revenue- Revenue trends
What it does: Predicts optimal discounts using XGBoost
Key Features:
- Analyzes current time, inventory, demand patterns
- Recommends discount percentage (0%, 5-10%, 15%, 20-25%)
- Provides confidence scores
- Real-time predictions (5-10ms)
Real Scenario:
8:00 PM (Dinner peak, Friday, 85% inventory):
→ ML says: "0% discount" (peak demand)
3:00 PM (Off-peak, Monday, 22% inventory):
→ ML says: "22% discount" (critical inventory)
Feature vector sent to ML:
{
hour: 15,
day_of_week: 1,
is_weekend: 0,
is_lunch_peak: 0,
is_dinner_peak: 0,
is_month_end: 0,
is_holiday_week: 0,
inventory_level: 0.22,
num_items: 2,
total_price: 560,
order_duration: 30
}
Output:
{
discount_percentage: 22,
confidence: 0.82,
reason: "Critical inventory levels"
}
Endpoints:
POST /predict- Get discount recommendationsGET /health- Service health checkPOST /train- Retrain model (dev only)
What it does: Entry point for all API requests
Key Features:
- Route requests to correct microservice
- JWT token validation
- Rate limiting (prevent abuse)
- CORS handling
- Logging
How it works:
Request comes in: POST /api/orders
↓
API Gateway checks:
1. JWT token valid? ✓
2. Tenant ID in token matches request? ✓
3. Rate limit OK? ✓
↓
Routes to: Order Service (port 3104)
↓
Response returned to client
Persistent data storage with 11 core tables:
| Table | Purpose | Example Data |
|---|---|---|
tenants |
Restaurants | Spice Route, Taj Mahal |
users |
Staff accounts | manager1, kitchen_staff1 |
customers |
Customer phone records | 9876543210 |
menu_items |
Dish names/prices | Paneer Tikka ₹280 |
categories |
Menu categories | Appetizers, Mains |
orders |
Order records | ord-123, Status: PENDING |
order_items |
Items in order | 2x Paneer Tikka, 1x Naan |
payments |
Payment records | ord-123, ₹719.80, COMPLETED |
tables |
Restaurant tables | Table 1-8, QR codes |
inventory |
Ingredient stock | Paneer 10kg |
otp_verifications |
OTP history | phone, otp_hash, expires_at |
In-memory cache and session storage:
- OTP codes: 5-minute expiry
- Sessions: 24-hour expiry
- Cached menu: 1-hour expiry
- Temporary counters: Request tracking
Event streaming for async communication:
Topics (channels):
order.created- New order publishedorder.status_changed- Status updatespayment.completed- Payment confirmedinventory.low_stock- Stock alertdiscount.applied- Discount info
┌─────────────────────────────────────────┐
│ Customer Phone │
│ Scan QR → https://intellidine.app/... │
└────────────────┬────────────────────────┘
│
▼
┌────────────────────┐
│ Frontend (React) │
│ Extract table ID │
└────────────────────┘
Frontend:
POST /api/auth/customer/otp
Body: { phone_number: "9876543210" }
│
├─→ API Gateway (3100)
│ │
└─→ Auth Service (3101)
│
├─→ PostgreSQL (store OTP hash)
├─→ Redis (cache OTP, 5 min)
├─→ SNS/Twilio (send SMS)
│
Response: "OTP sent to 9876543210"
Frontend:
POST /api/auth/customer/verify-otp
Body: { phone_number, otp: "123456" }
│
├─→ API Gateway (3100)
│ │
└─→ Auth Service (3101)
│
├─→ Redis (verify OTP)
├─→ PostgreSQL (create/fetch customer)
├─→ Redis (store session)
│
Response: { access_token: "eyJhbGc..." }
Frontend stores JWT, uses for future requests
Frontend:
GET /api/menu/items?tenant_id=...
│
├─→ API Gateway (validate JWT, tenant_id)
│ │
└─→ Menu Service (3102)
│
├─→ PostgreSQL (query menu_items)
│
Response: [{ id, name, price, image, ... }]
Frontend:
POST /api/orders?tenant_id=...
Body: { items: [{ menu_item_id, quantity }] }
│
├─→ API Gateway (validate JWT)
│ │
└─→ Order Service (3104)
│
├─→ Menu Service (verify items exist)
│
├─→ Discount Engine (get ML discount)
│ │
│ └─→ ML Service (predict discount)
│
├─→ PostgreSQL (create order record)
│
├─→ Kafka publish: order.created
│ │
│ ├─→ Notification Service (send SMS)
│ ├─→ Analytics Service (record sale)
│ ├─→ Inventory Service (reserve stock)
│ └─→ Kitchen Display (show order)
│
Response: { order_id: "ord-123", total: 719.80 }
Staff app (KDS):
1. Sees order on screen
2. Clicks "Start Cooking"
3. Sends: PATCH /api/orders/ord-123/status
Body: { status: "PREPARING" }
│
└─→ Order Service
│
├─→ PostgreSQL (update status)
│
├─→ Kafka publish: order.status_changed
│ │
│ └─→ Notification Service (send SMS)
│
Response: ✓ Status updated
Staff marks ready:
PATCH /api/orders/ord-123/status
Body: { status: "READY" }
│
└─→ (same flow as Step 6)
Customer receives SMS: "Your order is ready!"
Customer clicks "Pay":
1. Option 1 - Online: POST /api/payments/razorpay-order
→ Razorpay checkout
→ Customer pays
→ Webhook updates status
2. Option 2 - Cash: POST /api/payments/cash
→ Staff confirms amount
→ Change calculated
Payment Service:
├─→ PostgreSQL (record payment)
├─→ Kafka publish: payment.completed
│ │
│ └─→ Order Service (update status: COMPLETED)
│
Response: Payment recorded ✓
Final state:
- Order status: COMPLETED
- Payment status: COMPLETED
- Revenue recorded in Analytics
- Analytics dashboard updated
- Order history saved for future reference
✅ Complete flow finished!
1. Scans QR → No login required
2. Gets OTP via SMS
3. Enters OTP → Receives JWT token
4. Token valid for 8 hours
5. Can place orders, view order status
6. Cannot access admin functions
1. Staff login: POST /api/auth/staff/login
Body: { username: "manager1", password: "Password@123" }
2. Auth Service verifies credentials
3. Returns JWT with role: "MANAGER" | "KITCHEN_STAFF" | "WAITER"
4. Different endpoints require different roles:
- Update order status → MANAGER or KITCHEN_STAFF
- Manage menu items → MANAGER only
- View analytics → MANAGER only
- Create orders (POS) → WAITER or MANAGER
JWT Token contains:
{
sub: "user-id",
tenant_id: "11111111-1111-1111-1111-111111111111",
role: "MANAGER",
phone: "9876543210",
exp: 1729696800 // 8 hours from now
}
On every request:
1. API Gateway extracts JWT
2. Verifies signature (secret key)
3. Checks expiry
4. Validates tenant_id in token matches request
5. Validates role has permission for endpoint
6. Passes to service
Problem: Multiple restaurants use same system, must be completely isolated
Solution: Tenant ID on every operation
Restaurant 1: tenant_id = "11111111-1111-1111-1111-111111111111"
- Menu items only for Restaurant 1
- Orders only from Restaurant 1's tables
- Staff can only manage Restaurant 1
Restaurant 2: tenant_id = "22222222-2222-2222-2222-222222222222"
- Separate menu, orders, staff
- No data mixing
Every query filtered by tenant_id:
GET /api/menu/items?tenant_id=111...
→ SELECT * FROM menu_items
WHERE tenant_id = '111...' AND is_deleted = FALSE
// No way to query across tenants
// Staff JWT includes tenant_id
// API Gateway validates tenant_id in request matches JWT
Services don't call each other directly (reduces coupling):
❌ OLD WAY (tightly coupled):
Order Service calls Notification Service directly
→ Notification Service down? Order Service fails
✅ NEW WAY (event-driven):
Order Service: "An order was created!"
→ Publishes to Kafka topic: order.created
Kafka stores event, any service can consume:
├─→ Notification Service: "Send SMS!"
├─→ Analytics Service: "Record sale!"
├─→ Inventory Service: "Reserve stock!"
└─→ Kitchen Display: "Show on screen!"
If Notification Service is down temporarily:
→ Event stays in Kafka queue
→ Notification Service catches up when it comes back online
| Event | Publisher | Subscribers |
|---|---|---|
order.created |
Order Service | Notification, Analytics, Inventory, Kitchen |
order.status_changed |
Order Service | Notification, Analytics |
payment.completed |
Payment Service | Order Service, Analytics |
inventory.low_stock |
Inventory Service | Notification (alert manager) |
discount.applied |
Discount Engine | Analytics |
Time: 7:30 PM, Friday
Current inventory: 85% full (plenty of stock)
ML Model prediction: 0% discount (peak demand)
Customer places order (₹280 Paneer Tikka):
- Price: ₹280 (no discount)
- ML confidence: 0.95
- Reason: "Peak dinner hour"
System's reasoning:
- Peak time → High demand
- Stock available → No need to discount
- Maximize revenue → Sell at full price
Result: ✅ Restaurant captures full revenue
Time: 3:30 PM, Tuesday
Current inventory: 22% full (critical low stock)
ML Model prediction: 22% discount
Customer places order (₹280 Paneer Tikka):
- Original price: ₹280
- Discount: 22%
- Final price: ₹218
- ML confidence: 0.82
- Reason: "Critical inventory levels"
System's reasoning:
- Off-peak time → Low demand
- Low inventory → Risk of waste
- Apply discount → Encourage purchase
- Sell at 22% off better than 100% waste
Result: ✅ Item sells, minimizes waste, still captures revenue
Time: 8:15 PM
Customer finishes eating, clicks "Pay"
Option A - Online Payment:
1. Razorpay checkout appears
2. Customer pays ₹719.80 via card
3. Razorpay returns: Payment successful
4. Payment Service verifies & updates status
5. Order marked COMPLETED
6. SMS: "Thank you! Payment received."
Option B - Cash Payment:
1. Staff enters amount received: ₹750
2. System calculates change: ₹30.20
3. Staff gives cash & receipt
4. Order marked COMPLETED
5. SMS: "Thank you! Payment received."
Either way → Order finalized, revenue recorded
Time: 8:10 PM
Order placed 5 minutes ago (status: PREPARING)
Customer: "Can we add 1 Garlic Naan?"
Staff tablet:
1. Opens order details
2. Clicks "+ Add Item"
3. Selects "Garlic Naan"
4. Confirms update
Backend:
1. Adds item to order
2. Recalculates totals (+₹50)
3. Kafka event: order_items_added
4. Kitchen display updates (shows new naan)
5. Notification: "Item added to your order"
Result: ✅ Order updated, kitchen notified, total updated
Time: 8:45 PM
Order placed: 2x Paneer Tikka
Inventory Service:
- Before: Paneer = 2.3 kg (below min 5 kg)
- After order: Paneer = 2.0 kg (CRITICAL)
- Emits Kafka event: inventory.low_stock
Notification Service receives:
- Sends SMS to manager: "⚠️ Paneer low: 2.0 kg remaining"
Manager response:
- Calls supplier
- Orders more Paneer
- Status updated when stock arrives
Result: ✅ Prevents running out of critical ingredients
| Operation | Typical Time | Max Time |
|---|---|---|
| Browse menu (10 items) | 50ms | 200ms |
| Create order | 150ms | 500ms |
| Get ML discount | 8ms | 20ms |
| Process payment (Razorpay) | 2 sec | 5 sec |
| Update order status | 80ms | 300ms |
- Peak load: 100 concurrent orders per minute
- Database: 5,000 queries/second capacity
- Kafka: 10,000 events/second capacity
- API Gateway: Can route 50,000 requests/minute
All services are stateless and can run multiple instances:
API Gateway (3100)
├─→ Order Service instance 1
├─→ Order Service instance 2
├─→ Order Service instance 3
└─→ Load balancer distributes requests
| Error | Cause | Recovery |
|---|---|---|
| "Invalid OTP" | Wrong code entered | User can retry (5 attempts) |
| "Table not found" | Invalid table ID in URL | Scan correct QR code |
| "Item out of stock" | Item just sold out | Show "Currently unavailable" |
| "Payment failed" | Card declined/timeout | Show retry button |
| "Order cannot be cancelled" | Already being prepared | Show "Cannot cancel" message |
If Order Service goes down:
✗ New orders cannot be created
✓ But customers still see menu
✓ Staff get notification to call manually
If Notification Service goes down:
✗ No SMS sent immediately
✓ Events queued in Kafka
✓ Service restarts → catches up on events
If Discount Engine goes down:
✓ Orders still created at full price (safe default)
✓ Customers don't lose ability to order
If Payment Service fails:
✓ Order marked status "AWAITING_PAYMENT"
✓ Staff can manually collect payment later
- Services don't store session data
- Can scale horizontally (multiple instances)
- Any instance can handle any request
- Every operation filtered by tenant_id
- No cross-tenant data leakage possible
- Complete isolation at database level
- Services communicate via Kafka events
- Loose coupling (services don't know each other)
- Better fault tolerance (slow service doesn't block others)
- PostgreSQL for persistent data
- Redis for caching & sessions
- Kafka for event replay if needed
- JWT tokens for authentication
- Role-based access control
- Tenant ID validation on every request
- No sensitive data in logs
- Endpoints: All 35+ REST API endpoints
- Authentication: How to get JWT tokens
- Data Models: Order structure, payment flow
- Workflows: Complete user journeys
- Error Handling: What to show when failures happen
- ✅ Implement OTP flow (for customers)
- ✅ Display menu from Menu Service
- ✅ Implement cart (in-memory, no persistence)
- ✅ Place orders with Order Service
- ✅ Track order status in real-time
- ✅ Implement payment (Razorpay or cash)
- ✅ Handle errors gracefully
- ✅ Show discount info to user
Start here: This document (System Overview)
Then dive into:
- ORDERING_WORKFLOW.md - See complete flow
- API_ENDPOINTS.md - All endpoints with examples
- Service-specific docs for what you're building
Reference while coding:
- DATABASE.md - Data models
- KAFKA_EVENTS.md - Event structure
- 10 Services (9 NestJS + 1 Python ML)
- 35+ API Endpoints
- 11 Database Tables
- 7 Kafka Topics
- 4 Different User Roles (CUSTOMER, MANAGER, KITCHEN_STAFF, WAITER)
- ~5,000 Lines of Code per service
- 100 SQL Queries/second typical traffic
- 8-hour JWT expiry for security
Current State: ✅ Ready for Frontend Integration
- ✅ All microservices deployed & healthy
- ✅ Database seeded with staff users
- ✅ ML model trained & predictions working
- ✅ Authentication working (OTP + staff login)
- ✅ Order lifecycle complete
- ✅ Payment integration ready
- ✅ 35+ endpoints tested
Blockers: None 🎉
Next Steps:
- Frontend team should read ORDERING_WORKFLOW.md
- Get familiar with API_ENDPOINTS.md
- Start building React components
- Reference individual service docs as needed
Happy building! 🚀