openapi: 3.0.3 info: title: TenantPilot Admin/System - Workspace Commercial Lifecycle Overlay (Conceptual) version: 0.1.0 description: | Conceptual contract for the commercial lifecycle overlay that follows the existing workspace entitlement substrate from Spec 247. 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, the system/admin split, and the required 404 / 403 / business-state semantics. servers: - url: /admin - url: /system paths: /directory/workspaces/{workspace}: get: summary: View read-only workspace commercial lifecycle summary in the system plane description: | Renders the existing system directory workspace detail page with the effective lifecycle state, rationale, affected behavior summary, and the reused entitlement substrate summary. 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/SystemWorkspaceCommercialLifecycleView' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /directory/workspaces/{workspace}/actions/change-commercial-state: post: summary: Change the workspace commercial lifecycle state from the system plane description: | Conceptual contract for the confirmation-protected state-change action on the existing system workspace detail page. Behavior: - Platform user with directory visibility but without the dedicated lifecycle-manage capability: 403 - Wrong plane or non-platform actor: 404 semantics at the panel boundary - Authorized platform user: state and rationale are written through the existing workspace settings audit path parameters: - $ref: '#/components/parameters/WorkspaceId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ChangeCommercialLifecycleCommand' responses: '204': description: Commercial lifecycle state changed successfully '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '422': $ref: '#/components/responses/ValidationError' /onboarding/{onboardingDraft}: get: summary: View onboarding workflow with lifecycle-aware completion state description: | Renders the existing managed-tenant onboarding wizard. The completion step must include the commercial lifecycle outcome after the underlying entitlement substrate has been evaluated. parameters: - $ref: '#/components/parameters/OnboardingDraftId' responses: '200': description: Onboarding wizard rendered content: text/html: schema: type: string x-logical-view-model: $ref: '#/components/schemas/OnboardingCommercialLifecycleView' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /onboarding/{onboardingDraft}/actions/complete: post: summary: Complete onboarding when entitlement, lifecycle state, and existing readiness all allow 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 and review-pack list start action family. Behavior ordering: 1. authorization 2. underlying entitlement substrate decision 3. lifecycle overlay decision 4. existing dedupe / queued-start flow when allowed A lifecycle-blocked attempt is future-start-only in this slice: it creates no new `ReviewPack`, creates no new `OperationRun`, emits no queued or terminal review-pack notification, and does not affect any review-pack work that was already queued or running. 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 lifecycle overlay must block before any new `ReviewPack` or `OperationRun` is created, emit no queued or terminal review-pack notification for the blocked attempt, and leave any already-created queued or running review-pack work unchanged. 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 dedupe behavior remain in place when the lifecycle overlay allows the start. A lifecycle-blocked attempt is future-start-only: it creates no new `ReviewPack`, creates no new `OperationRun`, emits no queued or terminal review-pack notification, and leaves any already-created queued or running review-pack work unchanged. 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' /tenant-reviews/{tenantReview}: get: summary: View existing tenant review while the workspace may be suspended read-only parameters: - $ref: '#/components/parameters/TenantReviewId' responses: '200': description: Existing tenant review rendered when current RBAC allows it content: text/html: schema: type: string x-logical-view-model: $ref: '#/components/schemas/PreservedReadOnlyView' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /review-packs/{reviewPack}: get: summary: View existing review pack while the workspace may be suspended read-only parameters: - $ref: '#/components/parameters/ReviewPackId' responses: '200': description: Existing review pack rendered when current RBAC allows it content: text/html: schema: type: string x-logical-view-model: $ref: '#/components/schemas/PreservedReadOnlyView' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /review-packs/{reviewPack}/download: get: summary: Download an already-generated review pack while the workspace may be suspended read-only parameters: - $ref: '#/components/parameters/ReviewPackId' responses: '200': description: Existing generated pack download is still available when current RBAC allows it '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /evidence-snapshots/{evidenceSnapshot}: get: summary: View existing evidence snapshot while the workspace may be suspended read-only parameters: - $ref: '#/components/parameters/EvidenceSnapshotId' responses: '200': description: Existing evidence snapshot rendered when current RBAC allows it content: text/html: schema: type: string x-logical-view-model: $ref: '#/components/schemas/PreservedReadOnlyView' '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 EvidenceSnapshotId: name: evidenceSnapshot in: path required: true schema: type: integer responses: Forbidden: description: Established-scope actor lacks the required capability NotFound: description: Wrong plane, non-member scope, or inaccessible record BusinessStateBlocked: description: Actor is otherwise authorized, but the workspace commercial state or underlying entitlement substrate blocks the requested action content: application/json: schema: $ref: '#/components/schemas/CommercialLifecycleBlockResponse' ValidationError: description: Submitted commercial lifecycle state change failed validation schemas: ChangeCommercialLifecycleCommand: type: object required: - state - reason properties: state: $ref: '#/components/schemas/CommercialLifecycleState' reason: type: string description: Required for every explicit lifecycle state change, including an explicit return to active_paid. minLength: 1 maxLength: 500 CommercialLifecycleState: type: string enum: - trial - grace - active_paid - suspended_read_only ReviewPackGenerationCommand: type: object properties: include_pii: type: boolean include_operations: type: boolean SystemWorkspaceCommercialLifecycleView: type: object required: - workspace_id - lifecycle - affected_behaviors properties: workspace_id: type: integer lifecycle: $ref: '#/components/schemas/CommercialLifecycleDecision' affected_behaviors: type: array items: $ref: '#/components/schemas/CommercialLifecycleActionDecision' entitlement_substrate: type: object description: Existing Spec 247 workspace entitlement summary reused for context primary_action: $ref: '#/components/schemas/NextAction' nullable: true OnboardingCommercialLifecycleView: type: object required: - onboarding_draft_id - action_decision properties: onboarding_draft_id: type: integer action_decision: $ref: '#/components/schemas/CommercialLifecycleActionDecision' entitlement_substrate: type: object nullable: true CommercialLifecycleDecision: type: object required: - state - label - source - source_label properties: state: $ref: '#/components/schemas/CommercialLifecycleState' label: type: string source: type: string enum: - default_active_paid - workspace_setting source_label: type: string description: Rendered source label from the shared lifecycle source mapping used by system detail surfaces. rationale: type: string nullable: true last_changed_at: type: string format: date-time nullable: true last_changed_by: type: string nullable: true CommercialLifecycleActionDecision: type: object required: - action_key - outcome - lifecycle_state properties: action_key: type: string enum: - managed_tenant_activation - review_pack_start - review_history_read - evidence_read - generated_pack_read outcome: type: string enum: - allow - warn - block - allow_read_only reason_family: type: string nullable: true enum: - commercial_lifecycle - entitlement_substrate message: type: string nullable: true lifecycle_state: $ref: '#/components/schemas/CommercialLifecycleState' underlying_entitlement_key: type: string nullable: true CommercialLifecycleBlockResponse: type: object required: - reason_family - message properties: reason_family: type: string enum: - commercial_lifecycle - entitlement_substrate lifecycle_state: $ref: '#/components/schemas/CommercialLifecycleState' nullable: true message: type: string PreservedReadOnlyView: type: object required: - read_only_access_preserved properties: read_only_access_preserved: type: boolean enum: [true] lifecycle_state: $ref: '#/components/schemas/CommercialLifecycleState' message: type: string nullable: true description: Optional calm explanation that the workspace is suspended read-only while current history access remains available NextAction: type: object required: - label properties: label: type: string enabled: type: boolean reason: type: string nullable: true