openapi: 3.0.3
info:
  title: Railbites API
  description: |
    Railbites is a food ordering and restaurant management platform for Indian Railways.
    It handles email-based order ingestion from IRCTC and aggregator platforms, delivery
    management, multi-restaurant operations, and analytics.

    ## Role-Based Access Control (RBAC)

    ### Railbites Roles:
    - **super_admin**: Full platform access — all restaurants, chains, orders, reports, and user management
    - **admin**: Scoped to their own restaurant — orders, delivery boys, chains, and reports for that restaurant
    - **user**: Scoped to their assigned chain — can view and manage orders for their chain only

    ### Key Features:
    - JWT-based authentication (7-day tokens)
    - Restaurant & chain scoped data isolation
    - Email order parsing from IRCTC, RailRestro, RailFeast, Dibrail, OLF, YatriRestro
    - Gmail OAuth2 integration with auto-polling (SSE real-time notifications)
    - Aggregator tracking per order
    - Delivery boy assignment and performance tracking
    - COD / Prepaid payment management
    - Overview analytics reports
    - Password reset flow (token-based)

    ### Aggregators (email ordering platforms):
    | Name | Domain |
    |------|--------|
    | irctc | irctc.co.in |
    | railrestro | railrestro.com |
    | railfeast | railfeast.in / railfeast.com |
    | dibrail | dibrail.com |
    | olf | olf.in |
    | yatrirestro | yatrirestro.com |

  version: 1.0.0
  contact:
    name: Railbites Support
    email: support@railbites.in
  license:
    name: MIT
    url: https://opensource.org/licenses/MIT

servers:
  - url: http://localhost:5000/api
    description: Development server
  - url: https://api.railway.gov.in/api
    description: Production server

tags:
  - name: RestaurantAuth
    description: Railbites authentication — login, profile, user management
  - name: Restaurants
    description: Restaurant registration and management (super_admin)
  - name: Chains
    description: Chain / outlet management within a restaurant
  - name: EmailConfig
    description: Email integration configuration per restaurant (super_admin only)
  - name: Orders
    description: Food order management (Railbites)
  - name: Email
    description: IRCTC email fetching and order parsing (Railbites)
  - name: DeliveryBoys
    description: Delivery personnel management (Railbites)
  - name: RestaurantReports
    description: Order analytics and monthly reports (Railbites)

security:
  - bearerAuth: []

paths:
  # ================================================================
  # Railbites – Orders
  # ================================================================
  /orders:
    get:
      tags: [Orders]
      summary: List orders
      description: Retrieve all orders with optional filters and pagination.
      security:
        - bearerAuth: []
      parameters:
        - in: query
          name: status
          schema:
            type: string
            enum: [new, pending, accepted, delivered, undelivered, cancelled, rescheduled]
        - in: query
          name: paymentType
          schema:
            type: string
            enum: [prepaid, cod]
        - in: query
          name: trainNumber
          schema:
            type: string
        - in: query
          name: assignedDeliveryBoyId
          schema:
            type: string
        - in: query
          name: dateFrom
          schema:
            type: string
            format: date-time
        - in: query
          name: dateTo
          schema:
            type: string
            format: date-time
        - in: query
          name: acknowledged
          schema:
            type: boolean
        - in: query
          name: page
          schema:
            type: integer
            default: 1
        - in: query
          name: limit
          schema:
            type: integer
            default: 20
        - in: query
          name: sortBy
          schema:
            type: string
            default: createdAt
        - in: query
          name: order
          schema:
            type: string
            enum: [asc, desc]
        - in: query
          name: restaurantId
          description: Filter by restaurant (super_admin only)
          schema:
            type: string
            example: rest_hwh_a1b2c3
        - in: query
          name: chainId
          description: Filter by chain (super_admin only)
          schema:
            type: string
            example: chain_hwh_p1_9a0b1c
            default: desc
      responses:
        '200':
          description: Order list with pagination and counts
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object
                    properties:
                      orders:
                        type: array
                        items:
                          $ref: '#/components/schemas/Order'
                      pagination:
                        $ref: '#/components/schemas/Pagination'
                      counts:
                        $ref: '#/components/schemas/OrderCounts'
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      tags: [Orders]
      summary: Create a manual order
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateOrderRequest'
      responses:
        '201':
          description: Order created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object
                    properties:
                      order:
                        $ref: '#/components/schemas/Order'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /orders/summary:
    get:
      tags: [Orders]
      summary: Dashboard summary counts
      security:
        - bearerAuth: []
      responses:
        '200':
          description: Summary statistics for the dashboard
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    $ref: '#/components/schemas/OrderSummary'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /orders/{id}:
    get:
      tags: [Orders]
      summary: Get a single order
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Order details with delivery boy info
        '404':
          $ref: '#/components/responses/NotFound'
    delete:
      tags: [Orders]
      summary: Cancel / delete an order
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Order cancelled
        '404':
          $ref: '#/components/responses/NotFound'

  /orders/{id}/status:
    patch:
      tags: [Orders]
      summary: Update order status
      description: |
        Allowed status values:
        - Initial actions: `accepted`, `cancelled`, `pending`
        - Final actions: `delivered`, `undelivered`, `rescheduled`
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [status]
              properties:
                status:
                  type: string
                  enum: [new, pending, accepted, delivered, undelivered, cancelled, rescheduled]
                note:
                  type: string
      responses:
        '200':
          description: Status updated
        '400':
          $ref: '#/components/responses/BadRequest'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: Order already in a terminal state

  /orders/{id}/acknowledge:
    patch:
      tags: [Orders]
      summary: Acknowledge order notification (stops alarm)
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Notification acknowledged
        '404':
          $ref: '#/components/responses/NotFound'

  /orders/{id}/payment:
    patch:
      tags: [Orders]
      summary: Mark COD payment as received
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [paymentMethod]
              properties:
                paymentMethod:
                  type: string
                  enum: [cash, upi]
      responses:
        '200':
          description: Payment marked as received
        '400':
          $ref: '#/components/responses/BadRequest'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: Payment already received or not COD

  /orders/{id}/assign:
    patch:
      tags: [Orders]
      summary: Assign a delivery boy to an order
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [deliveryBoyId]
              properties:
                deliveryBoyId:
                  type: string
                  description: The string ID of the delivery boy (e.g. dboy_ramesh_a1b2c3)
      responses:
        '200':
          description: Delivery boy assigned
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: Delivery boy unavailable

  # ================================================================
  # Railbites – Email Parser
  # ================================================================
  /email/inbox:
    get:
      tags: [Email]
      summary: List emails in the simulated IRCTC inbox
      security:
        - bearerAuth: []
      parameters:
        - in: query
          name: processed
          schema:
            type: boolean
      responses:
        '200':
          description: Email list
        '401':
          $ref: '#/components/responses/Unauthorized'

  /email/fetch:
    post:
      tags: [Email]
      summary: Fetch and parse new IRCTC emails into orders
      description: Triggers email fetch + parse cycle. Unprocessed emails are parsed and new orders are created.
      security:
        - bearerAuth: []
      responses:
        '200':
          description: Emails processed and orders created
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object
                    properties:
                      message:
                        type: string
                      processedCount:
                        type: integer
                      newOrders:
                        type: array
                        items:
                          $ref: '#/components/schemas/Order'
                      failedEmails:
                        type: array
                        items:
                          type: object
                          properties:
                            emailId:
                              type: string
                            reason:
                              type: string
        '401':
          $ref: '#/components/responses/Unauthorized'

  /email/parse:
    post:
      tags: [Email]
      summary: Dry-run parse a raw email body
      description: Extracts structured order fields from raw email body without creating an order.
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [rawBody]
              properties:
                rawBody:
                  type: string
      responses:
        '200':
          description: Parsed order fields
        '422':
          description: Could not parse order data

  /email/{id}:
    get:
      tags: [Email]
      summary: Get a single email record
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Email details with linked order
        '404':
          $ref: '#/components/responses/NotFound'

  # ================================================================
  # Railbites – Delivery Boys
  # ================================================================
  /delivery-boys:
    get:
      tags: [DeliveryBoys]
      summary: List all delivery personnel
      security:
        - bearerAuth: []
      parameters:
        - in: query
          name: status
          schema:
            type: string
            enum: [available, busy, off-duty]
      responses:
        '200':
          description: Delivery boys list
    post:
      tags: [DeliveryBoys]
      summary: Add a new delivery person
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name, phone]
              properties:
                name:
                  type: string
                phone:
                  type: string
      responses:
        '201':
          description: Delivery person created
        '409':
          description: Phone number already exists

  /delivery-boys/{id}:
    get:
      tags: [DeliveryBoys]
      summary: Get delivery boy with assigned orders
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Delivery boy details
        '404':
          $ref: '#/components/responses/NotFound'
    patch:
      tags: [DeliveryBoys]
      summary: Update delivery boy info or status
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                phone:
                  type: string
                status:
                  type: string
                  enum: [available, busy, off-duty]
      responses:
        '200':
          description: Updated delivery boy
        '404':
          $ref: '#/components/responses/NotFound'
    delete:
      tags: [DeliveryBoys]
      summary: Remove a delivery boy (only if no active orders)
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Delivery boy removed
        '409':
          description: Has active orders assigned

  /delivery-boys/{id}/orders:
    get:
      tags: [DeliveryBoys]
      summary: List orders assigned to a delivery boy
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
        - in: query
          name: status
          schema:
            type: string
        - in: query
          name: dateFrom
          schema:
            type: string
            format: date-time
        - in: query
          name: dateTo
          schema:
            type: string
            format: date-time
      responses:
        '200':
          description: Orders assigned to delivery boy
        '404':
          $ref: '#/components/responses/NotFound'

  # ================================================================
  # Railbites – Reports
  # ================================================================

  /reports/overview:
    get:
      tags: [RestaurantReports]
      summary: Overall business analytics overview
      description: KPI summary, status breakdown, payment breakdown, top items, delivery performance, and aggregator/restaurant/chain breakdowns. Optionally filter by date range and restaurant (super_admin only).
      security:
        - bearerAuth: []
      parameters:
        - in: query
          name: dateFrom
          schema:
            type: string
            format: date
            example: '2026-03-31'
        - in: query
          name: dateTo
          schema:
            type: string
            format: date
            example: '2026-04-29'
        - in: query
          name: restaurantId
          description: Filter to a specific restaurant (super_admin only)
          schema:
            type: string
            example: rest_hwh_a1b2c3d4
      responses:
        '200':
          description: Analytics overview
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object
                    properties:
                      summary:
                        type: object
                        properties:
                          totalOrders:
                            type: integer
                          totalRevenue:
                            type: number
                          avgOrderValue:
                            type: number
                          deliverySuccessRate:
                            type: string
                            example: '75.00%'
                          totalCommissionFee:
                            type: number
                            description: Total aggregator commission deducted across all platforms
                          totalVendorNet:
                            type: number
                            description: Total revenue after all aggregator commissions
                      ordersByStatus:
                        type: object
                        properties:
                          new:
                            type: integer
                          pending:
                            type: integer
                          accepted:
                            type: integer
                          delivered:
                            type: integer
                          undelivered:
                            type: integer
                          cancelled:
                            type: integer
                          rescheduled:
                            type: integer
                      paymentBreakdown:
                        type: object
                        properties:
                          prepaidOrders:
                            type: integer
                          prepaidRevenue:
                            type: number
                          codOrders:
                            type: integer
                          codCollected:
                            type: number
                          codPending:
                            type: number
                      peakOrderHour:
                        type: integer
                        example: 8
                      topItems:
                        type: array
                        items:
                          type: object
                          properties:
                            name:
                              type: string
                            quantity:
                              type: integer
                      deliveryPerformance:
                        type: array
                        items:
                          type: object
                          properties:
                            id:
                              type: string
                            name:
                              type: string
                            totalAssigned:
                              type: integer
                            delivered:
                              type: integer
                            successRate:
                              type: string
                      byAggregator:
                        type: array
                        description: Orders grouped by email aggregator platform with commission data
                        items:
                          type: object
                          properties:
                            name:
                              type: string
                              enum: [irctc, railrestro, railfeast, dibrail, olf, yatrirestro, manual, other]
                            count:
                              type: integer
                            revenue:
                              type: number
                              description: Total delivered order revenue from this aggregator
                            color:
                              type: string
                              example: '#3b82f6'
                            commissionPercent:
                              type: number
                              description: Commission rate charged by this aggregator (%)
                            commissionAmount:
                              type: number
                              description: Total fee deducted by this aggregator
                            vendorNet:
                              type: number
                              description: Revenue after aggregator commission
                      byRestaurant:
                        type: array
                        description: Aggregated stats per restaurant (super_admin only)
                        items:
                          type: object
                          properties:
                            restaurantId:
                              type: string
                            restaurantName:
                              type: string
                            stationCode:
                              type: string
                            totalOrders:
                              type: integer
                            revenue:
                              type: number
                            delivered:
                              type: integer
                            cancelled:
                              type: integer
                            successRate:
                              type: string
                      byChain:
                        type: array
                        description: Aggregated stats per chain
                        items:
                          type: object
                          properties:
                            chainId:
                              type: string
                            chainName:
                              type: string
                            restaurantId:
                              type: string
                            restaurantName:
                              type: string
                            totalOrders:
                              type: integer
                            revenue:
                              type: number
                            delivered:
                              type: integer
                            cancelled:
                              type: integer
                            successRate:
                              type: string

  # ================================================================
  # Railbites – Restaurant Auth
  # ================================================================
  /restaurant-auth/login:
    post:
      tags: [RestaurantAuth]
      summary: Login (Railbites)
      description: Authenticate a Railbites user (super_admin / admin / user) and receive a JWT.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [email, password]
              properties:
                email:
                  type: string
                  example: railbites.ai@gmail.com
                password:
                  type: string
                  example: '••••••'
      responses:
        '200':
          description: Login successful
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object
                    properties:
                      token:
                        type: string
                      expiresIn:
                        type: string
                      user:
                        $ref: '#/components/schemas/RestaurantUser'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /restaurant-auth/me:
    get:
      tags: [RestaurantAuth]
      summary: Get current user profile and scope
      security:
        - bearerAuth: []
      responses:
        '200':
          description: Current user with resolved scope
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object
                    properties:
                      user:
                        $ref: '#/components/schemas/RestaurantUser'
                      scope:
                        $ref: '#/components/schemas/UserScope'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /restaurant-auth/users:
    get:
      tags: [RestaurantAuth]
      summary: List all Railbites users (super_admin only)
      security:
        - bearerAuth: []
      responses:
        '200':
          description: All users
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object
                    properties:
                      users:
                        type: array
                        items:
                          $ref: '#/components/schemas/RestaurantUser'
                      total:
                        type: integer
        '403':
          $ref: '#/components/responses/Forbidden'

    post:
      tags: [RestaurantAuth]
      summary: Create a new Railbites user (super_admin / admin)
      description: |
        - **super_admin** can create users with any role
        - **admin** can only create `user` role accounts within their own restaurant
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name, email, password, role]
              properties:
                name:
                  type: string
                  example: Jane Doe
                email:
                  type: string
                  format: email
                  example: jane@railbites.in
                password:
                  type: string
                  minLength: 6
                  example: pass123
                role:
                  type: string
                  enum: [super_admin, admin, user]
                restaurantId:
                  type: string
                  nullable: true
                  example: rest_hwh_a1b2c3d4
                chainId:
                  type: string
                  nullable: true
                  example: chain_hwh_p1_9a0b1c2d
      responses:
        '201':
          description: User created
        '400':
          $ref: '#/components/responses/BadRequest'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          description: Email already exists

  /restaurant-auth/users/{id}:
    put:
      tags: [RestaurantAuth]
      summary: Update a user's profile (name, email, phone)
      description: |
        - Users can update their own profile
        - Admins can update users within their restaurant
        - super_admin can update any user
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                email:
                  type: string
                  format: email
                phone:
                  type: string
      responses:
        '200':
          description: User updated
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: Email already taken

  /restaurant-auth/users/{id}/status:
    patch:
      tags: [RestaurantAuth]
      summary: Activate or deactivate a user
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [status]
              properties:
                status:
                  type: string
                  enum: [active, inactive]
      responses:
        '200':
          description: User status updated
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'

  /restaurant-auth/change-password:
    post:
      tags: [RestaurantAuth]
      summary: Change authenticated user's password
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [currentPassword, newPassword]
              properties:
                currentPassword:
                  type: string
                  example: oldpass123
                newPassword:
                  type: string
                  minLength: 6
                  example: newpass456
      responses:
        '200':
          description: Password changed successfully
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /restaurant-auth/forgot-password:
    post:
      tags: [RestaurantAuth]
      summary: Request a password reset token
      description: |
        Generates a 1-hour reset token for the given email.
        In production the token would be emailed; here it is returned in the response for testing.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [email]
              properties:
                email:
                  type: string
                  format: email
                  example: railbites.ai@gmail.com
      responses:
        '200':
          description: Reset token generated
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object
                    properties:
                      resetToken:
                        type: string
                        description: Use this token with /reset-password (development only — send via email in production)
                      email:
                        type: string
                      expiresIn:
                        type: string
                        example: 1h

  /restaurant-auth/reset-password:
    post:
      tags: [RestaurantAuth]
      summary: Reset password using a reset token
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [token, newPassword]
              properties:
                token:
                  type: string
                  description: Token received from /forgot-password
                newPassword:
                  type: string
                  minLength: 6
                  example: newpass456
      responses:
        '200':
          description: Password reset successfully
        '400':
          description: Invalid or expired reset token
        '404':
          $ref: '#/components/responses/NotFound'

  /restaurant-auth/verify-token:
    post:
      tags: [RestaurantAuth]
      summary: Verify current JWT and get remaining time
      security:
        - bearerAuth: []
      responses:
        '200':
          description: Token is valid
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object
                    properties:
                      valid:
                        type: boolean
                      user:
                        $ref: '#/components/schemas/RestaurantUser'
                      token:
                        type: object
                        properties:
                          iat:
                            type: integer
                          exp:
                            type: integer
                          remainingTime:
                            type: string
                            example: 6d 23h 58m
        '401':
          $ref: '#/components/responses/Unauthorized'

  /restaurant-auth/logout:
    post:
      tags: [RestaurantAuth]
      summary: Logout (client should discard the token)
      description: |
        Restaurant auth uses stateless JWTs — this endpoint confirms logout so the client
        can safely clear its stored token. The token remains technically valid until expiry
        (no server-side blacklist in this implementation).
      security:
        - bearerAuth: []
      responses:
        '200':
          description: Logged out successfully
        '401':
          $ref: '#/components/responses/Unauthorized'


  # ================================================================
  # Railbites – Restaurants
  # ================================================================
  /restaurants:
    get:
      tags: [Restaurants]
      summary: List restaurants
      description: |
        - **super_admin** → all restaurants
        - **admin** → their own restaurant only
        - **user** → their own restaurant only
      security:
        - bearerAuth: []
      responses:
        '200':
          description: Restaurant list
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object
                    properties:
                      restaurants:
                        type: array
                        items:
                          $ref: '#/components/schemas/Restaurant'
                      total:
                        type: integer
    post:
      tags: [Restaurants]
      summary: Register a new restaurant (super_admin only)
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateRestaurantRequest'
      responses:
        '201':
          description: Restaurant created – configure email next
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object
                    properties:
                      restaurant:
                        $ref: '#/components/schemas/Restaurant'
                      nextStep:
                        type: string
                        example: Configure email settings at PUT /api/restaurants/4/email-config
        '400':
          $ref: '#/components/responses/BadRequest'
        '403':
          $ref: '#/components/responses/Forbidden'

  /restaurants/{id}:
    get:
      tags: [Restaurants]
      summary: Get a single restaurant with its chains
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Restaurant detail
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
    patch:
      tags: [Restaurants]
      summary: Update restaurant info (super_admin or its admin)
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                city:
                  type: string
                stationCode:
                  type: string
                status:
                  type: string
                  enum: [active, inactive]
      responses:
        '200':
          description: Updated restaurant
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
    delete:
      tags: [Restaurants]
      summary: Delete a restaurant and all its chains (super_admin only)
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Restaurant deleted
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'

  # ── Email Configuration ──────────────────────────────────────────────────────
  /restaurants/{id}/email-config:
    get:
      tags: [EmailConfig]
      summary: Get email configuration for a restaurant
      description: |
        Returns the email integration settings for the restaurant.
        Sensitive fields (`clientSecret`, `emailAppPassword`) are **redacted** by default.
        Add `?reveal=true` to see the actual values (super_admin only).
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
        - in: query
          name: reveal
          description: Set to true to reveal secret fields (super_admin only)
          schema:
            type: boolean
      responses:
        '200':
          description: Email config (secrets redacted unless reveal=true)
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object
                    properties:
                      configured:
                        type: boolean
                      config:
                        $ref: '#/components/schemas/EmailConfig'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
    put:
      tags: [EmailConfig]
      summary: Create or replace email configuration (super_admin only)
      description: |
        Fully creates or replaces the email integration settings for a restaurant.

        ### Required fields by provider:
        | `provider` | Required |
        |---|---|
        | `gmail_oauth2` | `emailAddress`, `clientId`, `clientSecret`, `redirectUri` |
        | `gmail_app_password` | `emailAddress`, `emailAppPassword` |
        | `imap` | `emailAddress`, `emailAppPassword`, `imapHost`, `imapPort` |
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EmailConfigRequest'
            examples:
              gmailOAuth2:
                summary: Gmail OAuth2
                value:
                  emailAddress: orders.hwh@railbites.in
                  provider: gmail_oauth2
                  clientId: 123456-xxxx.apps.googleusercontent.com
                  clientSecret: GOCSPX-xxxxxxxxxxxx
                  redirectUri: http://localhost:5000/api/email/oauth2/callback
              gmailAppPassword:
                summary: Gmail App Password
                value:
                  emailAddress: orders.bct@railbites.in
                  provider: gmail_app_password
                  emailAppPassword: abcd efgh ijkl mnop
              imap:
                summary: Custom IMAP
                value:
                  emailAddress: orders.sbc@railbites.in
                  provider: imap
                  emailAppPassword: my_imap_password
                  imapHost: imap.example.com
                  imapPort: 993
                  imapUseSsl: true
      responses:
        '200':
          description: Configuration saved (secrets redacted in response)
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: object
                    properties:
                      config:
                        $ref: '#/components/schemas/EmailConfig'
        '400':
          $ref: '#/components/responses/BadRequest'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
    patch:
      tags: [EmailConfig]
      summary: Partially update email config (e.g. rotate secret)
      description: Update only specific fields without replacing the entire config.
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                emailAddress:
                  type: string
                provider:
                  type: string
                  enum: [gmail_oauth2, gmail_app_password, imap]
                clientId:
                  type: string
                clientSecret:
                  type: string
                redirectUri:
                  type: string
                emailAppPassword:
                  type: string
                imapHost:
                  type: string
                imapPort:
                  type: integer
                imapUseSsl:
                  type: boolean
      responses:
        '200':
          description: Config updated
        '400':
          $ref: '#/components/responses/BadRequest'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
    delete:
      tags: [EmailConfig]
      summary: Remove email configuration
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Config removed
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'

  # ── Chains ───────────────────────────────────────────────────────────────────
  /restaurants/{restaurantId}/chains:
    get:
      tags: [Chains]
      summary: List chains for a restaurant
      description: |
        - **super_admin / admin** → all chains for that restaurant
        - **user** → only their assigned chain
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: restaurantId
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Chain list
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
    post:
      tags: [Chains]
      summary: Add a new chain to a restaurant (super_admin or its admin)
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: restaurantId
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name, location]
              properties:
                name:
                  type: string
                  example: Platform 9 Counter
                location:
                  type: string
                  example: PF-9
      responses:
        '201':
          description: Chain created
        '400':
          $ref: '#/components/responses/BadRequest'
        '403':
          $ref: '#/components/responses/Forbidden'

  /restaurants/{restaurantId}/chains/{chainId}:
    patch:
      tags: [Chains]
      summary: Update a chain
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: restaurantId
          required: true
          schema:
            type: string
        - in: path
          name: chainId
          required: true
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                location:
                  type: string
                status:
                  type: string
                  enum: [active, inactive]
      responses:
        '200':
          description: Chain updated
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
    delete:
      tags: [Chains]
      summary: Remove a chain
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: restaurantId
          required: true
          schema:
            type: string
        - in: path
          name: chainId
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Chain removed
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'

  # ── Restaurant Staff ──────────────────────────────────────────────────────────
  /restaurants/{restaurantId}/users:
    get:
      tags: [Restaurants]
      summary: List staff users for a restaurant (super_admin or its admin)
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: restaurantId
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Staff list (passwords omitted)
        '403':
          $ref: '#/components/responses/Forbidden'
    post:
      tags: [Restaurants]
      summary: Add a staff user to a restaurant
      description: |
        - **admin** role users require `chainId`
        - **user** role users require `chainId`
      security:
        - bearerAuth: []
      parameters:
        - in: path
          name: restaurantId
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateRestaurantUserRequest'
      responses:
        '201':
          description: User created
        '400':
          $ref: '#/components/responses/BadRequest'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          description: Email already exists

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: JWT token from login endpoint

  schemas:

    Restaurant:
      type: object
      properties:
        id:
          type: string
          example: rest_hwh_a1b2c3d4
        name:
          type: string
        city:
          type: string
        stationCode:
          type: string
        adminId:
          type: string
          nullable: true
        status:
          type: string
          enum: [active, inactive]
        emailConfigured:
          type: boolean
          description: Whether email integration has been configured
        soundConfig:
          type: object
          nullable: true
          description: Per-restaurant alarm sound configuration
          properties:
            frequency:
              type: integer
              description: Tone frequency in Hz (100–2000)
            duration:
              type: integer
              description: Tone duration in ms (200–5000)
            volume:
              type: integer
              description: Volume level 1–100
        chainCount:
          type: integer
          description: Number of chains under this restaurant (enriched field)
        adminName:
          type: string
          nullable: true
        createdAt:
          type: string
          format: date-time

    CreateRestaurantRequest:
      type: object
      required: [name, city, stationCode]
      properties:
        name:
          type: string
          example: New Delhi Railway Catering
        city:
          type: string
          example: New Delhi
        stationCode:
          type: string
          example: NDLS

    Chain:
      type: object
      properties:
        id:
          type: string
          example: chain_hwh_p1_9a0b1c2d
        restaurantId:
          type: string
        name:
          type: string
        location:
          type: string
        status:
          type: string
          enum: [active, inactive]

    RestaurantUser:
      type: object
      properties:
        id:
          type: string
          example: usr_jane_a1b2c3d4
        name:
          type: string
        email:
          type: string
        role:
          type: string
          enum: [super_admin, admin, user]
        restaurantId:
          type: string
          nullable: true
        chainId:
          type: string
          nullable: true
        status:
          type: string
          enum: [active, inactive]
        createdAt:
          type: string
          format: date-time

    CreateRestaurantUserRequest:
      type: object
      required: [name, email, password, role]
      properties:
        name:
          type: string
        email:
          type: string
        password:
          type: string
        role:
          type: string
          enum: [admin, user]
        chainId:
          type: string
          description: Required when role is 'user'

    UserScope:
      type: object
      description: Resolved access scope for the authenticated user
      properties:
        level:
          type: string
          enum: [all, restaurant, chain]
          description: |
            - `all` → super_admin sees everything
            - `restaurant` → admin sees their restaurant + all chains
            - `chain` → user sees only their assigned chain
        restaurantId:
          type: string
          nullable: true
        chainId:
          type: string
          nullable: true

    EmailConfig:
      type: object
      properties:
        id:
          type: string
          example: ecfg_a1b2c3d4
        restaurantId:
          type: string
        emailAddress:
          type: string
          example: orders.hwh@railbites.in
        provider:
          type: string
          enum: [gmail_oauth2, gmail_app_password, imap]
        clientId:
          type: string
          nullable: true
          description: OAuth2 Client ID (gmail_oauth2 only)
        clientSecret:
          type: string
          nullable: true
          description: Redacted as '••••••••' unless reveal=true
        redirectUri:
          type: string
          nullable: true
          description: OAuth2 Redirect URI (gmail_oauth2 only)
        emailAppPassword:
          type: string
          nullable: true
          description: App password or IMAP password – redacted unless reveal=true
        imapHost:
          type: string
          nullable: true
        imapPort:
          type: integer
          nullable: true
        imapUseSsl:
          type: boolean
        aggregatorCommissions:
          type: object
          description: Commission percentage per aggregator platform. Keys are aggregator names (irctc, railrestro, etc.), values are percentages (0–100).
          example:
            irctc: 5
            railrestro: 3
            railfeast: 4
          additionalProperties:
            type: number
            minimum: 0
            maximum: 100
        configured:
          type: boolean
        configuredAt:
          type: string
          format: date-time
        configuredBy:
          type: string
          description: User ID of the super_admin who saved this config

    EmailConfigRequest:
      type: object
      required: [emailAddress, provider]
      properties:
        emailAddress:
          type: string
          example: orders.hwh@railbites.in
        provider:
          type: string
          enum: [gmail_oauth2, gmail_app_password, imap]
        clientId:
          type: string
          description: Required for gmail_oauth2
        clientSecret:
          type: string
          description: Required for gmail_oauth2
        redirectUri:
          type: string
          description: Required for gmail_oauth2
        emailAppPassword:
          type: string
          description: Required for gmail_app_password and imap
        imapHost:
          type: string
          description: Required for imap
        imapPort:
          type: integer
          description: Required for imap
          example: 993
        imapUseSsl:
          type: boolean
          default: true
        aggregatorCommissions:
          type: object
          description: Commission % per aggregator platform (0–100). Omit or pass {} for no commissions.
          example:
            irctc: 5
            railrestro: 3
          additionalProperties:
            type: number
            minimum: 0
            maximum: 100

    Order:
      type: object
      properties:
        id:
          type: string
          example: ord_a1b2c3d4
        source:
          type: string
          enum: [irctc_email, manual]
        emailId:
          type: string
          nullable: true
        irctcOrderId:
          type: string
          nullable: true
          description: Order ID extracted from IRCTC / aggregator email
        trainNumber:
          type: string
        trainName:
          type: string
          nullable: true
        coachNumber:
          type: string
        seatNumber:
          type: string
        customerName:
          type: string
        customerPhone:
          type: string
        items:
          type: array
          items:
            $ref: '#/components/schemas/OrderItem'
        totalAmount:
          type: number
        paymentType:
          type: string
          enum: [prepaid, cod]
        paymentStatus:
          type: string
          enum: [paid, pending, received]
        paymentMethod:
          type: string
          enum: [cash, upi]
          nullable: true
        orderStatus:
          type: string
          enum: [new, pending, accepted, delivered, undelivered, cancelled, rescheduled]
        assignedDeliveryBoyId:
          type: string
          nullable: true
          description: String ID of the assigned delivery boy (e.g. dboy_ramesh_a1b2c3)
        orderedAt:
          type: string
          format: date-time
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        notificationAcknowledged:
          type: boolean
        statusNote:
          type: string
          nullable: true
          description: Optional note set when changing order status
        aggregator:
          type: string
          nullable: true
          description: Aggregator platform (irctc, railrestro, etc.)
          enum: [irctc, railrestro, railfeast, dibrail, olf, yatrirestro, manual, other]

    OrderItem:
      type: object
      properties:
        name:
          type: string
        quantity:
          type: integer
        price:
          type: number

    CreateOrderRequest:
      type: object
      required: [trainNumber, coachNumber, seatNumber, customerName, customerPhone, items, paymentType]
      properties:
        trainNumber:
          type: string
        trainName:
          type: string
        coachNumber:
          type: string
        seatNumber:
          type: string
        customerName:
          type: string
        customerPhone:
          type: string
        items:
          type: array
          items:
            $ref: '#/components/schemas/OrderItem'
        paymentType:
          type: string
          enum: [prepaid, cod]
        source:
          type: string
          default: manual

    OrderCounts:
      type: object
      properties:
        new:
          type: integer
        pending:
          type: integer
        accepted:
          type: integer
        delivered:
          type: integer
        undelivered:
          type: integer
        cancelled:
          type: integer
        rescheduled:
          type: integer

    OrderSummary:
      type: object
      properties:
        totalOrders:
          type: integer
        totalRevenue:
          type: number
        pendingCodAmount:
          type: number
        unacknowledgedNewOrders:
          type: integer
        byStatus:
          $ref: '#/components/schemas/OrderCounts'
        byPaymentType:
          type: object
          properties:
            prepaid:
              type: integer
            cod:
              type: integer

    DeliveryBoy:
      type: object
      properties:
        id:
          type: string
          example: dboy_ramesh_a1b2c3d4
        name:
          type: string
        phone:
          type: string
        restaurantId:
          type: string
        chainId:
          type: string
          nullable: true
        status:
          type: string
          enum: [available, busy, off-duty]
        assignedOrders:
          type: array
          items:
            type: string
        activeOrderCount:
          type: integer
        createdAt:
          type: string
          format: date-time

    Pagination:
      type: object
      properties:
        page:
          type: integer
        limit:
          type: integer
        total:
          type: integer
        totalPages:
          type: integer
    ErrorResponse:
      type: object
      properties:
        success:
          type: boolean
          example: false
        error:
          type: object
          properties:
            code:
              type: string
            message:
              type: string
            details:
              type: object

  responses:
    BadRequest:
      description: Bad request - Invalid parameters or request format
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            invalidParameters:
              summary: Invalid request parameters
              value:
                success: false
                error:
                  code: BAD_REQUEST
                  message: Invalid request parameters
                  details:
                    field: "email"
                    issue: "Invalid email format"
            missingRequired:
              summary: Missing required fields
              value:
                success: false
                error:
                  code: MISSING_REQUIRED_FIELDS
                  message: Required fields are missing
                  details:
                    missingFields: ["title", "description", "priority"]

    Unauthorized:
      description: Unauthorized - Authentication required or invalid token
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            noToken:
              summary: No authentication token provided
              value:
                success: false
                error:
                  code: UNAUTHORIZED
                  message: Authentication required
            invalidCredentials:
              summary: Invalid login credentials
              value:
                success: false
                error:
                  code: INVALID_CREDENTIALS
                  message: Invalid email or password
            expiredToken:
              summary: Expired authentication token
              value:
                success: false
                error:
                  code: TOKEN_EXPIRED
                  message: Authentication token has expired

    Forbidden:
      description: Forbidden - Insufficient permissions for this operation
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            departmentAccess:
              summary: Department access denied
              value:
                success: false
                error:
                  code: FORBIDDEN
                  message: You don't have permission to access this department's data
                  details:
                    userDepartment: "Signal & Telecom"
                    requestedDepartment: "IT"
            rolePermission:
              summary: Role permission denied
              value:
                success: false
                error:
                  code: INSUFFICIENT_PERMISSIONS
                  message: Your role does not allow this operation
                  details:
                    userRole: "user"
                    requiredRole: "admin"
            ticketAccess:
              summary: Ticket access denied
              value:
                success: false
                error:
                  code: TICKET_ACCESS_DENIED
                  message: You don't have permission to access this ticket
                  details:
                    ticketId: "TKT-2024-001"
                    reason: "Ticket not assigned to your department"

    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            ticketNotFound:
              summary: Ticket not found
              value:
                success: false
                error:
                  code: TICKET_NOT_FOUND
                  message: Ticket not found
                  details:
                    ticketId: "TKT-2024-999"
            departmentNotFound:
              summary: Department not found
              value:
                success: false
                error:
                  code: DEPARTMENT_NOT_FOUND
                  message: Department not found
                  details:
                    departmentId: 999

    InternalServerError:
      description: Internal server error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            databaseError:
              summary: Database connection error
              value:
                success: false
                error:
                  code: DATABASE_ERROR
                  message: Database connection failed
            systemError:
              summary: Unexpected system error
              value:
                success: false
                error:
                  code: INTERNAL_ERROR
                  message: An unexpected error occurred
            serviceUnavailable:
              summary: Service temporarily unavailable
              value:
                success: false
                error:
                  code: SERVICE_UNAVAILABLE
                  message: Service temporarily unavailable, please try again later