openapi: 3.0.3
info:
  title: Provider Foundation v1 (Internal)
  version: 1.0.0
  description: >
    Conceptual API contract for Provider Connections and Provider Operations.
    This is an internal planning artifact for the admin suite.

servers:
  - url: https://example.invalid

paths:
  /tenants/{tenantId}/provider-connections:
    get:
      summary: List provider connections
      parameters:
        - $ref: '#/components/parameters/TenantId'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/ProviderConnection'
    post:
      summary: Create provider connection
      parameters:
        - $ref: '#/components/parameters/TenantId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateProviderConnectionRequest'
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProviderConnection'
        '409':
          description: Duplicate connection
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

  /tenants/{tenantId}/provider-connections/{connectionId}:
    get:
      summary: Get provider connection
      parameters:
        - $ref: '#/components/parameters/TenantId'
        - $ref: '#/components/parameters/ConnectionId'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProviderConnection'
    patch:
      summary: Update provider connection (display, default, disable)
      parameters:
        - $ref: '#/components/parameters/TenantId'
        - $ref: '#/components/parameters/ConnectionId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateProviderConnectionRequest'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProviderConnection'

  /tenants/{tenantId}/provider-connections/{connectionId}/credentials:
    put:
      summary: Attach / rotate credentials (secret never returned)
      parameters:
        - $ref: '#/components/parameters/TenantId'
        - $ref: '#/components/parameters/ConnectionId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpsertCredentialsRequest'
      responses:
        '204':
          description: Updated

  /tenants/{tenantId}/provider-connections/{connectionId}/operations/health-check:
    post:
      summary: Start connection health check (OperationRun-backed)
      parameters:
        - $ref: '#/components/parameters/TenantId'
        - $ref: '#/components/parameters/ConnectionId'
      responses:
        '201':
          description: Run created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OperationRunRef'
        '200':
          description: Returned existing active run (dedupe)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OperationRunRef'
        '409':
          description: Scope busy (different operation already active for same scope)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScopeBusyResponse'

  /tenants/{tenantId}/provider-connections/{connectionId}/operations/inventory:
    post:
      summary: Start inventory collection (OperationRun-backed)
      parameters:
        - $ref: '#/components/parameters/TenantId'
        - $ref: '#/components/parameters/ConnectionId'
      responses:
        '201':
          description: Run created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OperationRunRef'
        '200':
          description: Returned existing active run (dedupe)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OperationRunRef'
        '409':
          description: Scope busy (different operation already active for same scope)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScopeBusyResponse'

  /tenants/{tenantId}/provider-connections/{connectionId}/operations/compliance-snapshot:
    post:
      summary: Start compliance snapshot (counts) (OperationRun-backed)
      parameters:
        - $ref: '#/components/parameters/TenantId'
        - $ref: '#/components/parameters/ConnectionId'
      responses:
        '201':
          description: Run created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OperationRunRef'
        '200':
          description: Returned existing active run (dedupe)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OperationRunRef'
        '409':
          description: Scope busy (different operation already active for same scope)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScopeBusyResponse'

components:
  parameters:
    TenantId:
      name: tenantId
      in: path
      required: true
      schema:
        type: integer
        format: int64
    ConnectionId:
      name: connectionId
      in: path
      required: true
      schema:
        type: string
        format: uuid

  schemas:
    ProviderConnection:
      type: object
      required:
        - id
        - tenant_id
        - provider
        - entra_tenant_id
        - display_name
        - is_default
        - status
        - health_status
      properties:
        id:
          type: string
          format: uuid
        tenant_id:
          type: integer
          format: int64
        provider:
          type: string
          enum: [microsoft]
        entra_tenant_id:
          type: string
          description: Entra tenant ID (GUID)
        display_name:
          type: string
        is_default:
          type: boolean
        status:
          type: string
          enum: [connected, needs_consent, error, disabled]
        health_status:
          type: string
          enum: [ok, degraded, down]
        last_health_check_at:
          type: string
          format: date-time
          nullable: true
        last_error_reason_code:
          type: string
          nullable: true
        last_error_message:
          type: string
          nullable: true

    CreateProviderConnectionRequest:
      type: object
      required:
        - provider
        - entra_tenant_id
        - display_name
      properties:
        provider:
          type: string
          enum: [microsoft]
        entra_tenant_id:
          type: string
        display_name:
          type: string
        is_default:
          type: boolean
          default: false

    UpdateProviderConnectionRequest:
      type: object
      properties:
        display_name:
          type: string
        is_default:
          type: boolean
        status:
          type: string
          enum: [connected, needs_consent, error, disabled]

    UpsertCredentialsRequest:
      type: object
      required:
        - type
        - client_id
        - client_secret
      properties:
        type:
          type: string
          enum: [client_secret]
        client_id:
          type: string
        client_secret:
          type: string
          format: password

    OperationRunRef:
      type: object
      required:
        - id
        - type
        - status
        - outcome
      properties:
        id:
          type: integer
          format: int64
        type:
          type: string
        status:
          type: string
        outcome:
          type: string
        view_url:
          type: string
          nullable: true

    ScopeBusyResponse:
      type: object
      required:
        - error
        - active_run
      properties:
        error:
          type: string
          enum: [scope_busy]
        message:
          type: string
        active_run:
          $ref: '#/components/schemas/OperationRunRef'

    ErrorResponse:
      type: object
      required:
        - error
      properties:
        error:
          type: string
        message:
          type: string
