openapi: 3.0.3
info:
  title: NovaTrek Inventory Procurement API
  description: |
    Manages purchasing workflows, supplier relationships, and stock replenishment
    for gear and supplies across all NovaTrek locations. Integrates with
    svc-location-services for warehouse/shop inventory tracking and
    svc-gear-inventory for item category definitions.
  version: 2.1.0
  contact:
    name: NovaTrek Platform Engineering
    email: platform-eng@novatrek.example.com

servers:
  - url: https://api.novatrek.example.com/procurement/v1
    description: Production
  - url: https://api-staging.novatrek.example.com/procurement/v1
    description: Staging

security:
  - bearerAuth: []

paths:
  /purchase-orders:
    post:
      operationId: createPurchaseOrder
      summary: Create a new purchase order
      description: Initiates a purchase order in DRAFT status. Items reference gear categories from svc-gear-inventory.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreatePurchaseOrderRequest'
      responses:
        '201':
          description: Purchase order created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PurchaseOrder'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalError'

  /purchase-orders/{po_id}:
    get:
      operationId: getPurchaseOrder
      summary: Get purchase order details
      parameters:
        - $ref: '#/components/parameters/PurchaseOrderId'
      responses:
        '200':
          description: Purchase order details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PurchaseOrder'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalError'
    patch:
      operationId: updatePurchaseOrder
      summary: Update purchase order status or line items
      description: |
        Supports status transitions: DRAFT->SUBMITTED->APPROVED->SHIPPED->RECEIVED.
        Orders can be CANCELLED from DRAFT or SUBMITTED states only.
      parameters:
        - $ref: '#/components/parameters/PurchaseOrderId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdatePurchaseOrderRequest'
      responses:
        '200':
          description: Purchase order updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PurchaseOrder'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '500':
          $ref: '#/components/responses/InternalError'

  /suppliers:
    get:
      operationId: listSuppliers
      summary: List all suppliers
      parameters:
        - name: rating_min
          in: query
          schema:
            type: number
            format: double
            minimum: 0
            maximum: 5
        - name: category
          in: query
          description: Filter by supply category
          schema:
            type: string
        - $ref: '#/components/parameters/PageSize'
        - $ref: '#/components/parameters/PageToken'
      responses:
        '200':
          description: List of suppliers
          content:
            application/json:
              schema:
                type: object
                properties:
                  suppliers:
                    type: array
                    items:
                      $ref: '#/components/schemas/Supplier'
                  next_page_token:
                    type: string
                  total_count:
                    type: integer
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalError'
    post:
      operationId: createSupplier
      summary: Register a new supplier
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateSupplierRequest'
      responses:
        '201':
          description: Supplier created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Supplier'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '409':
          $ref: '#/components/responses/Conflict'
        '500':
          $ref: '#/components/responses/InternalError'

  /stock-levels:
    get:
      operationId: getStockLevels
      summary: Query current stock levels
      description: |
        Returns stock levels filtered by location and/or item category.
        Location references svc-location-services; categories reference svc-gear-inventory.
      parameters:
        - name: location_id
          in: query
          description: Filter by location (cross-ref svc-location-services)
          schema:
            type: string
            format: uuid
        - name: item_category
          in: query
          description: Filter by gear category (cross-ref svc-gear-inventory)
          schema:
            type: string
        - name: below_reorder_point
          in: query
          description: Only return items below reorder threshold
          schema:
            type: boolean
            default: false
        - $ref: '#/components/parameters/PageSize'
        - $ref: '#/components/parameters/PageToken'
      responses:
        '200':
          description: Stock level data
          content:
            application/json:
              schema:
                type: object
                properties:
                  stock_levels:
                    type: array
                    items:
                      $ref: '#/components/schemas/StockLevel'
                  next_page_token:
                    type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalError'

  /stock-adjustments:
    post:
      operationId: createStockAdjustment
      summary: Record a stock adjustment
      description: Used for manual corrections, damage write-offs, or receiving shipments outside PO flow.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StockAdjustmentRequest'
      responses:
        '201':
          description: Adjustment recorded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StockAdjustment'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalError'

  /reorder-alerts:
    get:
      operationId: listReorderAlerts
      summary: Get active reorder alerts
      description: Returns items that have fallen below their configured reorder point and need replenishment.
      parameters:
        - name: location_id
          in: query
          schema:
            type: string
            format: uuid
        - name: severity
          in: query
          schema:
            type: string
            enum: [LOW, MEDIUM, CRITICAL]
        - $ref: '#/components/parameters/PageSize'
        - $ref: '#/components/parameters/PageToken'
      responses:
        '200':
          description: Reorder alerts
          content:
            application/json:
              schema:
                type: object
                properties:
                  alerts:
                    type: array
                    items:
                      $ref: '#/components/schemas/ReorderAlert'
                  next_page_token:
                    type: string
                  total_count:
                    type: integer
        '401':
          $ref: '#/components/responses/Unauthorized'
        '500':
          $ref: '#/components/responses/InternalError'

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

  parameters:
    PurchaseOrderId:
      name: po_id
      in: path
      required: true
      schema:
        type: string
        format: uuid
    PageSize:
      name: page_size
      in: query
      schema:
        type: integer
        minimum: 1
        maximum: 100
        default: 25
    PageToken:
      name: page_token
      in: query
      schema:
        type: string

  schemas:
    PurchaseOrderStatus:
      type: string
      enum: [DRAFT, SUBMITTED, APPROVED, SHIPPED, RECEIVED, CANCELLED]

    PurchaseOrder:
      type: object
      required: [id, supplier_id, items, status, total_amount]
      properties:
        id:
          type: string
          format: uuid
        supplier_id:
          type: string
          format: uuid
        items:
          type: array
          minItems: 1
          items:
            $ref: '#/components/schemas/PurchaseOrderItem'
        status:
          $ref: '#/components/schemas/PurchaseOrderStatus'
        total_amount:
          type: number
          format: double
          minimum: 0
        currency:
          type: string
          default: USD
        delivery_location_id:
          type: string
          format: uuid
          description: Delivery destination (cross-ref svc-location-services)
        expected_delivery_date:
          type: string
          format: date
        notes:
          type: string
        created_by:
          type: string
          format: uuid
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    PurchaseOrderItem:
      type: object
      required: [item_category, description, quantity, unit_price]
      properties:
        item_category:
          type: string
          description: Gear category (cross-ref svc-gear-inventory)
          example: "CLIMBING_HARNESS"
        description:
          type: string
          example: "Black Diamond Momentum Harness - Medium"
        quantity:
          type: integer
          minimum: 1
        unit_price:
          type: number
          format: double
          minimum: 0
        line_total:
          type: number
          format: double

    Supplier:
      type: object
      required: [id, name, contact, lead_time_days]
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
          example: "Alpine Gear Distributors"
        contact:
          $ref: '#/components/schemas/SupplierContact'
        lead_time_days:
          type: integer
          minimum: 1
          description: Average days from order to delivery
        rating:
          type: number
          format: double
          minimum: 0
          maximum: 5
        categories:
          type: array
          items:
            type: string
          description: Supply categories this vendor fulfills
        active:
          type: boolean
          default: true
        created_at:
          type: string
          format: date-time

    SupplierContact:
      type: object
      properties:
        email:
          type: string
          format: email
        phone:
          type: string
        representative_name:
          type: string
        address:
          type: string

    StockLevel:
      type: object
      required: [item_category, location_id, on_hand, reorder_point]
      properties:
        item_category:
          type: string
          description: Gear category (cross-ref svc-gear-inventory)
        location_id:
          type: string
          format: uuid
          description: Storage location (cross-ref svc-location-services)
        on_hand:
          type: integer
          minimum: 0
        on_order:
          type: integer
          minimum: 0
          default: 0
        reorder_point:
          type: integer
          minimum: 0
        reorder_quantity:
          type: integer
          minimum: 1
        last_count_date:
          type: string
          format: date
        unit_cost:
          type: number
          format: double

    StockAdjustmentRequest:
      type: object
      required: [item_category, location_id, quantity_change, reason]
      properties:
        item_category:
          type: string
        location_id:
          type: string
          format: uuid
        quantity_change:
          type: integer
          description: Positive for additions, negative for removals
        reason:
          type: string
          enum: [DAMAGE, LOSS, CORRECTION, TRANSFER, OTHER]
        notes:
          type: string

    StockAdjustment:
      type: object
      properties:
        id:
          type: string
          format: uuid
        item_category:
          type: string
        location_id:
          type: string
          format: uuid
        quantity_change:
          type: integer
        reason:
          type: string
        notes:
          type: string
        adjusted_by:
          type: string
          format: uuid
        created_at:
          type: string
          format: date-time

    ReorderAlert:
      type: object
      properties:
        id:
          type: string
          format: uuid
        item_category:
          type: string
        location_id:
          type: string
          format: uuid
        current_on_hand:
          type: integer
        reorder_point:
          type: integer
        recommended_order_quantity:
          type: integer
        severity:
          type: string
          enum: [LOW, MEDIUM, CRITICAL]
        preferred_supplier_id:
          type: string
          format: uuid
        created_at:
          type: string
          format: date-time

    CreatePurchaseOrderRequest:
      type: object
      required: [supplier_id, items, delivery_location_id]
      properties:
        supplier_id:
          type: string
          format: uuid
        items:
          type: array
          minItems: 1
          items:
            $ref: '#/components/schemas/PurchaseOrderItem'
        delivery_location_id:
          type: string
          format: uuid
        expected_delivery_date:
          type: string
          format: date
        notes:
          type: string

    UpdatePurchaseOrderRequest:
      type: object
      properties:
        status:
          $ref: '#/components/schemas/PurchaseOrderStatus'
        items:
          type: array
          items:
            $ref: '#/components/schemas/PurchaseOrderItem'
        expected_delivery_date:
          type: string
          format: date
        notes:
          type: string

    CreateSupplierRequest:
      type: object
      required: [name, contact, lead_time_days]
      properties:
        name:
          type: string
        contact:
          $ref: '#/components/schemas/SupplierContact'
        lead_time_days:
          type: integer
          minimum: 1
        categories:
          type: array
          items:
            type: string

    Error:
      type: object
      required: [code, message]
      properties:
        code:
          type: string
        message:
          type: string
        details:
          type: array
          items:
            type: object
            properties:
              field:
                type: string
              reason:
                type: string

  responses:
    BadRequest:
      description: Invalid request parameters
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: Missing or invalid authentication
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Conflict:
      description: Resource conflict or invalid state transition
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    InternalError:
      description: Internal server error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
