Technical Documentation v1.0

🍳 Sizzle

Architecture, Workflows, ER Diagrams & Complete Technical Reference for the Chef Booking Platform

1

Tech Stack

Every technology powering Sizzle, from frontend to deployment

FRONTEND

React SPA + PWA

Modern single-page app with progressive web app capabilities, server state caching, and smooth animations.

React 18 TypeScript 5 Vite 5 Tailwind CSS 3 Zustand React Query Framer Motion
MOBILE

Capacitor 6 (Android / iOS)

Native mobile app from the same React codebase. GPS geolocation, splash screen, status bar integration.

Capacitor 6 Geolocation Splash Screen Status Bar Android APK
BACKEND

FastAPI + Async Python

High-performance async API server with Pydantic validation, SQLAlchemy ORM, and automatic OpenAPI docs.

FastAPI Python 3.12 Uvicorn Pydantic v2 SQLAlchemy 2.0 AsyncPG
DATABASE

PostgreSQL 16 + Redis 7

Relational database for all entities. Redis for OTP storage, rate limiting, and session caching.

PostgreSQL 16 Redis 7 UUID PKs JSONB
AUTH & EMAIL

JWT + OTP (Passwordless)

Passwordless authentication via email OTP. Three-tier email delivery with automatic fallback.

JWT HS256 Email OTP Resend API Gmail SMTP RBAC
PAYMENTS & DEPLOY

PhonePe UPI + Cloud Run

Indian UPI payments via PhonePe gateway. Dockerized deployment on GCP Cloud Run with Nginx.

PhonePe UPI Docker Nginx GCP Cloud Run Supervisord
2

System Architecture

How all components connect — from user devices to databases and external services

🏗️

Full System Architecture

Client → Gateway → Backend → Data → External Services
graph TB
    subgraph Clients["📱 Client Layer"]
        direction LR
        WEB["🌐 Web Browser\n(React SPA / PWA)"]
        ANDROID["📱 Android App\n(Capacitor 6)"]
    end

    subgraph Gateway["🔀 Reverse Proxy"]
        NGINX["Nginx\nStatic Files · API Proxy\nGzip · Security Headers"]
    end

    subgraph Backend["⚙️ Application Server"]
        FASTAPI["FastAPI + Uvicorn\nASGI · Port 8000"]
        
        subgraph MW["Middleware Pipeline"]
            CORS["CORS\nOrigin Filter"]
            JWT_MW["JWT Auth\nToken Validation"]
            ROLE["Role Guard\n🧑Customer · 👨‍🍳Chef · 🛡️Admin"]
        end
        
        subgraph BL["Business Logic Services"]
            AUTH_S["🔐 Auth Service\nOTP · JWT · Email"]
            BOOK_S["📋 Booking Service\nPricing · CRUD"]
            PAY_S["💳 Payment Service\nPhonePe UPI"]
            NOTIF_S["🔔 Notification Service\nEmail · Push"]
        end
    end

    subgraph Data["💾 Data Layer"]
        PG[("🐘 PostgreSQL 16\n8 Tables · UUID PKs\nAsync via AsyncPG")]
        REDIS[("🔴 Redis 7\nOTP Store · Rate Limiter\n5 min TTL")]
    end

    subgraph External["🌍 External Services"]
        RESEND["📧 Resend API\n3K emails/mo free"]
        GMAIL["📧 Gmail SMTP\nFallback email"]
        PHONEPE["💳 PhonePe\nUPI Payments"]
        OSM["🗺️ OpenStreetMap\nMaps + Geocoding"]
    end

    WEB & ANDROID --> NGINX
    NGINX -->|"/api/v1/*"| FASTAPI
    NGINX -->|"/*"| WEB

    FASTAPI --> CORS --> JWT_MW --> ROLE
    ROLE --> AUTH_S & BOOK_S & PAY_S & NOTIF_S

    AUTH_S --> PG & REDIS & RESEND & GMAIL
    BOOK_S --> PG
    PAY_S --> PG & PHONEPE
    NOTIF_S --> RESEND
    WEB & ANDROID -.->|"Map tiles"| OSM

    style Clients fill:#FFF7ED,stroke:#EA580C,stroke-width:2px
    style Gateway fill:#EFF6FF,stroke:#2563EB,stroke-width:2px
    style Backend fill:#F0FDF4,stroke:#16A34A,stroke-width:2px
    style Data fill:#FEF3C7,stroke:#D97706,stroke-width:2px
    style External fill:#F5F3FF,stroke:#7C3AED,stroke-width:2px
            
3

Entity Relationship Diagram

Complete database schema — 8 tables, all fields, types, and relationships

🗄️

Database ER Diagram

PostgreSQL 16 — All tables, fields, and foreign key relationships
erDiagram
    USERS {
        uuid id PK
        string name "nullable"
        string email UK "indexed"
        string phone UK "indexed"
        enum role "customer | chef | admin"
        date dob "nullable"
        boolean is_active "default true"
        string avatar_url "nullable"
        timestamp created_at
        timestamp updated_at
    }

    CHEF_PROFILES {
        uuid id PK
        uuid user_id FK, UK "unique → users"
        text bio "nullable"
        array specialties "string[]"
        int experience_years "default 0"
        float rating "nullable"
        int total_bookings "default 0"
        float hourly_rate "default 399.0 INR"
        boolean is_available "default true"
        boolean is_verified "default false"
        string service_city "nullable"
        timestamp created_at
        timestamp updated_at
    }

    CHEF_AVAILABILITY {
        uuid id PK
        uuid chef_profile_id FK "→ chef_profiles"
        enum day_of_week "mon-sun"
        time start_time "HH:MM"
        time end_time "HH:MM"
        boolean is_available "default true"
    }

    ADDRESSES {
        uuid id PK
        uuid user_id FK "→ users, indexed"
        string label "Home | Office | Other"
        text full_address "required"
        string city "required"
        string state "nullable"
        string pincode "required"
        float latitude "GPS"
        float longitude "GPS"
        boolean is_default "default false"
        timestamp created_at
    }

    BOOKINGS {
        uuid id PK
        uuid customer_id FK "→ users, indexed"
        uuid chef_id FK "→ users, nullable"
        uuid address_id FK "→ addresses"
        date booking_date "required"
        time time_slot "HH:MM"
        int duration_hours "1-8, default 2"
        int guest_count "1-20, default 2"
        text special_requests "nullable"
        decimal total_amount "10,2 INR"
        enum status "pending|confirmed|in_progress|completed|cancelled"
        text cancellation_reason "nullable"
        string booking_ref UK "SZ-XXXXXXXX"
        timestamp created_at
        timestamp updated_at
    }

    PAYMENTS {
        uuid id PK
        uuid booking_id FK, UK "→ bookings"
        decimal amount "10,2 INR"
        enum status "pending|success|failed|refunded"
        string transaction_id UK "PhonePe TXN"
        string merchant_transaction_id UK "SZ_uuid"
        string payment_method "UPI"
        jsonb gateway_response "raw PhonePe"
        timestamp created_at
        timestamp updated_at
    }

    LOCATIONS {
        uuid id PK
        string city "indexed"
        string state "required"
        string pincode "nullable"
        boolean is_serviceable "default true"
        timestamp created_at
    }

    SERVICE_AREAS {
        uuid id PK
        uuid location_id FK "→ locations, CASCADE"
        string name "area name"
        string city "indexed"
        float latitude "center"
        float longitude "center"
        float radius_km "default 10.0"
        boolean is_active "default true"
        timestamp created_at
    }

    USERS ||--o| CHEF_PROFILES : "has profile (if chef)"
    USERS ||--o{ ADDRESSES : "has many"
    USERS ||--o{ BOOKINGS : "creates (as customer)"
    USERS ||--o{ BOOKINGS : "fulfills (as chef)"
    CHEF_PROFILES ||--o{ CHEF_AVAILABILITY : "has weekly slots"
    BOOKINGS ||--o| PAYMENTS : "has payment"
    BOOKINGS }o--|| ADDRESSES : "service location"
    LOCATIONS ||--o{ SERVICE_AREAS : "has areas"
            
4

User Roles & Workflows

Three distinct user journeys — Customer, Chef, and Admin

🧑

Customer Journey

From opening the app to tracking a booking
flowchart LR
    A["📱 Open App"] --> B["✉️ Login\n(Email OTP)"]
    B --> C{"🆕 New\nUser?"}
    C -->|Yes| D["📝 Onboarding\n(Name · Phone)"]
    C -->|No| E["🏠 Dashboard"]
    D --> E
    E --> F["📍 Select or\nAdd Address"]
    F --> G["📅 Pick Date\n& Time Slot"]
    G --> H["⏱️ Set Duration\n& Guest Count"]
    H --> I["📋 Review\nPrice Breakdown"]
    I --> J["💳 Pay via\nPhonePe UPI"]
    J --> K["✅ Booking\nConfirmed!"]
    K --> L["🔔 Track\nLive Status"]

    style A fill:#FFF7ED,stroke:#EA580C,stroke-width:2px
    style E fill:#DBEAFE,stroke:#2563EB,stroke-width:2px
    style K fill:#DCFCE7,stroke:#16A34A,stroke-width:2px
    style J fill:#F5F3FF,stroke:#7C3AED,stroke-width:2px
            
👨‍🍳

Chef Journey

From profile setup to completing a booking
flowchart LR
    A["🔑 Login"] --> B["📝 Profile Setup\nBio · Specialties · Rate"]
    B --> C["📅 Set Weekly\nAvailability"]
    C --> D["📥 Receive\nBooking"]
    D --> E{"✅ Accept?"}
    E -->|Yes| F["👍 Confirm\nBooking"]
    E -->|No| G["❌ Decline"]
    F --> H["🍳 Start\nCooking"]
    H --> I["✅ Mark\nCompleted"]
    I --> J["💰 Earnings\nUpdated"]

    style D fill:#FEF3C7,stroke:#D97706,stroke-width:2px
    style I fill:#DCFCE7,stroke:#16A34A,stroke-width:2px
    style J fill:#DCFCE7,stroke:#16A34A,stroke-width:2px
            
🛡️

Admin Workflow

Platform management and oversight
flowchart TB
    A["🛡️ Admin Dashboard"] --> B["📊 View Stats\nUsers · Revenue · Bookings"]
    A --> C["👨‍🍳 Manage Chefs"]
    A --> D["📋 Manage Bookings"]
    A --> E["📍 Manage Locations"]

    C --> C1["➕ Register New Chef"]
    C --> C2["✅ Verify Chef"]
    C --> C3["📅 Set Chef Availability"]
    C --> C4["✏️ Edit Chef Profile"]

    D --> D1["👁️ View All Bookings"]
    D --> D2["👨‍🍳 Assign Chef"]
    D --> D3["🔄 Update Status"]

    E --> E1["🏙️ Add City"]
    E --> E2["📍 Add Service Area"]
    E --> E3["🟢 Toggle Serviceability"]

    style A fill:#DCFCE7,stroke:#16A34A,stroke-width:2px
            
5

Authentication Flow

Passwordless OTP authentication with JWT tokens and auto-refresh

🔐

OTP Login Sequence

Email → OTP → JWT → Role-based redirect
sequenceDiagram
    autonumber
    participant U as 📱 User
    participant F as 🌐 Frontend
    participant B as ⚙️ Backend
    participant R as 🔴 Redis
    participant E as 📧 Email Service

    U->>F: Enter email address
    F->>B: POST /auth/send-otp {email}
    B->>R: Check rate limit (max 5/5min)
    R-->>B: ✅ Under limit
    B->>B: Generate 6-digit OTP
    B->>R: Store OTP (TTL: 5 min)

    alt 🟢 Resend API available
        B->>E: Send via Resend API
    else 🟡 SMTP fallback
        B->>E: Send via Gmail SMTP
    else 🔵 Dev mode
        B->>B: Log OTP to console
    end

    E-->>U: 📩 Branded HTML email with OTP
    B-->>F: {message: "OTP sent"}

    U->>F: Enter 6-digit OTP
    F->>B: POST /auth/verify-otp {email, otp}
    B->>R: Verify OTP & delete
    R-->>B: ✅ Match

    B->>B: Get or create user
    B->>B: Generate access + refresh JWT

    B-->>F: {access_token, refresh_token, role, is_new_user}
    F->>F: Save tokens → localStorage

    alt 🆕 New user
        F->>U: Redirect → /onboarding
    else 🧑 Customer
        F->>U: Redirect → /customer/dashboard
    else 👨‍🍳 Chef
        F->>U: Redirect → /chef/profile
    else 🛡️ Admin
        F->>U: Redirect → /admin/dashboard
    end
            
🔄

Token Refresh Flow

Auto-refresh on 401 with retry mechanism
sequenceDiagram
    autonumber
    participant F as 🌐 Frontend (Axios)
    participant B as ⚙️ Backend

    F->>B: API request (expired access_token)
    B-->>F: 401 Unauthorized

    F->>F: Get refresh_token from localStorage
    F->>B: POST /auth/refresh {refresh_token}

    alt ✅ Valid refresh token
        B-->>F: {new access_token, new refresh_token}
        F->>F: Update both tokens in localStorage
        F->>B: 🔄 Retry original request (new token)
        B-->>F: ✅ Success response
    else ❌ Invalid/expired refresh token
        B-->>F: 401 Invalid token
        F->>F: Clear all tokens
        F->>F: Redirect → /login
    end
            
6

Booking Flow

State machine and end-to-end booking creation sequence

📋

Booking State Machine

All possible booking status transitions
stateDiagram-v2
    [*] --> PENDING: Customer creates booking

    PENDING --> CONFIRMED: Chef/Admin confirms
    PENDING --> CANCELLED: Customer cancels

    CONFIRMED --> IN_PROGRESS: Chef starts cooking
    CONFIRMED --> CANCELLED: Either party cancels

    IN_PROGRESS --> COMPLETED: Chef finishes service

    COMPLETED --> [*]
    CANCELLED --> [*]

    note right of PENDING
        🏷️ Ref: SZ-XXXXXXXX
        💳 Payment initiated
        ⏳ Awaiting chef
    end note

    note right of CONFIRMED
        👨‍🍳 Chef assigned
        💰 Payment successful
        📱 Notifications sent
    end note

    note right of IN_PROGRESS
        🍳 Chef on-site
        🕐 Timer running
        📍 At customer address
    end note

    note right of COMPLETED
        ✅ Service delivered
        ⭐ Rating eligible
        💰 Chef paid
    end note

    note right of CANCELLED
        📝 Reason recorded
        💸 Refund eligible
    end note
            
🔄

Booking Creation Sequence

Step-by-step from address selection to confirmation
sequenceDiagram
    autonumber
    participant C as 👤 Customer
    participant F as 🌐 Frontend
    participant B as ⚙️ Backend
    participant DB as 🐘 PostgreSQL

    C->>F: Tap address from saved list
    F->>F: Auto-advance → datetime step
    C->>F: Pick date + time slot (e.g. 19:00)
    F->>F: Advance → duration step
    C->>F: Set duration (3 hrs) + guests (8)
    F->>F: Calculate price breakdown (client-side mirror)

    Note over F: Base: ₹399×3 = ₹1,197
    Note over F: Surcharge: (8-4)×₹49×3 = ₹588
    Note over F: Peak 20%: ₹2,142
    Note over F: Platform 5%: ₹107.10
    Note over F: GST 5%: ₹112.46
    Note over F: Total: ₹2,361.56

    C->>F: Review & Confirm
    F->>B: POST /customer/bookings
    B->>DB: Fetch chef hourly_rate (₹399)
    B->>B: Server-side price calculation
    B->>B: Generate ref: SZ-A1B2C3D4
    B->>DB: INSERT INTO bookings
    DB-->>B: Booking created
    B-->>F: {id, ref: "SZ-A1B2C3D4", total: 2361.56, status: "pending"}
    F-->>C: ✅ "Booking Created!" with breakdown
            
7

Pricing Engine

Smart Indian market pricing — fair for customers, profitable for chefs

💰

Price Calculation Flow

₹399/hr base → Guest surcharge → Peak premium → Fees → Total
flowchart TD
    START(["📋 Booking Request\nrate · hours · guests · time"]):::start --> BASE["💵 Base Cost\nchef_rate × duration_hours\n(default ₹399/hr)"]

    BASE --> GUEST_CHECK{"👥 Guests > 4?"}
    GUEST_CHECK -->|"Yes"| SURCHARGE["💵 Guest Surcharge\n(guests - 4) × ₹49 × hours"]
    GUEST_CHECK -->|"No (≤ 4)"| NO_SURCHARGE["✅ No surcharge\n₹0"]

    SURCHARGE --> PEAK_CHECK
    NO_SURCHARGE --> PEAK_CHECK

    PEAK_CHECK{"🌙 Time between\n18:00 - 21:00?"}
    PEAK_CHECK -->|"Yes (Dinner)"| PEAK["🔥 Peak Premium\nsubtotal × 1.20\n(+20%)"]
    PEAK_CHECK -->|"No"| NO_PEAK["✅ No premium\nsubtotal × 1.00"]

    PEAK --> PLATFORM
    NO_PEAK --> PLATFORM

    PLATFORM["🏢 Platform Fee\n5% of subtotal"]
    PLATFORM --> GST["🏛️ GST\n5% of (subtotal + platform_fee)"]
    GST --> TOTAL(["💰 TOTAL\nsubtotal + platform_fee + GST\n(rounded to ₹X.XX)"]):::total

    classDef start fill:#FFF7ED,stroke:#EA580C,stroke-width:2px
    classDef total fill:#DCFCE7,stroke:#16A34A,stroke-width:3px
            
Scenario Rate/hr Hours Guests Time Base Surcharge Peak Platform GST Total
Basic lunch ₹399 2 4 12:00 ₹798 ₹0 ₹798 ₹39.90 ₹41.90 ₹879.80
Dinner party ₹399 3 8 19:00 ₹1,197 ₹588 ₹2,142 ₹107.10 ₹112.46 ₹2,361.56
Small dinner ₹399 2 2 20:00 ₹798 ₹0 ₹957.60 ₹47.88 ₹50.27 ₹1,055.75
Big gathering ₹599 4 15 13:00 ₹2,396 ₹2,156 ₹4,552 ₹227.60 ₹238.98 ₹5,018.58
8

Payment Flow

PhonePe UPI integration — initiation, redirect, webhook, and verification

💳

PhonePe UPI Payment Sequence

Customer → Backend → PhonePe → Webhook → Status
sequenceDiagram
    autonumber
    participant C as 👤 Customer
    participant F as 🌐 Frontend
    participant B as ⚙️ Backend
    participant PP as 💳 PhonePe
    participant DB as 🐘 PostgreSQL

    C->>F: Tap "Pay Now"
    F->>B: POST /payments/initiate {booking_id}
    B->>DB: Get booking (amount, ref)
    B->>B: Generate merchant_txn_id (SZ_uuid)
    B->>B: Create base64 payload
    B->>B: Calculate X-VERIFY checksum (SHA256 + salt)
    B->>PP: POST /pg/v1/pay (payload, X-VERIFY)
    PP-->>B: {success: true, payment_url}
    B->>DB: INSERT payment (status: pending)
    B-->>F: {payment_url, merchant_txn_id}

    F->>C: 🔗 Redirect to PhonePe
    C->>PP: Complete UPI payment (PIN)
    PP-->>C: Payment result page

    par Webhook (server-to-server)
        PP->>B: POST /payments/callback (signed)
        B->>B: Verify X-VERIFY checksum
        B->>DB: UPDATE payment status → success
        B->>DB: UPDATE booking status → confirmed
    and Redirect (user-facing)
        PP->>F: Redirect → /booking/status?ref=SZ-XXX
        F->>B: GET /payments/status/{txn_id}
        B-->>F: {status: "success", amount: 2361.56}
        F-->>C: ✅ "Payment Successful!"
    end
            
9

API Architecture

28 RESTful endpoints organized by role and domain

🔗

API Endpoint Map

All 28 endpoints grouped by authentication requirement
graph LR
    API["🔗 /api/v1"] --> AUTH["🔓 /auth\n(Public)"]
    API --> CUST["🧑 /customer\n(JWT + Customer)"]
    API --> CHEF["👨‍🍳 /chef\n(JWT + Chef)"]
    API --> ADMIN["🛡️ /admin\n(JWT + Admin)"]
    API --> PAY["💳 /payments\n(JWT + Webhook)"]

    AUTH --> A1["POST send-otp"]
    AUTH --> A2["POST verify-otp"]
    AUTH --> A3["POST refresh"]

    CUST --> C1["GET|PUT profile"]
    CUST --> C2["CRUD addresses (4)"]
    CUST --> C3["POST check-serviceability"]
    CUST --> C4["POST|GET bookings (3)"]

    CHEF --> CH1["GET|PUT profile"]
    CHEF --> CH2["POST|DEL availability"]
    CHEF --> CH3["GET bookings + PUT status"]

    ADMIN --> AD1["GET stats"]
    ADMIN --> AD2["CRUD chefs (6)"]
    ADMIN --> AD3["GET|PUT bookings"]
    ADMIN --> AD4["CRUD locations (4)"]
    ADMIN --> AD5["POST|DEL service-areas"]

    PAY --> P1["POST initiate"]
    PAY --> P2["POST callback"]
    PAY --> P3["GET status"]

    style AUTH fill:#DCFCE7,stroke:#16A34A,stroke-width:2px
    style CUST fill:#DBEAFE,stroke:#2563EB,stroke-width:2px
    style CHEF fill:#FEF3C7,stroke:#D97706,stroke-width:2px
    style ADMIN fill:#DCFCE7,stroke:#16A34A,stroke-width:2px
    style PAY fill:#F5F3FF,stroke:#7C3AED,stroke-width:2px
            
10

Frontend Architecture

React component tree, state management, and routing

🌐

Frontend Component Architecture

React 18 + Zustand + React Query + Capacitor
graph TB
    subgraph App["📱 React Application"]
        ROUTER["🔀 React Router v6\nRole-Based Routing"]
        
        subgraph AuthPages["🔑 Auth Pages"]
            LOGIN["LoginPage\nEmail → OTP → JWT"]
            ONBOARD["OnboardingPage\nName · Phone · Role"]
        end
        
        subgraph CustPages["🧑 Customer Pages"]
            CDASH["DashboardPage\nOverview · Quick Book"]
            CBOOK["BookingsListPage\nAll Bookings"]
            CNEW["NewBookingPage\n5-Step Wizard"]
            CDET["BookingDetailPage\nView · Cancel · Pay"]
            CPROF["ProfilePage\nEdit · Addresses"]
        end
        
        subgraph ChefPages["👨‍🍳 Chef Pages"]
            CHPROF["ChefProfilePage\nBio · Rate · Slots"]
            CHBOOK["ChefBookingsPage\nManage · Status"]
        end
        
        subgraph AdminPages["🛡️ Admin Pages"]
            ADASH["AdminDashboardPage\nStats · Analytics"]
            ACHEF["AdminChefsPage\nCRUD · Verify"]
            ABOOK["AdminBookingsPage\nAll · Assign"]
            ALOC["AdminLocationsPage\nCities · Areas"]
        end
    end

    subgraph State["📦 State Layer"]
        ZUSTAND["🐻 Zustand Store\nauth · user · tokens\nlocalStorage persist"]
        RQ["🔄 React Query\nServer state · Auto-refetch\nCaching · Mutations"]
    end
    
    subgraph UILib["🎨 UI Layer"]
        TW["Tailwind CSS 3.4"]
        FM["Framer Motion 11"]
        TOAST["React Hot Toast"]
        LEAFLET["React Leaflet"]
        ICONS["React Icons"]
    end

    subgraph APILayer["🌐 API Layer"]
        AXIOS["Axios Instance\nBase URL · Bearer Auth\n401 Auto-Refresh"]
    end

    subgraph Mobile["📱 Capacitor 6"]
        GEO["GPS Geolocation"]
        SPLASH["Splash Screen"]
        SBAR["Status Bar"]
    end

    ROUTER --> AuthPages & CustPages & ChefPages & AdminPages
    CustPages & ChefPages & AdminPages --> State
    State --> APILayer
    CustPages & ChefPages & AdminPages --> UILib
    App --> Mobile

    style App fill:#FFF7ED,stroke:#EA580C,stroke-width:2px
    style State fill:#DBEAFE,stroke:#2563EB
    style UILib fill:#FEF3C7,stroke:#D97706
    style APILayer fill:#DCFCE7,stroke:#16A34A
    style Mobile fill:#F5F3FF,stroke:#7C3AED
            
🗺️

Route Map

All frontend routes organized by role
flowchart TD
    ROOT["/ (Root)"] --> LOGIN["/login"]
    ROOT --> ONBOARD["/onboarding"]
    
    ROOT --> CUST["/customer"]
    CUST --> CDASH["/customer/dashboard\n🏠 Home Overview"]
    CUST --> CBOOK["/customer/bookings\n📋 Booking History"]
    CUST --> CNEW["/customer/bookings/new\n✨ Create Booking"]
    CUST --> CDET["/customer/bookings/:id\n👁️ Booking Details"]
    CUST --> CPROF["/customer/profile\n⚙️ Settings"]
    
    ROOT --> CHEF["/chef"]
    CHEF --> CHPROF["/chef/profile\n📝 Edit Profile"]
    CHEF --> CHBOOK["/chef/bookings\n📋 My Bookings"]
    
    ROOT --> ADMIN["/admin"]
    ADMIN --> ADASH["/admin/dashboard\n📊 Analytics"]
    ADMIN --> ACHEF["/admin/chefs\n👨‍🍳 Chef Mgmt"]
    ADMIN --> ABOOK["/admin/bookings\n📋 All Bookings"]
    ADMIN --> ALOC["/admin/locations\n📍 Locations"]

    style ROOT fill:#0F172A,color:#FFF
    style LOGIN fill:#FFF7ED,stroke:#EA580C
    style CUST fill:#DBEAFE,stroke:#2563EB,stroke-width:2px
    style CHEF fill:#FEF3C7,stroke:#D97706,stroke-width:2px
    style ADMIN fill:#DCFCE7,stroke:#16A34A,stroke-width:2px
            
11

Deployment Architecture

Three deployment modes — local dev, Docker production, and GCP Cloud Run

🖥️

Local Development

Hot-reload frontend + backend with Docker databases
graph LR
    subgraph Local["🖥️ Local Machine"]
        VITE["⚡ Vite Dev Server\nlocalhost:5173\nHot Module Reload"]
        UVICORN["🐍 Uvicorn\nlocalhost:8000\n--reload mode"]
        subgraph Docker["🐳 Docker Compose"]
            PG["🐘 PostgreSQL 16\nlocalhost:5432"]
            RD["🔴 Redis 7\nlocalhost:6379"]
        end
    end

    VITE -->|"VITE_API_URL"| UVICORN
    UVICORN --> PG & RD

    style Local fill:#F0FDF4,stroke:#16A34A,stroke-width:2px
    style Docker fill:#DBEAFE,stroke:#2563EB
            
🐳

Docker Compose Production

Self-hosted with Nginx reverse proxy
graph TB
    INTERNET["🌐 Internet\nUsers"] --> NGINX

    subgraph DockerProd["🐳 Docker Compose Production"]
        NGINX["📦 Nginx Container\nPort 80 / 443\nStatic + Reverse Proxy"]
        BACKEND["📦 Backend Container\nFastAPI + Uvicorn\nPort 8000"]
        PG["📦 PostgreSQL 16\nPort 5432\nPersistent Volume"]
        REDIS["📦 Redis 7\nPort 6379\nLRU · 256MB"]
    end

    NGINX -->|"/ → static files"| NGINX
    NGINX -->|"/api/* → proxy"| BACKEND
    BACKEND --> PG & REDIS

    style DockerProd fill:#FFF7ED,stroke:#EA580C,stroke-width:2px
            
☁️

GCP Cloud Run (Serverless)

Auto-scaling container with managed databases
graph TB
    USERS["👥 Users\n(Web + Android)"] --> CR

    subgraph GCP["☁️ Google Cloud Platform"]
        CR["🚀 Cloud Run\nasia-south1 (Mumbai)\nAuto-scale 0→3\nPort 8080"]

        subgraph Container["📦 Single Container"]
            SUP["🔧 Supervisord\nProcess Manager"]
            NGX["🌐 Nginx\nStatic + Proxy\nPort 8080"]
            UVI["🐍 Uvicorn\nFastAPI Backend\nPort 8000"]
        end
    end

    subgraph Free["🆓 Free Tier Services"]
        NEON["🐘 Neon.tech\nPostgreSQL\n0.5 GB free"]
        UPSTASH["🔴 Upstash\nRedis\n10K cmd/day free"]
    end

    CR --> Container
    SUP --> NGX & UVI
    NGX -->|"/api/*"| UVI
    UVI --> NEON & UPSTASH

    style GCP fill:#DBEAFE,stroke:#2563EB,stroke-width:2px
    style Container fill:#EFF6FF,stroke:#93C5FD
    style Free fill:#DCFCE7,stroke:#16A34A,stroke-width:2px
            
12

API Reference

Complete endpoint reference — 28 endpoints across 5 routers

Authentication — /api/v1/auth (Public)

MethodEndpointDescriptionBody
POST/auth/send-otpSend OTP to email or phone{email} or {phone}
POST/auth/verify-otpVerify OTP, return JWT tokens{email, otp}
POST/auth/refreshRefresh access token{refresh_token}

Customer — /api/v1/customer (JWT + Customer role)

MethodEndpointDescription
GET/customer/profileGet customer profile
PUT/customer/profileUpdate customer profile
GET/customer/addressesList all saved addresses
POST/customer/addressesAdd a new address
PUT/customer/addresses/:idUpdate existing address
DEL/customer/addresses/:idDelete an address
POST/customer/check-serviceabilityCheck if city is serviceable
POST/customer/bookingsCreate a new booking
GET/customer/bookingsList customer bookings (paginated)
GET/customer/bookings/:idGet booking details

Chef — /api/v1/chef (JWT + Chef role)

MethodEndpointDescription
GET/chef/profileGet chef profile with availability slots
PUT/chef/profileUpdate chef profile
POST/chef/availabilityAdd availability slot
DEL/chef/availability/:idRemove availability slot
GET/chef/bookingsList chef's bookings
GET/chef/bookings/:idGet booking details
PUT/chef/bookings/:id/statusUpdate booking status

Admin — /api/v1/admin (JWT + Admin role)

MethodEndpointDescription
GET/admin/statsDashboard statistics (users, revenue, bookings)
GET/admin/chefsList all chefs with profiles
POST/admin/chefsRegister a new chef
GET/admin/chefs/:idGet chef details
PUT/admin/chefs/:idUpdate chef profile
DEL/admin/chefs/:idDeactivate chef
POST/admin/chefs/:id/availabilityBulk set chef availability
GET/admin/bookingsList all bookings (filterable)
PUT/admin/bookings/:idUpdate/assign booking
GET/admin/locationsList all locations
POST/admin/locationsAdd location/city
PUT/admin/locations/:idUpdate location
DEL/admin/locations/:idDelete location
POST/admin/locations/:id/areasAdd service area
DEL/admin/service-areas/:idDelete service area

Payments — /api/v1/payments (JWT + Webhook)

MethodEndpointDescription
POST/payments/initiateInitiate PhonePe UPI payment
POST/payments/callbackPhonePe webhook callback
GET/payments/status/:txn_idCheck payment status
13

Security Architecture

Multi-layer security from client to database

🔒

Security Layers

Defense in depth — every layer has protection
graph TB
    subgraph Client["🌐 Client Security"]
        TOKEN["🔑 JWT stored in localStorage\nAccess (7d) + Refresh (30d)"]
        HTTPS["🔒 HTTPS only\n(in production)"]
    end

    subgraph Network["🌐 Network Security"]
        CORS_S["🚫 CORS\nRestricted origins only"]
        HEADERS["🛡️ Security Headers\nX-Frame-Options · CSP\nX-Content-Type"]
        GZIP["📦 Gzip compression"]
    end

    subgraph Auth["🔐 Authentication"]
        OTP_S["📧 Email OTP\n6-digit · 5 min expiry"]
        RATE["⏱️ Rate Limiting\nMax 5 OTPs / 5 min (Redis)"]
        JWT_S["🎫 JWT HS256\nRole-based claims\nExpiry validation"]
    end

    subgraph Access["🛡️ Authorization"]
        RBAC_S["👥 Role-Based Access\nCustomer · Chef · Admin\nMiddleware guards"]
        OWNER["🔒 Ownership Check\nUsers access own data only"]
    end

    subgraph Data_S["💾 Data Security"]
        ORM["🐍 SQLAlchemy ORM\nParameterized queries\nNo raw SQL"]
        VALID["✅ Pydantic Validation\nInput sanitization\nType enforcement"]
        UUID_S["🔑 UUID Primary Keys\nNon-sequential · Unpredictable"]
    end

    Client --> Network --> Auth --> Access --> Data_S

    style Client fill:#FEE2E2,stroke:#DC2626
    style Network fill:#FEF3C7,stroke:#D97706
    style Auth fill:#F5F3FF,stroke:#7C3AED
    style Access fill:#DBEAFE,stroke:#2563EB
    style Data_S fill:#DCFCE7,stroke:#16A34A
            
🔐 Authentication

Passwordless email OTP, 6-digit, 5 min expiry, rate-limited to 5 attempts per 5 minutes via Redis

🎫 JWT Tokens

HS256 signing, access token (7 days), refresh token (30 days), role claim in payload

🛡️ RBAC

Three roles: customer, chef, admin. Middleware guards on every protected route

🔒 SQL Injection

SQLAlchemy ORM with parameterized queries — no raw SQL anywhere in the codebase

✅ Input Validation

Pydantic v2 schemas validate all request bodies with type enforcement and constraints

🌐 CORS

Configured allowed origins, only permitted frontend domains can make API requests

14

Project Structure

Complete directory layout of the Sizzle monorepo

sizzle/ ├── backend/ │ ├── app/ │ │ ├── main.py # FastAPI app + CORS + router mounts │ │ ├── config.py # Pydantic Settings (env vars) │ │ ├── database.py # Async SQLAlchemy engine + session │ │ ├── redis.py # Redis connection pool │ │ │ │ │ ├── models/ # SQLAlchemy ORM Models │ │ │ ├── user.py # User (customer/chef/admin) │ │ │ ├── chef_profile.py # ChefProfile + ChefAvailability │ │ │ ├── booking.py # Booking (status machine) │ │ │ ├── payment.py # Payment (PhonePe UPI) │ │ │ ├── address.py # Address (GPS coords) │ │ │ └── location.py # Location + ServiceArea │ │ │ │ │ ├── schemas/ # Pydantic DTOs │ │ │ └── user.py # All request/response schemas │ │ │ │ │ ├── routers/ # API Route Handlers (28 endpoints) │ │ │ ├── auth.py # /auth — OTP, JWT, refresh │ │ │ ├── customer.py # /customer — profile, address, booking │ │ │ ├── chef.py # /chef — profile, availability, booking │ │ │ ├── admin.py # /admin — stats, CRUD everything │ │ │ └── payments.py # /payments — PhonePe UPI │ │ │ │ │ ├── services/ # Business Logic Layer │ │ │ ├── auth_service.py # OTP + JWT + Email (3-tier) │ │ │ ├── booking_service.py# Smart pricing + CRUD │ │ │ ├── payment_service.py# PhonePe integration │ │ │ └── notification_service.py │ │ │ │ │ └── middleware/ │ │ └── auth.py # JWT validation + role guards │ │ │ ├── requirements.txt # Python dependencies │ ├── Dockerfile # Backend container │ └── .env # Secrets (gitignored) │ ├── frontend/ │ ├── src/ │ │ ├── App.tsx # Router + role-based routing │ │ ├── main.tsx # React entry point │ │ │ │ │ ├── pages/ │ │ │ ├── auth/ # LoginPage · OnboardingPage │ │ │ ├── customer/ # Dashboard · Bookings · New · Profile │ │ │ ├── chef/ # ChefProfile · ChefBookings │ │ │ └── admin/ # Dashboard · Chefs · Bookings · Locations │ │ │ │ │ ├── components/ │ │ │ ├── layout/ # AppLayout · BottomNav · Sidebar │ │ │ └── ui/ # Button · Card · Input · Modal │ │ │ │ │ ├── store/ # Zustand state management │ │ │ └── authStore.ts # Auth + user + token persistence │ │ │ │ │ ├── lib/ │ │ │ ├── api.ts # Axios + interceptors + auto-refresh │ │ │ └── utils.ts # Helpers (format, date, etc.) │ │ │ │ │ ├── config/ │ │ │ └── index.ts # App config · time slots · colors │ │ │ │ │ └── types/ │ │ └── index.ts # TypeScript interfaces + enums │ │ │ ├── android/ # Capacitor Android project │ ├── capacitor.config.ts # Mobile app config │ ├── vite.config.ts # Build tool config + PWA │ ├── tailwind.config.js # Design tokens + Sizzle theme │ └── package.json # Frontend dependencies │ ├── deploy/ │ ├── nginx-cloudrun.conf # Nginx config (Cloud Run) │ ├── supervisord.conf # Process manager config │ └── deploy-gcp.sh # GCP deployment script │ ├── Dockerfile.cloudrun # Multi-stage Cloud Run build ├── docker-compose.yml # Local dev (DB + Redis) ├── docker-compose.prod.yml # Production compose └── ARCHITECTURE.md # This documentation