openapi: 3.0.3
info:
  title: TenantPilot Admin — External Support Desk Handoff (Conceptual)
  version: 0.1.0
  description: |
    Conceptual contract for the first external support desk handoff slice.

    NOTE: These flows are implemented as Filament (Livewire) actions on
    existing pages. This file captures the expected action payload, outcome
    semantics, and authorization boundaries rather than a public REST API.
servers:
  - url: /admin
paths:
  /t/{tenant}/support-requests/actions/submit:
    post:
      summary: Submit a tenant-context support request with optional external handoff
      description: |
        Existing tenant dashboard support action, extended with one-way external
        handoff behavior.

        Authorization:
        - Workspace non-member or non-entitled tenant actor: 404
        - Entitled tenant member without `support_requests.create`: 403
        - Authorized actor: 200 with one support-request submission result

        Behavior:
        - Always creates the internal `SR-...` support request first
        - `internal_only` performs no outbound handoff
        - `link_existing_ticket` stores the provided external reference and must not call external create
        - `create_external_ticket` uses one application-configured external target only
        - `create_external_ticket` applies a maximum 5 second outbound timeout budget
        - External create failure keeps the internal support request and returns an explicit failed-handoff outcome
        - No queue, `OperationRun`, retry scheduler, or bidirectional sync is introduced
      parameters:
        - name: tenant
          in: path
          required: true
          schema:
            type: string
          description: Filament tenancy slug (`tenants.external_id`)
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SupportRequestHandoffSubmission'
      responses:
        '200':
          description: Support request accepted with internal-only, linked, created, or failed-handoff outcome
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SupportRequestHandoffResult'
        '403':
          description: Forbidden (entitled tenant member lacks support-request capability)
        '404':
          description: Not found (wrong workspace, non-member, or missing tenant entitlement)
  /operations/{run}/support-requests/actions/submit:
    post:
      summary: Submit a run-context support request with optional external handoff
      description: |
        Existing canonical run detail support action, extended with one-way
        external handoff behavior.

        Authorization:
        - Inaccessible run or run outside entitled tenant scope: 404
        - Entitled member without `support_requests.create`: 403
        - Authorized actor: 200 with one support-request submission result

        Behavior:
        - The run must resolve to an entitled tenant before any support truth is revealed
        - Uses the same payload contract and outcome semantics as the tenant-context action
        - Does not create, resume, or update an `OperationRun`
      parameters:
        - name: run
          in: path
          required: true
          schema:
            type: integer
          description: Internal `operation_runs.id`
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SupportRequestHandoffSubmission'
      responses:
        '200':
          description: Support request accepted with internal-only, linked, created, or failed-handoff outcome
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SupportRequestHandoffResult'
        '403':
          description: Forbidden (entitled member lacks support-request capability)
        '404':
          description: Not found (run inaccessible under workspace or tenant scope)
components:
  schemas:
    SupportRequestHandoffSubmission:
      type: object
      required:
        - severity
        - summary
        - handoff_mode
      properties:
        severity:
          type: string
          enum: [low, normal, high, blocking]
        summary:
          type: string
        reproduction_notes:
          type: string
          nullable: true
        contact_name:
          type: string
          nullable: true
        contact_email:
          type: string
          format: email
          nullable: true
        handoff_mode:
          type: string
          enum: [internal_only, create_external_ticket, link_existing_ticket]
        external_ticket_reference:
          type: string
          nullable: true
          description: Required when `handoff_mode = link_existing_ticket`
        external_ticket_url:
          type: string
          format: uri
          nullable: true
        target_available:
          type: boolean
          nullable: true
          description: Derived UI hint only; the server remains authoritative
    SupportRequestHandoffResult:
      type: object
      required:
        - support_request_id
        - internal_reference
        - primary_context_type
        - handoff_mode
        - handoff_outcome
        - latest_summary
      properties:
        support_request_id:
          type: integer
        internal_reference:
          type: string
        primary_context_type:
          type: string
          enum: [tenant, operation_run]
        primary_context_id:
          type: integer
          nullable: true
        handoff_mode:
          type: string
          enum: [internal_only, create_external_ticket, link_existing_ticket]
        handoff_outcome:
          type: string
          enum:
            - internal_only
            - external_ticket_created
            - external_ticket_linked
            - external_handoff_failed
        external_ticket_reference:
          type: string
          nullable: true
        external_ticket_url:
          type: string
          format: uri
          nullable: true
        failure_summary:
          type: string
          nullable: true
        latest_summary:
          $ref: '#/components/schemas/LatestSupportRequestHandoffSummary'
    LatestSupportRequestHandoffSummary:
      type: object
      required:
        - internal_reference
        - primary_context_type
        - submitted_at
        - handoff_mode
        - has_external_link
        - has_failure
      properties:
        internal_reference:
          type: string
        primary_context_type:
          type: string
          enum: [tenant, operation_run]
        primary_context_id:
          type: integer
          nullable: true
        submitted_at:
          type: string
          format: date-time
        handoff_mode:
          type: string
          enum: [internal_only, create_external_ticket, link_existing_ticket]
        external_ticket_reference:
          type: string
          nullable: true
        external_ticket_url:
          type: string
          format: uri
          nullable: true
        external_handoff_failure_summary:
          type: string
          nullable: true
        has_external_link:
          type: boolean
        has_failure:
          type: boolean