openapi: 3.0.3 info: title: TenantPilot Admin/System - Workspace Billing & Subscription Truth (Conceptual) version: 0.1.0 description: | Conceptual contract for the bounded billing and subscription truth follow-through over existing entitlement and commercial lifecycle foundations. NOTE: These routes are implemented as existing Filament pages, resources, widgets, and Livewire-backed actions. Exact Livewire payload shapes are not part of this contract. This file captures logical route boundaries, plane separation, and the requirement that runtime gating still flows through the shared commercial lifecycle resolver. paths: /directory/workspaces/{workspace}: servers: - url: /system get: summary: View current subscription truth and derived commercial posture in the system plane 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/SystemWorkspaceSubscriptionView' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /directory/workspaces/{workspace}/actions/update-subscription-truth: servers: - url: /system post: summary: Create or update the current workspace subscription truth from the system plane description: | Conceptual contract for the confirmation-protected system action that creates or updates one current workspace subscription record. Behavior: - Platform user with directory visibility but without the dedicated commercial-management capability: 403 - Wrong plane or non-platform actor: 404 semantics at the panel boundary - Authorized platform user: writes the current subscription record and audit trail, then updates the derived lifecycle source used by current onboarding and review-pack flows parameters: - $ref: '#/components/parameters/WorkspaceId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateSubscriptionTruthCommand' responses: '204': description: Current subscription truth updated successfully '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '422': $ref: '#/components/responses/ValidationError' /directory/workspaces/{workspace}/actions/change-commercial-state: servers: - url: /system post: summary: Change the fallback manual commercial lifecycle state when no subscription record exists description: | Conceptual contract for the existing manual lifecycle action after this slice lands. Behavior: - available only when the workspace has no current subscription record - remains confirmation-protected - preserves the current settings-backed fallback semantics from Spec 251 parameters: - $ref: '#/components/parameters/WorkspaceId' requestBody: required: true content: application/json: schema: type: object required: - state - reason properties: state: type: string reason: type: string responses: '204': description: Fallback lifecycle state changed successfully '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': description: Current subscription truth exists, so fallback mutation is unavailable /settings/workspace: servers: - url: /admin get: summary: View a read-only subscription-backed commercial summary on the admin workspace settings page responses: '200': description: Workspace settings page rendered content: text/html: schema: type: string x-logical-view-model: $ref: '#/components/schemas/SettingsSubscriptionSummaryView' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /onboarding/{onboardingDraft}: servers: - url: /admin get: summary: View onboarding workflow with subscription-backed lifecycle gating when a subscription exists parameters: - $ref: '#/components/parameters/OnboardingDraftId' responses: '200': description: Onboarding wizard rendered content: text/html: schema: type: string x-logical-view-model: $ref: '#/components/schemas/LifecycleDecisionView' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /onboarding/{onboardingDraft}/actions/complete: servers: - url: /admin post: summary: Complete onboarding when entitlement substrate and derived lifecycle both allow it 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: servers: - url: /admin post: summary: Generate a review pack through the existing shared lifecycle gate description: | Behavior ordering: 1. authorization 2. underlying entitlement substrate decision 3. derived lifecycle decision, potentially sourced from current subscription truth 4. existing dedupe or queued-start flow when allowed A blocked attempt creates no new `ReviewPack`, creates no new `OperationRun`, and emits no queued or terminal review-pack notification. 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: servers: - url: /admin post: summary: Export an executive pack through the existing shared lifecycle gate 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: servers: - url: /admin post: summary: Regenerate a review pack through the existing shared lifecycle gate parameters: - $ref: '#/components/parameters/ReviewPackId' 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' 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 responses: Forbidden: description: Actor is in-scope but missing the required capability NotFound: description: Wrong plane or non-member access is hidden as not found ValidationError: description: Submitted subscription truth is invalid for the chosen state BusinessStateBlocked: description: The actor is otherwise authorized, but the derived lifecycle blocks the action schemas: UpdateSubscriptionTruthCommand: oneOf: - $ref: '#/components/schemas/TrialSubscriptionCommand' - $ref: '#/components/schemas/ActiveSubscriptionCommand' - $ref: '#/components/schemas/PastDueSubscriptionCommand' - $ref: '#/components/schemas/CancelAtPeriodEndSubscriptionCommand' - $ref: '#/components/schemas/EndedSubscriptionCommand' TrialSubscriptionCommand: type: object required: - state - trial_ends_at - status_reason properties: state: type: string enum: - trial billing_reference: type: string nullable: true trial_ends_at: type: string format: date-time status_reason: type: string ActiveSubscriptionCommand: type: object required: - state - current_period_starts_at - current_period_ends_at - status_reason properties: state: type: string enum: - active billing_reference: type: string nullable: true current_period_starts_at: type: string format: date-time current_period_ends_at: type: string format: date-time status_reason: type: string PastDueSubscriptionCommand: type: object required: - state - current_period_starts_at - current_period_ends_at - status_reason properties: state: type: string enum: - past_due billing_reference: type: string nullable: true current_period_starts_at: type: string format: date-time current_period_ends_at: type: string format: date-time status_reason: type: string CancelAtPeriodEndSubscriptionCommand: type: object required: - state - current_period_starts_at - current_period_ends_at - status_reason properties: state: type: string enum: - cancel_at_period_end billing_reference: type: string nullable: true current_period_starts_at: type: string format: date-time current_period_ends_at: type: string format: date-time status_reason: type: string EndedSubscriptionCommand: type: object required: - state - current_period_ends_at - status_reason properties: state: type: string enum: - ended billing_reference: type: string nullable: true current_period_ends_at: type: string format: date-time status_reason: type: string WorkspaceSubscriptionSummary: type: object required: - source - fallback_status - subscription_present - derived_lifecycle_state - needs_review properties: source: type: string enum: - workspace_subscription - workspace_setting - default_active_paid fallback_status: type: boolean subscription_present: type: boolean state: type: string nullable: true label: type: string nullable: true billing_reference: type: string nullable: true status_reason: type: string nullable: true key_date_label: type: string nullable: true key_date: type: string format: date-time nullable: true needs_review: type: boolean derived_lifecycle_state: type: string SystemWorkspaceSubscriptionView: allOf: - $ref: '#/components/schemas/WorkspaceSubscriptionSummary' - type: object properties: last_changed_at: type: string format: date-time nullable: true last_changed_by: type: string nullable: true SettingsSubscriptionSummaryView: type: object required: - source - derived_lifecycle_state - fallback_status - state_label - explanation properties: source: type: string enum: - workspace_subscription - workspace_setting - default_active_paid derived_lifecycle_state: type: string state_label: type: string explanation: type: string fallback_status: type: boolean key_date_label: type: string nullable: true key_date: type: string format: date-time nullable: true LifecycleDecisionView: type: object required: - lifecycle_state - source - outcome - explanation properties: lifecycle_state: type: string source: type: string enum: - workspace_subscription - workspace_setting - default_active_paid outcome: type: string enum: - allow - warn - block explanation: type: string ReviewPackGenerationCommand: type: object additionalProperties: true