openapi: 3.0.3
info:
  title: TenantPilot Admin/System — Workspace Entitlements Foundation (Conceptual)
  version: 0.1.0
  description: |
    Conceptual contract for the workspace-first entitlement foundation.

    NOTE: These routes are implemented as existing Filament pages, widgets,
    resources, and Livewire-backed actions. The exact Livewire payload shape is
    not part of this contract. This file captures the user-visible routes,
    logical action boundaries, and the required 404 / 403 / business-state
    blocking semantics for the first slice.
servers:
  - url: /admin
  - url: /system
paths:
  /settings/workspace:
    get:
      summary: View workspace entitlement settings
      description: |
        Renders the existing workspace settings singleton page with one new
        entitlement section.

        Behavior:
        - No workspace selected: redirect to `/admin/choose-workspace`
        - Non-member or wrong workspace: 404
        - Workspace member without `workspace_settings.view`: 403
        - Authorized member: render plan profile, effective entitlements,
          source labels, rationale, and current usage summary
      responses:
        '200':
          description: Workspace settings page rendered
          content:
            text/html:
              schema:
                type: string
          x-logical-view-model:
            $ref: '#/components/schemas/WorkspaceEntitlementSettingsView'
        '302':
          description: Redirect to choose-workspace when no workspace is active
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /settings/workspace/actions/save-entitlements:
    post:
      summary: Save plan profile and explicit entitlement overrides
      description: |
        Conceptual contract for the existing singleton settings save action.
        The save reuses existing workspace-setting persistence and audit logging.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WorkspaceEntitlementSettingsCommand'
      responses:
        '204':
          description: Settings saved successfully
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/ValidationError'
  /settings/workspace/actions/reset-entitlement-override/{entitlementKey}:
    post:
      summary: Reset one explicit entitlement override and rationale
      description: |
        Conceptual contract for a confirmation-protected override reset action.
        Resetting returns effective truth to the selected plan profile or the
        code-owned default profile.
      parameters:
        - $ref: '#/components/parameters/EntitlementKey'
      responses:
        '204':
          description: Override reset successfully
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /onboarding/{onboardingDraft}:
    get:
      summary: View onboarding workflow with entitlement-aware completion state
      description: |
        Renders the existing managed-tenant onboarding wizard. The completion
        step must include managed-tenant activation entitlement truth.
      parameters:
        - $ref: '#/components/parameters/OnboardingDraftId'
      responses:
        '200':
          description: Onboarding wizard rendered
          content:
            text/html:
              schema:
                type: string
          x-logical-view-model:
            $ref: '#/components/schemas/OnboardingEntitlementView'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /onboarding/{onboardingDraft}/actions/complete:
    post:
      summary: Complete onboarding when entitlement and existing readiness allow
      description: |
        Conceptual contract for the existing confirmation-protected completion
        action. The entitlement gate must run before any tenant activation
        mutation occurs.
      parameters:
        - $ref: '#/components/parameters/OnboardingDraftId'
      responses:
        '204':
          description: Onboarding completed
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/BusinessStateBlocked'
  /review-packs/actions/generate:
    post:
      summary: Generate a review pack from the current tenant context
      description: |
        Conceptual contract for the tenant dashboard widget and review-pack list
        generate action family. Existing dedupe and queued-start behavior remain
        unchanged when entitlement allows execution.
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReviewPackGenerationCommand'
      responses:
        '202':
          description: Generation accepted or deduped through the existing flow
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/BusinessStateBlocked'
  /tenant-reviews/{tenantReview}/actions/export-executive-pack:
    post:
      summary: Export an executive pack from an existing tenant review
      description: |
        Conceptual contract for the review register and tenant review detail
        export action family. The entitlement gate must run before any new
        `ReviewPack` or `OperationRun` is created.
      parameters:
        - $ref: '#/components/parameters/TenantReviewId'
      responses:
        '202':
          description: Export accepted or deduped through the existing flow
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/BusinessStateBlocked'
  /review-packs/{reviewPack}/actions/regenerate:
    post:
      summary: Regenerate an existing review pack
      description: |
        Conceptual contract for the existing review-pack detail regenerate
        action. Existing confirmation and reuse behavior remain in place.
      parameters:
        - $ref: '#/components/parameters/ReviewPackId'
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReviewPackGenerationCommand'
      responses:
        '202':
          description: Regeneration accepted or deduped through the existing flow
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/BusinessStateBlocked'
  /directory/workspaces/{workspace}:
    get:
      summary: View read-only workspace entitlement summary in the system plane
      description: |
        Renders the existing system directory workspace detail page with a
        read-only entitlement summary.

        Behavior:
        - Platform user with `platform.directory.view`: 200
        - Platform user without that capability: 403
        - Wrong-plane or non-platform actor: 404 semantics at the panel boundary
      parameters:
        - $ref: '#/components/parameters/WorkspaceId'
      responses:
        '200':
          description: System workspace detail rendered
          content:
            text/html:
              schema:
                type: string
          x-logical-view-model:
            $ref: '#/components/schemas/SystemWorkspaceEntitlementView'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
components:
  parameters:
    WorkspaceId:
      name: workspace
      in: path
      required: true
      schema:
        type: integer
    OnboardingDraftId:
      name: onboardingDraft
      in: path
      required: true
      schema:
        type: integer
    TenantReviewId:
      name: tenantReview
      in: path
      required: true
      schema:
        type: integer
    ReviewPackId:
      name: reviewPack
      in: path
      required: true
      schema:
        type: integer
    EntitlementKey:
      name: entitlementKey
      in: path
      required: true
      schema:
        type: string
        enum:
          - managed_tenant_activation_limit
          - review_pack_generation_enabled
  responses:
    Forbidden:
      description: Member or platform user lacks the required capability in an already established scope
    NotFound:
      description: Wrong plane, non-member scope, or inaccessible record
    BusinessStateBlocked:
      description: Actor is otherwise authorized, but the workspace is not entitled for the requested action
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/EntitlementBlockResponse'
    ValidationError:
      description: Submitted entitlement settings failed validation
  schemas:
    WorkspaceEntitlementSettingsCommand:
      type: object
      required:
        - plan_profile
        - entitlements
      properties:
        plan_profile:
          type: string
          nullable: true
          description: Null means use the code-owned default profile
        entitlements:
          type: array
          items:
            $ref: '#/components/schemas/EntitlementOverrideInput'
    EntitlementOverrideInput:
      type: object
      required:
        - key
      properties:
        key:
          type: string
          enum:
            - managed_tenant_activation_limit
            - review_pack_generation_enabled
        override_value:
          oneOf:
            - type: integer
            - type: boolean
          nullable: true
        rationale:
          type: string
          nullable: true
    ReviewPackGenerationCommand:
      type: object
      properties:
        include_pii:
          type: boolean
        include_operations:
          type: boolean
    WorkspaceEntitlementSettingsView:
      type: object
      required:
        - workspace_id
        - effective_plan_profile
        - entitlements
        - primary_action
      properties:
        workspace_id:
          type: integer
        effective_plan_profile:
          $ref: '#/components/schemas/PlanProfileSummary'
        entitlements:
          type: array
          items:
            $ref: '#/components/schemas/WorkspaceEntitlementDecision'
        last_changed:
          $ref: '#/components/schemas/LastChangedAttribution'
          nullable: true
        primary_action:
          $ref: '#/components/schemas/NextAction'
    OnboardingEntitlementView:
      type: object
      required:
        - draft_id
        - completion_decision
      properties:
        draft_id:
          type: integer
        completion_decision:
          $ref: '#/components/schemas/WorkspaceEntitlementDecision'
        primary_action:
          $ref: '#/components/schemas/NextAction'
        blocked_reason:
          type: string
          nullable: true
    SystemWorkspaceEntitlementView:
      type: object
      required:
        - workspace_id
        - effective_plan_profile
        - entitlements
      properties:
        workspace_id:
          type: integer
        effective_plan_profile:
          $ref: '#/components/schemas/PlanProfileSummary'
        entitlements:
          type: array
          items:
            $ref: '#/components/schemas/WorkspaceEntitlementDecision'
        last_changed:
          $ref: '#/components/schemas/LastChangedAttribution'
          nullable: true
    PlanProfileSummary:
      type: object
      required:
        - id
        - label
      properties:
        id:
          type: string
        label:
          type: string
        description:
          type: string
          nullable: true
        source:
          type: string
          enum: [workspace_selection, code_default]
    WorkspaceEntitlementDecision:
      type: object
      required:
        - key
        - effective_value
        - source
        - is_blocked
      properties:
        key:
          type: string
          enum:
            - managed_tenant_activation_limit
            - review_pack_generation_enabled
        effective_value:
          oneOf:
            - type: integer
            - type: boolean
        source:
          type: string
          enum: [plan_profile_default, workspace_override]
        rationale:
          type: string
          nullable: true
        current_usage:
          type: integer
          nullable: true
        remaining_capacity:
          type: integer
          nullable: true
        is_blocked:
          type: boolean
        block_reason:
          type: string
          nullable: true
    LastChangedAttribution:
      type: object
      required:
        - at
        - by
      properties:
        at:
          type: string
          format: date-time
        by:
          type: string
    EntitlementBlockResponse:
      type: object
      required:
        - key
        - reason
      properties:
        key:
          type: string
        reason:
          type: string
        source:
          type: string
          enum: [plan_profile_default, workspace_override]
        current_usage:
          type: integer
          nullable: true
        effective_value:
          oneOf:
            - type: integer
            - type: boolean
    NextAction:
      type: object
      required:
        - label
        - kind
      properties:
        label:
          type: string
        kind:
          type: string
          enum:
            - save_entitlements
            - reset_override
            - complete_onboarding
            - generate_pack
            - export_executive_pack
            - regenerate_pack
            - open_admin_workspace
        action_name:
          type: string
          nullable: true
        url:
          type: string
          nullable: true