Some checks failed
Main Confidence / confidence (push) Failing after 1m45s
## Summary - add the bounded workspace commercial lifecycle overlay from spec 251 on top of the existing entitlement substrate - expose audited commercial state inspection and mutation on the system workspace detail surface - gate onboarding activation and review-pack start actions through the shared lifecycle decision while preserving suspended read-only access to existing review, evidence, and generated-pack history - add focused Pest coverage plus the spec/plan/tasks/data-model/contract artifacts for the feature ## Validation - targeted Pest unit and feature lanes for lifecycle resolution, system-plane mutation, onboarding gating, review-pack enforcement, download preservation, customer review workspace access, and evidence snapshot access - `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent` - integrated browser smoke on the system workspace detail and the preserved read-only review/evidence/review-pack surfaces ## Notes - branch: `251-commercial-entitlements-billing-state` - base: `dev` - commit: `606e9760` Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #292
465 lines
15 KiB
YAML
465 lines
15 KiB
YAML
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 |