Version: 1.0
Last Updated: October 2025
Status: Production Ready
- Tech Stack
- System Architecture
- Microservices Overview
- Communication Patterns
- Authentication & Authorization
- Database Architecture
- Event-Driven Architecture
- Multi-Tenancy Implementation
- Monitoring & Observability
- Deployment Architecture
- API Gateway
- Performance & Scaling
- Runtime: Node.js 20 (Alpine Linux)
- Framework: NestJS 10 (TypeScript-first)
- Database: PostgreSQL 15 (Relational data)
- Cache: Redis 7 (Sessions, caching)
- Message Queue: Apache Kafka 7.5.0 (Event streaming)
- ORM: Prisma 5 (Database access & migrations)
- Containerization: Docker & Docker Compose
- Reverse Proxy: Nginx
- Monitoring: Prometheus + Grafana
- Tunneling: Cloudflare Tunnel (for production)
- Language: TypeScript 5
- Testing: Jest
- Package Manager: npm
- Version Control: Git
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Frontend Applications β
β (Web & Mobile - intellidine.aahil-khan.tech) β
ββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββ
β
HTTPS / JWT Token
β
ββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββ
β API Gateway (intellidine-api.aahil-khan.tech) β
β - Single entry point for all requests β
β - Request routing to backend services β
β - Response wrapping & error handling β
β - CORS handling β
ββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββ
β
ββββββββββββββββββββΌβββββββββββββββββββ¬ββββββββββββββββββ
β β β β
βΌ βΌ βΌ βΌ
Auth Service Menu Service Order Service Payment Service
(Port 3101) (Port 3103) (Port 3102) (Port 3105)
β β β β
ββββββββββββββββββββ΄βββββββββββββββββββ΄ββββββββββββββββββ
β
Shared PostgreSQL Database
(Tenant-Isolated Data)
β
ββββββββββββββββββββΌβββββββββββββββββββ¬ββββββββββββββββββ
β β β β
βΌ βΌ βΌ βΌ
Inventory Svc Notification Svc Analytics Svc Discount Engine
(Port 3104) (Port 3106) (Port 3107) (Port 3108)
β β β
β ββββββββββββ¬ββββββββ
β β
β Apache Kafka Queue
β (Event Streaming)
β β
βββββββββββββββββββββββββββββββ
Cache & Sessions: Redis (Port 6379)
- Single Entry Point: All external requests go through API Gateway
- Service Isolation: Each service has its own responsibility
- Shared Database: Multi-tenancy enforced at application level
- Asynchronous Processing: Kafka for non-blocking operations
- Scalability: Services can be scaled independently
Responsibility: Route all external requests to appropriate services
Key Features:
- Request routing based on path patterns
- Response wrapping in consistent format
- CORS handling
- Health check aggregation
- Route listing endpoint
Routing Rules:
GET /health β Aggregate health from all services
GET /routes β List all available routes
POST /api/auth/* β Auth Service
GET /api/menu/* β Menu Service
POST /api/orders/* β Order Service
GET /api/payments/* β Payment Service
GET /api/inventory/* β Inventory Service
POST /api/notifications/* β Notification Service
GET /api/analytics/* β Analytics Service
POST /api/discounts/* β Discount Engine
Ports Mapping:
- Gateway: 3000 (localhost) / 3100 (Docker)
- Production:
intellidine-api.aahil-khan.tech
Responsibility: Customer authentication, staff login, JWT token generation
Authentication Flows:
1. Request OTP
POST /api/auth/customer/request-otp
Body: { phone: "9876543210", tenant_id: "11111111-..." }
Response: { message: "OTP sent", expires_at: "2025-10-22T10:00:00Z" }
2. Verify OTP
POST /api/auth/customer/verify-otp
Body: { phone: "9876543210", otp: "123456", tenant_id: "11111111-..." }
Response: {
access_token: "eyJhbGc...",
expires_at: "2025-10-22T18:00:00Z",
user: { id: "...", phone_number: "9876543210" }
}
POST /api/auth/staff/login
Body: { username: "manager1", password: "Password@123", tenant_id: "11111111-..." }
Response: {
access_token: "eyJhbGc...",
expires_at: "2025-10-22T18:00:00Z",
user: { id: "...", username: "manager1", email: "...", role: "MANAGER" }
}
Pre-seeded Staff Users β :
- Username:
manager1| Password:Password@123| Role:MANAGER - Username:
kitchen_staff1| Password:Password@123| Role:KITCHEN_STAFF - Username:
waiter1| Password:Password@123| Role:WAITER - All linked to tenant:
11111111-1111-1111-1111-111111111111(Spice Route)
Key Components:
- OTP Service: Generates, stores, verifies OTPs via MSG91
- JWT Utils: Token generation (8hr expiry)
- Password Hashing: bcrypt with salt rounds
- Session Management: Redis-based token validation
Database:
customerstable: phone_number (unique)userstable: username, email, role, password_hashotp_verificationstable: phone_number, otp_hash, expires_at
Responsibility: Menu item management, categories, availability
Key Operations:
- Get menu items (paginated)
- Get single item details
- Create menu item
- Update price/availability
- Delete menu item (soft delete)
- Filter by category
Database:
categoriestable: name, display_ordermenu_itemstable: tenant_id, category_id, name, price, cost_price, discount_percentage, is_available
Key Features:
- Multi-tenant isolation (tenant_id in all queries)
- Soft deletes for audit trail
- Redis caching for menu lists
- Price history tracking
Responsibility: Order creation, status management, order history
Order Workflow:
1. Create Order
Items selected β Calculate total β Create order record
Status: "pending"
2. Payment Processing
Order β Payment Service β Order status: "paid"
3. Kitchen Preparation
Status: "preparing"
4. Completion
Status: "completed"
5. Cancellation (anytime before completion)
Status: "cancelled"
Database:
orderstable: customer_id, table_id, status, total_amount, tax, discountorder_itemstable: order_id, menu_item_id, quantity, priceorder_status_historytable: audit trail
Key Features:
- Order status tracking
- Item-level pricing (captured at order time)
- Multi-tenant isolation
- Kafka event publishing (order created, completed)
Responsibility: Payment processing via Razorpay & cash
Payment Methods:
- Razorpay: Online payment processing (UPI, cards, wallets)
- Cash: On-premise cash handling
Razorpay Flow:
1. Create Razorpay Order
POST /api/payments/create-razorpay-order
Body: { order_id, amount, tenant_id }
Response: { razorpay_order_id, ... }
2. Client-side Payment (JavaScript SDK)
Razorpay.open({ key, order_id, ... })
3. Verify Payment
POST /api/payments/verify-razorpay
Body: { razorpay_order_id, razorpay_payment_id, razorpay_signature }
Validates signature using Razorpay secret
Database:
paymentstable: order_id, tenant_id, amount, method, status, razorpay_order_id, razorpay_payment_id
Key Features:
- Signature verification for Razorpay
- Kafka event publishing (payment succeeded/failed)
- Payment statistics API (daily revenue)
Responsibility: Stock management, reorder alerts, inventory tracking
Key Features:
- Stock quantity tracking
- Reorder level alerts
- Expiry date tracking
- Low stock notifications (via Kafka)
Database:
inventorytable: tenant_id, item_name, category, quantity, unit, reorder_level, cost_price, expiry_date
Workflow:
- Create inventory item with reorder level
- Update quantity as items are used
- Trigger notification when below reorder level
- Track expiry dates
Responsibility: Real-time notifications via WebSocket + Kafka events
Notification Types:
- Order status updates
- Payment confirmations
- Inventory alerts
- Kitchen display system
- Customer notifications
Technology Stack:
- Socket.io for WebSocket connections
- Kafka consumer for events
- Redis for connection management
Key Features:
- Real-time message delivery
- Connection statistics
- Multi-room support (by tenant/kitchen/table)
- Automatic reconnection handling
Responsibility: Business metrics, trends, reporting
Key Metrics:
- Daily revenue
- Order count & trends
- Top selling items
- Peak hours
- Customer behavior patterns
Database:
- Aggregated views on orders, payments, menu items
Key Features:
- Time-series data
- Trend analysis
- Revenue forecasting (future)
Responsibility: Discount rule evaluation and application
Discount Types:
- Percentage-based (e.g., 10% off)
- Fixed amount (e.g., βΉ50 off)
- Time-based (happy hour specials)
- Volume-based (buy 2 get discount)
Evaluation:
1. Receive order details
2. Match against discount rules
3. Calculate applicable discounts
4. Return discount amount & breakdown
Database:
pricing_rulestable: discount rules, conditions, percentage/amount
Responsibility: Predictive models for business intelligence
Models (Pending):
- Demand forecasting
- Customer churn prediction
- Menu recommendation
- Optimal pricing
Technology: Python with scikit-learn/TensorFlow
Used for: Immediate responses required
Pattern:
Client β API Gateway β Service β Database β Response
(routes)
Examples:
- Get menu items
- Create order
- Verify payment
- Update inventory
Latency: 10-100ms
Used for: Non-blocking operations, event streaming
Pattern:
Service A publishes event to Kafka topic
β
Kafka broker persists message
β
Service B, C, D consume and process event
Events Published:
- order.created - New order placed
- order.completed - Order ready/finished
- order.cancelled - Order cancelled
- payment.succeeded - Payment confirmed
- payment.failed - Payment failed
- inventory.low_stock - Stock below reorder level
- customer.created - New customer registered
Consumers:
- Notification Service β Sends notifications
- Analytics Service β Records metrics
- Inventory Service β Updates stock
- Order Service β Updates order status
Benefits:
- Decoupled services
- Non-blocking operations
- Reliable event delivery
- Easy to add new consumers
Technology: Redis
Usage:
Auth Service generates JWT β Stores in Redis (8 hours TTL)
Service validates token β Checks Redis
Token expires β Redis auto-deletes
Keys:
session:${userId}:${token}
Header: {
"alg": "HS256",
"typ": "JWT"
}
Payload: {
"userId": "customer_123",
"role": "customer",
"iat": 1697969280,
"exp": 1697987280, // 8 hours later
"tenant_id": "11111111-1111-1111-1111-111111111111"
}
Signature: HMACSHA256(secret_key)
Roles:
SUPER_ADMIN: Full system accessMANAGER: Restaurant managementKITCHEN_STAFF: Order preparationWAITER: Table serviceCUSTOMER: Customer portal
Guard Implementation:
@UseGuards(JwtGuard, RolesGuard)
@RequireRole('MANAGER')
async deleteMenuItem() {
// Only managers can delete menu items
}Principle: Every request includes tenant_id in:
- JWT token (tenant_id claim)
- X-Tenant-ID header
- Request body
Enforcement:
// Every query includes tenant_id filter
const items = await db.menu_items.findMany({
where: {
tenant_id: req.user.tenant_id, // Always filtered by tenant
is_deleted: false
}
});Security:
- Tenant cannot access another tenant's data
- Tenant_id validated at middleware level
- JWT signed with secret (cannot be forged)
Tenants
ββ id (PK, UUID)
ββ name
ββ contact
ββ owner_email
ββ is_active
βββ Users (via tenant_id)
β ββ id (PK, UUID)
β ββ tenant_id (FK)
β ββ username (UNIQUE)
β ββ email (UNIQUE)
β ββ password_hash
β ββ role (ENUM)
β ββ is_active
β
βββ Customers (Global)
β ββ id (PK, UUID)
β ββ phone_number (UNIQUE)
β ββ name
β ββ Orders (1:N)
β
βββ Tables (via tenant_id)
β ββ id (PK, UUID)
β ββ tenant_id (FK)
β ββ table_number
β ββ capacity
β ββ Orders (1:N)
β
βββ MenuItems (via tenant_id)
β ββ id (PK, UUID)
β ββ tenant_id (FK)
β ββ category_id (FK)
β ββ name
β ββ price
β ββ cost_price
β ββ discount_percentage
β ββ is_available
β
βββ Categories
β ββ id (PK, String)
β ββ name
β ββ display_order
β
βββ Orders (via tenant_id)
β ββ id (PK, UUID)
β ββ tenant_id (FK)
β ββ customer_id (FK)
β ββ table_id (FK)
β ββ status (ENUM)
β ββ total_amount
β ββ tax
β ββ discount
β ββ OrderItems (1:N)
β ββ Payments (1:1)
β
βββ Inventory (via tenant_id)
β ββ id (PK, UUID)
β ββ tenant_id (FK)
β ββ item_name
β ββ quantity
β ββ reorder_level
β ββ expiry_date
β
βββ Payments (via tenant_id)
ββ id (PK, UUID)
ββ tenant_id (FK)
ββ order_id (FK)
ββ method (ENUM)
ββ status (ENUM)
ββ razorpay_order_id
-- Frequently queried columns
CREATE INDEX idx_users_tenant_id ON users(tenant_id);
CREATE INDEX idx_orders_tenant_id ON orders(tenant_id);
CREATE INDEX idx_orders_customer_id ON orders(customer_id);
CREATE INDEX idx_order_items_order_id ON order_items(order_id);
CREATE INDEX idx_menu_items_tenant_id ON menu_items(tenant_id);
CREATE INDEX idx_inventory_tenant_id ON inventory(tenant_id);File: backend/prisma/seed.sql
Default Data β :
- Tenant: "Spice Route" (ID: 11111111-1111-1111-1111-111111111111)
- Tables: 5 tables (capacity 2-6)
- Categories: Appetizers, Main Course, Sides, Desserts
- Menu Items: 5 sample items (biryani, dal, butter chicken, etc.)
- Inventory: 3 stock items (paneer, chicken, flour)
- Staff Users β
(NEW):
- manager1 (Password@123) - MANAGER
- kitchen_staff1 (Password@123) - KITCHEN_STAFF
- waiter1 (Password@123) - WAITER
Migration:
npx prisma migrate dev --name initial
# Runs all .sql files in migrations/
# Automatically creates staff usersAll Users Ready for Testing β
Topic: orders
{
"event": "order.created",
"order_id": "uuid",
"tenant_id": "uuid",
"customer_id": "uuid",
"items": [...],
"total_amount": 450.50,
"timestamp": "2025-10-22T10:30:00Z"
}Consumers:
- Notification Service β Notify customer
- Analytics Service β Record metric
- Discount Engine β Check eligibility
Topic: inventory
{
"event": "inventory.low_stock",
"item_name": "Paneer",
"current_quantity": 2.5,
"reorder_level": 5.0,
"tenant_id": "uuid",
"timestamp": "2025-10-22T10:30:00Z"
}Consumers:
- Notification Service β Alert manager
- Analytics Service β Track trends
Topic: payments
{
"event": "payment.succeeded",
"payment_id": "uuid",
"order_id": "uuid",
"amount": 450.50,
"method": "razorpay",
"tenant_id": "uuid",
"timestamp": "2025-10-22T10:30:00Z"
}Model: Database-level isolation with table-level filtering
βββββββββββββββββββ
β PostgreSQL DB β
β (intellidine) β
ββββββββββ¬βββββββββ
β
βββββββββββββββββΌββββββββββββββββ
β β β
Tenant A Tenant B Tenant C
(Spice Route) (Biryani House) (Pizza Palace)
β β β
All data filtered All data filtered ...
by tenant_id by tenant_id
-
Middleware Level - Validates tenant_id in JWT
// Extracts tenant_id from token req.user.tenant_id = "11111111-..."
-
Service Level - Filters all queries
const items = await db.menuItem.findMany({ where: { tenant_id: req.user.tenant_id // Always included } });
-
Request Level - Validates tenant_id in body/params
// Mismatch rejected if (req.body.tenant_id !== req.user.tenant_id) { throw new ForbiddenException("Tenant mismatch"); }
- Data Privacy: Each tenant completely isolated
- Multi-tenant Scaling: Single database, multiple tenants
- Cost Efficient: Shared infrastructure
- Security: No data leakage between tenants
Container: intellidine-prometheus (Port 9090)
Configuration: monitoring/prometheus/prometheus.yml
Current Status: π΄ PARTIALLY SETUP
- Prometheus running
- Scrapes Prometheus metrics
- Service metrics endpoints: NOT YET EXPOSED
To Enable Service Metrics:
-
Add Prometheus client library to services:
npm install @nestjs/metrics prom-client
-
Enable metrics endpoint in each service:
import { PrometheusModule } from '@nestjs/metrics'; @Module({ imports: [PrometheusModule.register()], }) export class AppModule {}
-
Update prometheus.yml:
scrape_configs: - job_name: 'api-gateway' static_configs: - targets: ['api-gateway:3100'] metrics_path: '/metrics' - job_name: 'auth-service' static_configs: - targets: ['auth-service:3101'] metrics_path: '/metrics' # ... repeat for all services
-
Restart Prometheus:
docker-compose restart prometheus
Container: intellidine-grafana (Port 3009)
Access:
- URL:
http://localhost:3009 - Username:
admin - Password:
${GRAFANA_PASSWORD}(from .env)
Current Status: π‘ RUNNING BUT NO DASHBOARDS
Setup Steps:
1. Login to Grafana
2. Menu β Configuration β Data Sources
3. Click "Add data source"
4. Select "Prometheus"
5. URL: http://prometheus:9090
6. Click "Save & Test"
Option A: Quick Dashboard (Manual)
1. Menu β Create β Dashboard
2. Click "Add panel"
3. Select Prometheus as data source
4. Write PromQL query:
- Total requests: sum(rate(http_requests_total[5m]))
- Response time: histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))
5. Set refresh interval (30s)
6. Save dashboard
Option B: Import Dashboard (Recommended)
1. Visit grafana.com/grafana/dashboards
2. Search "NestJS" or "Node.js"
3. Copy dashboard ID (e.g., 11074)
4. In Grafana: Menu β Create β Import
5. Paste ID, select Prometheus data source
6. Import
1. HTTP Requests
- Total requests: http_requests_total
- Request rate: rate(http_requests_total[5m])
- Success rate: rate(http_requests_total{status="200"}[5m])
2. Response Time (Latency)
- P50: histogram_quantile(0.50, http_request_duration_seconds)
- P95: histogram_quantile(0.95, http_request_duration_seconds)
- P99: histogram_quantile(0.99, http_request_duration_seconds)
3. Errors
- Error rate: rate(http_requests_total{status=~"5.."}[5m])
- 404s: rate(http_requests_total{status="404"}[5m])
4. Database Connections
- Active connections: db_pool_size
- Query time: db_query_duration_seconds
1. Orders
- Orders per minute: rate(orders_created_total[1m])
- Average order value: orders_total_amount / orders_total_count
2. Revenue
- Revenue per hour: rate(revenue_total[1h])
- Revenue by payment method
3. Inventory
- Items below reorder level
- Stock usage rate
# Average response time by endpoint
avg(rate(http_request_duration_seconds_sum[5m]) / rate(http_request_duration_seconds_count[5m])) by (endpoint)
# Orders created per minute
rate(orders_created_total[1m])
# Database connection pool utilization
db_pool_active / db_pool_max
# Error rate
rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m])
# Top 10 slowest endpoints
topk(10, rate(http_request_duration_seconds_sum[5m]) / rate(http_request_duration_seconds_count[5m]))
groups:
- name: application
rules:
- alert: HighErrorRate
expr: rate(http_requests_total{status=~"5.."}[5m]) > 0.05
for: 5m
annotations:
summary: "High error rate detected"
- alert: HighLatency
expr: histogram_quantile(0.95, http_request_duration_seconds) > 1
for: 10m
annotations:
summary: "P95 latency above 1 second"
- alert: LowInventory
expr: inventory_quantity < inventory_reorder_level
for: 1m
annotations:
summary: "Item below reorder level"Current: NestJS Logger (console output)
// Replaced console.log with Logger
import { Logger } from '@nestjs/common';
export class OrderService {
private readonly logger = new Logger(OrderService.name);
async createOrder(dto) {
this.logger.log(`Creating order for tenant: ${dto.tenant_id}`);
this.logger.debug(`Order details: ${JSON.stringify(dto)}`);
try {
// Business logic
} catch (error) {
this.logger.error(`Failed to create order: ${error.message}`, error.stack);
}
}
}Future: ELK Stack (Elasticsearch + Logstash + Kibana)
- Centralized log aggregation
- Full-text search
- Real-time analysis
- Long-term retention
Docker Compose
ββ PostgreSQL (localhost:5432)
ββ Redis (localhost:6379)
ββ Kafka (localhost:9092)
ββ API Gateway (localhost:3100)
ββ Services (localhost:3101-3108)
ββ Prometheus (localhost:9090)
ββ Grafana (localhost:3009)
Internet
β
Cloudflare Edge Network
β
Cloudflare Tunnel (Ingress)
β
Home Server Network
ββ Docker Compose Stack
ββ All services in Docker containers
ββ Shared PostgreSQL database
ββ Data volumes for persistence
ββ Reverse proxy (Nginx)
Domain: intellidine-api.aahil-khan.tech
β
API Gateway (internal)
β
Backend Services (internal)
services:
postgres: # Port 5443 (mapped from 5432)
redis: # Port 6380 (mapped from 6379)
kafka: # Port 9092
zookeeper: # Port 2181
prometheus: # Port 9090
grafana: # Port 3009
nginx: # Port 81 (reverse proxy)
api-gateway: # Port 3100
auth-service: # Port 3101
order-service: # Port 3102
menu-service: # Port 3103
inventory-service: # Port 3104
payment-service: # Port 3105
notification-service: # Port 3106
analytics-service: # Port 3107
discount-engine: # Port 3108
ml-service: # Port 8000Volume Persistence:
- postgres_data: Database files
- redis_data: Cache data
- prometheus_data: Metrics history
- grafana_data: Dashboards & config
Single entry point for all frontend requests with intelligent routing
1. Frontend makes request
GET https://intellidine-api.aahil-khan.tech/api/menu/items
Header: Authorization: Bearer <JWT>
2. API Gateway receives request
- Validates CORS origin
- Parses route: /api/menu/items
- Extracts path: /items
3. Route matching
/api/menu/* β menu-service:3103
4. Forward request
GET http://menu-service:3103/items
(Maintains headers, body, query params)
5. Service processes & responds
{ status: 200, data: [...] }
6. Gateway wraps response
{ success: true, data: [...], timestamp: "..." }
7. Send to frontend
Success:
{
"success": true,
"data": { /* service response */ },
"message": "Success",
"timestamp": "2025-10-22T10:30:00Z"
}Error:
{
"success": false,
"error": "InvalidCredentials",
"message": "Invalid phone or password",
"timestamp": "2025-10-22T10:30:00Z",
"status_code": 401
}Gateway Responsibilities:
- Catch service errors
- Map to standard HTTP status codes
- Wrap errors consistently
- Return meaningful messages
HTTP Status Codes:
- 200 OK - Success
- 201 Created - Resource created
- 400 Bad Request - Invalid input
- 401 Unauthorized - Missing/invalid auth
- 403 Forbidden - Insufficient permissions
- 404 Not Found - Resource not found
- 500 Internal Server Error - Server error
Aggregate Health:
GET /health
Response: {
status: "healthy",
services: {
"auth-service": "up",
"menu-service": "up",
"order-service": "up",
...
}
}
Individual Service Health:
GET /api/menu/health
Response: { status: 'ok', service: 'menu-service' }
-
Database:
- Indexes on frequently queried columns (tenant_id, user_id)
- Connection pooling (Prisma)
- Query optimization (N+1 prevention)
-
Caching:
- Redis for menu lists (TTL: 1 hour)
- Session caching (JWT validation)
- Redis for Kafka consumer groups
-
Asynchronous Processing:
- Kafka for non-critical operations
- Order creation doesn't wait for notifications
- Inventory updates async
-
Container Optimization:
- Alpine Linux (small image size)
- Multi-stage Docker builds
- Resource limits set
# Scale order-service to 3 instances
docker-compose up -d --scale order-service=3
# Load balancer (Nginx) distributes traffic
# Services share same PostgreSQL database# docker-compose.yml
order-service:
resources:
limits:
cpus: '2' # 2 CPU cores
memory: 2G # 2GB RAM
reservations:
cpus: '1'
memory: 1G-- Add indexes for common queries
CREATE INDEX idx_orders_created_at ON orders(created_at DESC);
CREATE INDEX idx_orders_tenant_id_status ON orders(tenant_id, status);
-- Partition large tables (future)
CREATE TABLE orders_2025_01 PARTITION OF orders
FOR VALUES FROM ('2025-01-01') TO ('2025-02-01');Current Bottlenecks:
- Shared PostgreSQL database - All services compete for connections
- Single Redis instance - Cache contention
- Synchronous API calls - Waiting for service responses
Future Solutions:
- Database replication & read replicas
- Redis Cluster for distributed caching
- API caching layer (Varnish/CDN)
- gRPC for inter-service communication
IntelliDine is a modern, scalable microservices architecture built with NestJS and PostgreSQL. Key characteristics:
- β Multi-tenant SaaS - Isolated data per restaurant
- β Event-driven - Decoupled services via Kafka
- β API-first - REST JSON API
- β Real-time - WebSocket notifications
- β Production-ready - Error handling, logging, monitoring
- β Scalable - Horizontal & vertical scaling options
- β Secure - JWT auth, role-based access, tenant isolation
For questions or to add additional services, refer to individual service READMEs in backend/*/ directories.