TenantAtlas/specs/251-commercial-entitlements-billing-state/plan.md
ahmido 7ee4909212
Some checks failed
Main Confidence / confidence (push) Failing after 1m45s
feat: commercial lifecycle overlay for workspace entitlements (#292)
## 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
2026-04-28 13:39:33 +00:00

33 KiB

Implementation Plan: Commercial Entitlements and Billing-State Maturity

Branch: 251-commercial-entitlements-billing-state | Date: 2026-04-28 | Spec: /Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/251-commercial-entitlements-billing-state/spec.md Input: Feature specification from /Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/251-commercial-entitlements-billing-state/spec.md

Note: This template is filled in by the /speckit.plan command. See .specify/scripts/ for helper scripts.

Summary

  • Layer one bounded workspace commercial lifecycle overlay on top of the already-real Spec 247 entitlement substrate, not beside it. The existing WorkspaceEntitlementResolver remains canonical for plan/default/override truth, and the new slice adds one explicit lifecycle state plus action-family outcomes for onboarding activation, review-pack start, and preserved read-only history access.
  • Keep mutation narrow and platform-owned: persist lifecycle state through the existing workspace settings infrastructure, expose inspection plus state change from the existing system workspace detail surface, and keep /admin limited to contextual allow, warn, or block messaging on onboarding and review-pack surfaces.
  • Preserve current review/evidence/download truth while suspended. New lifecycle blocking must stop future onboarding activation and future review-pack starts before any tenant mutation, ReviewPack, or OperationRun creation, while leaving already-generated history and evidence consumption under current RBAC intact.

Technical Context

Language/Version: PHP 8.4 (Laravel 12)
Primary Dependencies: Filament v5 + Livewire v4, existing workspace settings stack (SettingsRegistry, SettingsResolver, SettingsWriter), WorkspaceEntitlementResolver, ReviewPackService, system directory detail page
Storage: PostgreSQL via existing workspace_settings rows plus existing audit log records; no new table or billing/account model
Testing: Pest unit and feature tests via Laravel Sail
Validation Lanes: fast-feedback, confidence
Target Platform: Monorepo Laravel web application in apps/platform, using existing Filament admin and system panels
Project Type: web
Performance Goals: Reuse existing settings reads and current workspace aggregates only, add no new external calls during render, keep review-pack dedupe and shared run UX unchanged when allowed, and short-circuit blocked review-pack starts before any ReviewPack or OperationRun write
Constraints: One commercial lifecycle overlay only, four bounded states, two real gated behavior families, preserved authorized read-only history/evidence/download access while suspended, explicit /admin vs /system separation, no payment provider/invoice/checkout/website/broad billing-engine scope
Scale/Scope: One bounded lifecycle resolver, one system-plane mutation surface, one platform capability addition, one onboarding gate, one review-pack action-family gate, and focused lifecycle/read-only test coverage

Filament v5 / Panel Notes

  • Livewire v4.0+ compliance: The slice stays inside existing Filament v5 pages, widgets, resources, and Livewire-backed actions. No Livewire v3 assumptions or compatibility work are introduced.
  • Provider registration location: No panel/provider registration changes are planned. Existing Laravel 12 + Filament provider registration remains in bootstrap/providers.php.
  • Global search: No new globally searchable resource is introduced. Current global-search behavior remains unchanged.
  • Destructive and high-impact actions: The future Change commercial state action on the system workspace detail page must use ->requiresConfirmation(), require platform authorization, and write audit history. The Suspended / read-only transition is the only high-risk path in scope. Review-pack and onboarding blocks remain non-destructive business-state responses, not hidden authorization failures.
  • Asset strategy: No new panel or shared assets are planned. Deployment remains unchanged, including cd apps/platform && php artisan filament:assets when registered Filament assets are deployed elsewhere in the product.

UI / Surface Guardrail Plan

  • Guardrail scope: changed surfaces
  • Native vs custom classification summary: mixed
  • Shared-family relevance: system detail controls, status messaging, onboarding helper text, review-pack action gating, review/evidence viewer messaging
  • State layers in scope: page, detail
  • Audience modes in scope: operator-MSP, support-platform, customer/read-only
  • Decision/diagnostic/raw hierarchy plan: decision-first on the system workspace detail surface and on the immediate onboarding/review-pack action context; diagnostics-second via the existing entitlement substrate and review/run/history context; no new raw/support payload surface is planned
  • Raw/support gating plan: capability-gated system-plane inspection only; customer/read-only surfaces remain calm and evidence-first
  • One-primary-action / duplicate-truth control: /system/directory/workspaces/{workspace} remains the only mutation surface; onboarding and review-pack surfaces show only the local lifecycle consequence required for the immediate action; suspended read-only history pages do not restate the whole commercial profile
  • Handling modes by drift class or surface: review-mandatory because one lifecycle vocabulary must stay consistent across system, onboarding, review-pack, and read-only history surfaces
  • Repository-signal treatment: review-mandatory
  • Special surface test profiles: standard-native-filament, shared-detail-family, monitoring-state-page
  • Required tests or manual smoke: functional-core, state-contract
  • Exception path and spread control: no second admin-plane commercial mutation surface, no page-local lifecycle labels, and no broad suspension sweep across unrelated mutable surfaces
  • Active feature PR close-out entry: Guardrail

Shared Pattern & System Fit

  • Cross-cutting feature marker: yes
  • Systems touched: SettingsRegistry, SettingsResolver, SettingsWriter, existing workspace-setting audit path, WorkspaceEntitlementResolver, WorkspaceSettings as the current entitlement substrate reference, App\Filament\System\Pages\Directory\ViewWorkspace, ManagedTenantOnboardingWizard, ReviewPackService, TenantReviewPackCard, ReviewRegister, TenantReviewResource, ReviewPackResource, CustomerReviewWorkspace, EvidenceSnapshotResource, and WorkspaceEntitlementBlockedException
  • Shared abstractions reused: WorkspaceEntitlementResolver, WorkspacePlanProfileCatalog, SettingsResolver, SettingsWriter, current workspace audit logging, ReviewPackService, OperationUxPresenter, OperationRunLinks, Capabilities, PlatformCapabilities, and existing Filament action/resource surfaces
  • New abstraction introduced? why?: one bounded WorkspaceCommercialLifecycleResolver is justified because the existing entitlement resolver answers per-key entitlement truth but does not express one workspace-wide lifecycle posture with action-family outcomes, preserved read-only semantics, or system/admin messaging
  • Why the existing abstraction was sufficient or insufficient: Spec 247 already provides canonical entitlement substrate truth and must remain the foundation. It is insufficient for trial, grace, active_paid, and suspended_read_only because those states cut across more than one entitlement key and need one central business-state explanation
  • Bounded deviation / spread control: no page-local lifecycle conditionals and no second exception taxonomy by default; prefer reusing the existing blocked decision payload/catch path for review-pack actions unless implementation proves that the current class name or payload cannot carry lifecycle metadata cleanly

OperationRun UX Impact

  • Touches OperationRun start/completion/link UX?: yes
  • Central contract reused: existing shared review-pack OperationRun start UX through ReviewPackService, OperationUxPresenter, and OperationRunLinks
  • Delegated UX behaviors: queued toast, run link, run-enqueued browser event, dedupe messaging, and existing terminal notifications remain unchanged when review-pack generation is allowed; lifecycle-blocked starts create no OperationRun, no queued DB notification, and no terminal notification
  • Surface-owned behavior kept local: onboarding completion helper text, review-pack tooltips/disabled state, and suspended read-only explanation on history surfaces remain local projections of the central lifecycle decision
  • Queued DB-notification policy: unchanged explicit opt-in only
  • Terminal notification path: unchanged central lifecycle mechanism for existing review-pack runs only
  • Exception path: none planned; lifecycle blocking must happen before ReviewPackService creates or reuses a ReviewPack or OperationRun, and the preferred later implementation is to extend the current blocked-decision payload rather than invent a second parallel business-state exception family

Provider Boundary & Portability Fit

  • Shared provider/platform boundary touched?: no
  • Provider-owned seams: N/A
  • Platform-core seams: workspace commercial lifecycle vocabulary, lifecycle rationale, action-family outcomes, system/admin messaging, and audit semantics
  • Neutral platform terms / contracts preserved: workspace, trial, grace, active paid, suspended / read-only, commercial state, review pack, managed tenant activation
  • Retained provider-specific semantics and why: none; review-pack generation stays provider-backed operationally, but the new lifecycle vocabulary remains platform-core and provider-neutral
  • Bounded extraction or follow-up path: none

Constitution Check

GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.

  • Inventory-first: PASS - the slice adds workspace-owned business state, not new inventory or backup truth.
  • Read/write separation: PASS - the only new write is a confirmation-protected, audited system-plane lifecycle mutation using existing workspace settings persistence.
  • Graph contract path: PASS - no new Microsoft Graph path is introduced.
  • Deterministic capabilities: PASS - admin-plane capabilities remain unchanged, and any new platform capability stays registry-backed.
  • RBAC-UX: PASS - /admin and /system remain separated; wrong-plane and non-member access stay 404; member-without-capability stays 403; otherwise-authorized actors get a business-state block or warning instead of authorization failure.
  • Workspace isolation: PASS - admin-plane contextual behavior still requires established workspace context.
  • RBAC-UX destructive confirmation: PASS - the future system-plane state-change action must require confirmation and rationale.
  • RBAC-UX global search: PASS - no new searchable resource or search scope is introduced.
  • Tenant isolation: PASS - onboarding, review-pack, review history, evidence, and download surfaces remain tenant-safe.
  • Run observability: PASS - review-pack generation keeps the existing OperationRun path when allowed, and blocked starts stop before run creation.
  • OperationRun start UX: PASS - the plan preserves shared review-pack start UX and inserts lifecycle blocking before run creation.
  • Ops-UX 3-surface feedback: PASS - existing feedback stays toast + progress surfaces + terminal notification only when a run exists.
  • Ops-UX lifecycle: PASS - no new OperationRun lifecycle contract is introduced.
  • Ops-UX summary counts: N/A - no summary_counts shape change is planned.
  • Ops-UX guards: N/A - no new run guard family is planned in the planning slice.
  • Ops-UX system runs: N/A - initiator-null behavior is unchanged.
  • Automation: N/A - no new queued or scheduled workflow family is introduced.
  • Data minimization: PASS - no payment payloads, account records, or provider secrets are introduced.
  • Test governance (TEST-GOV-001): PASS - the plan stays in focused unit + feature lanes with explicit proof commands and limited fixture growth.
  • Proportionality (PROP-001): PASS - persistence stays in existing settings rows, and the only new structural element is one bounded lifecycle overlay.
  • No premature abstraction (ABSTR-001): PASS - no interface, registry, strategy system, or framework is planned; only one local resolver is added because multiple real surfaces already need the same lifecycle decision.
  • Persisted truth (PERSIST-001): PASS - no new table or durable artifact is introduced.
  • Behavioral state (STATE-001): PASS - grace and suspended_read_only create distinct action-family consequences immediately, and trial remains justified because it is part of the explicit platform-managed commercial posture and audit workflow even though its two in-scope gated families currently match active_paid.
  • UI semantics (UI-SEM-001): PASS - the plan prefers direct mapping from lifecycle truth to helper text and badges instead of a new presentation framework.
  • Shared pattern first (XCUT-001): PASS - system detail, onboarding, review-pack, and read-only history surfaces all reuse the existing substrate and shared run path first.
  • Provider boundary (PROV-001): PASS - the new vocabulary is platform-core, not Microsoft-shaped.
  • V1 explicitness / few layers (V1-EXP-001, LAYER-001): PASS - one explicit state family plus one thin overlay resolver is the narrowest viable shape.
  • Spec discipline / bloat check (SPEC-DISC-001, BLOAT-001): PASS - the plan keeps the whole lifecycle overlay in one coherent spec and includes proportionality review below.
  • Badge semantics (BADGE-001): PASS - any future lifecycle badge must reuse shared badge semantics or stay plain text; no page-local color taxonomy is planned.
  • Filament-native UI (UI-FIL-001): PASS - the slice extends existing Filament pages, resources, widgets, and the current system Blade page.
  • Filament-native UI local Blade/Tailwind: PASS - the existing system Blade view remains the only custom-rendered surface in scope and must preserve current Filament visual language.
  • UI/UX surface taxonomy (UI-CONST-001 / UI-SURF-001): PASS - existing system detail, guided onboarding, action family, and read-only viewer surface types remain intact.
  • Decision-first operating model (DECIDE-001): PASS - system workspace detail is primary, onboarding/review-pack surfaces stay contextual, and read-only history/evidence pages remain tertiary evidence/diagnostics.
  • Audience-aware disclosure (DECIDE-AUD-001 / OPSURF-001): PASS - system detail stays platform/support-facing, admin action gates stay operator-first, and suspended read-only pages keep customer-safe history access without raw platform diagnostics.
  • UI/UX inspect model (UI-HARD-001): PASS - no duplicate inspect affordances are added.
  • UI/UX action hierarchy (UI-HARD-001 / UI-EX-001): PASS - the plan keeps one system mutation action and existing onboarding/review-pack primary actions in place.
  • UI/UX scope, truth, and naming (UI-HARD-001 / UI-NAMING-001 / OPSURF-001): PASS - labels remain narrow and billing-provider-free.
  • UI/UX placeholder ban (UI-HARD-001): PASS - no empty action groups are planned.
  • UI naming (UI-NAMING-001): PASS - primary labels stay Change commercial state, Complete onboarding, Generate pack, Regenerate, and Export executive pack.
  • Operator surfaces (OPSURF-001): PASS - mutation scope remains explicit, and /admin surfaces only show contextual lifecycle truth.
  • Operator surface page contract: PASS - the spec already defines the required surface contracts.
  • Filament UI Action Surface Contract: PASS - touched surfaces already have contracts or exemptions; the plan preserves them while adding lifecycle truth.
  • Filament UI UX-001 (Layout & IA): PASS - no new page shell or panel is introduced.
  • Action-surface discipline (ACTSURF-001 / HDR-001): PASS - one system primary action and existing onboarding/review-pack action families remain the only primary mutations in scope.
  • UI review workflow: PASS - guardrail, shared-family, and exception posture remain explicit in this plan.

Test Governance Check

  • Test purpose / classification by changed surface: Unit for the bounded lifecycle overlay and behavior matrix; Feature for system-plane mutation, onboarding activation gating, review-pack start blocking, and preserved suspended read-only consumption
  • Affected validation lanes: fast-feedback, confidence
  • Why this lane mix is the narrowest sufficient proof: the business risk is deterministic decision ordering plus existing Filament/Livewire and service entry points. Browser or heavy-governance coverage would add cost without proving additional current-release risk for this bounded overlay.
  • Narrowest proving command(s):
    • export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/Entitlements/WorkspaceCommercialLifecycleResolverTest.php
    • export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/System/ViewWorkspaceEntitlementsTest.php tests/Feature/System/Spec113/AuthorizationSemanticsTest.php tests/Feature/Onboarding/ManagedTenantOnboardingEntitlementTest.php tests/Feature/Onboarding/OnboardingRbacSemanticsTest.php
    • export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/ReviewPack/ReviewPackEntitlementEnforcementTest.php tests/Feature/ReviewPack/ReviewPackGenerationTest.php tests/Feature/ReviewPack/ReviewPackDownloadTest.php tests/Feature/Reviews/CustomerReviewWorkspacePageTest.php tests/Feature/Reviews/CustomerReviewWorkspacePackAccessTest.php tests/Feature/Evidence/EvidenceSnapshotResourceTest.php
  • Fixture / helper / factory / seed / context cost risks: limited to workspace, platform user, workspace member, onboarding draft, tenant, existing review pack, tenant review, and evidence snapshot fixtures
  • Expensive defaults or shared helper growth introduced?: no - implementation should reuse existing factories and opt-in tenant/review/evidence helpers only
  • Heavy-family additions, promotions, or visibility changes: none
  • Surface-class relief / special coverage rule: standard-native relief for system detail and onboarding; monitoring-state-page proof for no new run creation; shared-detail-family proof for preserved view/download access while suspended
  • Closing validation and reviewer handoff: rerun the exact targeted commands above, verify 404 vs 403 vs business-state outcomes separately, verify system detail source labels remain consistent, verify blocked review-pack starts create no new ReviewPack or OperationRun and emit no queued or terminal notification, verify already queued or running review-pack runs continue unaffected after later suspension, and verify suspended workspaces still allow authorized review/evidence/download access
  • Budget / baseline / trend follow-up: none expected beyond ordinary feature-local growth
  • Review-stop questions: does the state vocabulary stay narrow enough, does the system/admin split remain intact, does suspended read-only coverage avoid broad mutation-sweep scope, and does the blocked-decision transport avoid a second exception framework
  • Escalation path: document-in-feature if only payload wording or helper reuse needs adjustment; follow-up-spec only if the overlay starts pulling unrelated mutable surfaces into suspension logic
  • Active feature PR close-out entry: Guardrail
  • Why no dedicated follow-up spec is needed: the testing cost stays local to one overlay resolver and a small set of existing pages/services/resources; no new browser or heavy-governance harness is justified

Project Structure

Documentation (this feature)

specs/251-commercial-entitlements-billing-state/
├── plan.md
├── research.md
├── data-model.md
├── quickstart.md
├── contracts/
│   └── workspace-commercial-lifecycle-overlay.logical.openapi.yaml
├── checklists/
│   └── requirements.md
└── tasks.md             # Created later by /speckit.tasks, not by this plan step

Source Code (repository root)

apps/platform/
├── app/
│   ├── Exceptions/Entitlements/WorkspaceEntitlementBlockedException.php
│   ├── Filament/
│   │   ├── Pages/
│   │   │   ├── Reviews/CustomerReviewWorkspace.php
│   │   │   ├── Reviews/ReviewRegister.php
│   │   │   ├── Settings/WorkspaceSettings.php
│   │   │   └── Workspaces/ManagedTenantOnboardingWizard.php
│   │   ├── Resources/
│   │   │   ├── EvidenceSnapshotResource.php
│   │   │   ├── EvidenceSnapshotResource/Pages/ViewEvidenceSnapshot.php
│   │   │   ├── ReviewPackResource.php
│   │   │   ├── ReviewPackResource/Pages/ViewReviewPack.php
│   │   │   ├── TenantReviewResource.php
│   │   │   └── TenantReviewResource/Pages/ViewTenantReview.php
│   │   ├── System/Pages/Directory/ViewWorkspace.php
│   │   └── Widgets/Tenant/TenantReviewPackCard.php
│   ├── Models/WorkspaceSetting.php
│   ├── Services/
│   │   ├── Entitlements/WorkspaceCommercialLifecycleResolver.php   # likely new bounded overlay service
│   │   ├── Entitlements/WorkspaceEntitlementResolver.php
│   │   ├── ReviewPackService.php
│   │   └── Settings/
│   │       ├── SettingsResolver.php
│   │       └── SettingsWriter.php
│   ├── Support/
│   │   ├── Auth/Capabilities.php
│   │   ├── Auth/PlatformCapabilities.php
│   │   └── Settings/SettingsRegistry.php
├── resources/views/filament/system/pages/directory/view-workspace.blade.php
└── tests/
    ├── Feature/
    └── Unit/

Structure Decision: Single Laravel/Filament application inside apps/platform, with one new bounded lifecycle overlay service and changes limited to existing settings persistence, system detail, onboarding, review-pack, and read-only review/evidence/download surfaces plus focused Pest coverage.

Likely Implementation Surfaces

  • app/Support/Settings/SettingsRegistry.php to register lifecycle-setting definitions and validation using the existing workspace settings infrastructure
  • app/Services/Entitlements/WorkspaceCommercialLifecycleResolver.php as the new bounded overlay, with WorkspaceEntitlementResolver.php remaining the canonical substrate provider
  • app/Support/Auth/PlatformCapabilities.php and related platform authorization helpers for one dedicated commercial-lifecycle management capability
  • app/Filament/System/Pages/Directory/ViewWorkspace.php and resources/views/filament/system/pages/directory/view-workspace.blade.php for read-only summary plus the confirmation-protected state-change action
  • app/Filament/Pages/Workspaces/ManagedTenantOnboardingWizard.php for contextual lifecycle messaging and activation blocking before tenant mutation
  • app/Services/ReviewPackService.php, app/Filament/Widgets/Tenant/TenantReviewPackCard.php, app/Filament/Pages/Reviews/ReviewRegister.php, app/Filament/Resources/TenantReviewResource.php, app/Filament/Resources/ReviewPackResource.php, app/Filament/Resources/ReviewPackResource/Pages/ViewReviewPack.php, and app/Filament/Resources/TenantReviewResource/Pages/ViewTenantReview.php for shared start gating and tooltip/disabled-state reuse
  • Existing read-only consumption surfaces CustomerReviewWorkspace.php, ViewTenantReview.php, ViewReviewPack.php, ViewEvidenceSnapshot.php, and the current review-pack download path to prove suspended history/evidence access remains available under existing RBAC
  • Focused unit and feature tests under tests/Unit/Entitlements, tests/Feature/System/Directory, tests/Feature/Onboarding, tests/Feature/ReviewPack, tests/Feature/Reviews, and tests/Feature/Evidence

Complexity Tracking

Violation Why Needed Simpler Alternative Rejected Because
One bounded WorkspaceCommercialLifecycleResolver Two real gated behavior families plus preserved read-only consumption need one shared workspace-wide decision layered above existing entitlements Page-local conditionals in onboarding, review-pack resources/widgets, and system detail would drift immediately and undermine business-state consistency
Four-state commercial lifecycle vocabulary Platform operators need one auditable commercial posture that distinguishes trial, grace, active paid, and suspended/read-only on the single system decision surface Three unlabeled booleans or ad hoc flags would either collapse grace into suspension or lose the explicit platform-side lifecycle state needed for support and audit

Proportionality Review

  • Current operator problem: The repo can already answer per-key entitlement questions, but it cannot say in one place whether a workspace is currently trialing, in grace, fully active paid, or suspended/read-only, nor can it explain why onboarding and review-pack starts are blocked while history remains readable.
  • Existing structure is insufficient because: WorkspaceEntitlementResolver and current workspace settings expose substrate truth only. They do not provide one workspace-wide lifecycle posture, one system-owned mutation path, or one action-family outcome that distinguishes lifecycle blocks from entitlement blocks and authorization failures.
  • Narrowest correct implementation: Keep persistence inside existing workspace_settings, add only one four-state lifecycle family plus rationale, derive action-family outcomes in one bounded overlay service, mutate it from one system detail page, and apply it only to onboarding activation, review-pack starts, and preserved read-only history/evidence/download semantics.
  • Ownership cost created: One new state vocabulary, one overlay service, one platform capability, cross-surface copy discipline, and focused lifecycle/read-only tests.
  • Alternative intentionally rejected: A billing/subscription engine, customer-account model, payment-provider seam, or many local page booleans was rejected because the current release only needs a single workspace commercial overlay on top of the already-real entitlement substrate.
  • Release truth: current-release truth. The four-state vocabulary is justified now because platform operators already need to set and audit those named postures, even though only grace and suspended_read_only introduce new blocked outcomes for the two in-scope action families in this slice.

Phase 0 — Research (output: research.md)

See: /Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/251-commercial-entitlements-billing-state/research.md

Goals:

  • Confirm the narrowest reuse of the existing entitlements settings domain and audit path for lifecycle state and rationale.
  • Confirm that one bounded overlay service can compose WorkspaceEntitlementResolver without creating a second commercial framework.
  • Confirm that lifecycle mutation remains platform-only on the existing system workspace detail page and does not leak into /admin self-service.
  • Confirm that review-pack start blocking happens before ReviewPack or OperationRun creation and can reuse the current blocked-decision transport.
  • Confirm that suspended read-only preservation remains bounded to existing review, evidence, and generated-pack consumption surfaces instead of becoming a broad product-wide suspension sweep.

Phase 1 — Design & Contracts (outputs: data-model.md, contracts/, quickstart.md)

See:

  • /Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/251-commercial-entitlements-billing-state/data-model.md
  • /Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/251-commercial-entitlements-billing-state/contracts/workspace-commercial-lifecycle-overlay.logical.openapi.yaml
  • /Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/251-commercial-entitlements-billing-state/quickstart.md

Design focus:

  • Persist commercial_lifecycle_state plus rationale through the existing entitlements settings domain instead of adding a new table or billing domain.
  • Keep the overlay inside App\Services\Entitlements and let it compose WorkspaceEntitlementResolver rather than replacing it.
  • Extend the existing system workspace detail page with a read-only lifecycle summary and one confirmation-protected Change commercial state action, while leaving WorkspaceSettings as substrate truth rather than a second mutation plane.
  • Gate ManagedTenantOnboardingWizard completion from the central lifecycle decision after underlying entitlement truth is known.
  • Gate review-pack Generate pack, Regenerate, and Export executive pack starts through ReviewPackService and current action surfaces, stopping before any ReviewPack or OperationRun write when the lifecycle blocks the action.
  • Preserve CustomerReviewWorkspace, review detail, evidence detail, review-pack detail, and pack download access under current RBAC while suspended, and keep any broader mutable-surface suspension work explicitly out of scope.

Phase 1 — Agent Context Update

After Phase 1 artifacts are generated, update Copilot context from the completed plan:

  • /Users/ahmeddarrazi/Documents/projects/wt-plattform/.specify/scripts/bash/update-agent-context.sh copilot

Phase 2 — Implementation Outline (tasks created later by /speckit.tasks)

  • Register lifecycle state and rationale setting definitions under the existing entitlements settings domain and wire them into the current workspace-setting audit path.
  • Add one bounded WorkspaceCommercialLifecycleResolver that composes underlying entitlement decisions and yields action-family outcomes plus suspended read-only allowances.
  • Add one dedicated platform capability for commercial lifecycle management and enforce it on the system detail mutation action only.
  • Extend ViewWorkspace plus its Blade view with current lifecycle state, affected behavior summary, and a confirmation-protected Change commercial state action.
  • Gate onboarding completion in ManagedTenantOnboardingWizard using the shared lifecycle decision while preserving existing tenant operability checks and 404/403 semantics.
  • Gate review-pack start surfaces and ReviewPackService using the shared lifecycle decision, preserving current queued-start UX when allowed and reusing the existing blocked-decision transport when blocked.
  • Prove suspended read-only continuation by asserting existing review/evidence/download surfaces remain available under current RBAC while no new onboarding activation or review-pack run can start.
  • Add focused Sail/Pest unit and feature coverage only.

Constitution Check (Post-Design)

Re-check result: PASS. The design keeps Filament v5 + Livewire v4 compliance intact, leaves provider registration unchanged in bootstrap/providers.php, introduces no new globally searchable resource, keeps asset strategy unchanged, preserves strict /admin vs /system separation, layers one bounded lifecycle resolver above the existing entitlement substrate, and blocks review-pack starts before OperationRun creation rather than forking shared run UX.

Planning Readiness

  • Outcome: keep
  • No unresolved clarification markers remain in the plan-phase artifacts.
  • No application implementation is included in this planning step.
  • The next repo-native step is /speckit.tasks for an implementation task breakdown, not code changes.

Implementation Close-Out

  • Workflow outcome: keep.
  • Implementation result: one bounded commercial lifecycle overlay was implemented through existing workspace settings, one system-plane Change commercial state action, onboarding activation gating, review-pack start allow/warn/block semantics, and preserved suspended read-only review/evidence/download access.
  • Blocked-decision transport: document-in-feature. The existing WorkspaceEntitlementBlockedException transport remains sufficient for review-pack blocked starts; no second business-state exception family was introduced.
  • Preserved read-only scope: document-in-feature. Suspension stays bounded to onboarding activation and new review-pack starts in this spec; broader mutable-surface suspension remains out of scope.
  • Browser smoke path: /system/login as operator@tenantpilot.io, /system/directory/workspaces/1, open Change commercial state, set Trial with rationale, confirm, observe updated lifecycle summary and notification follow-up, then restore Active paid.
  • Browser smoke result: pass after fixing WorkspaceResolver to accept Livewire serialized workspace route parameters; the follow-up notification update no longer emits console errors or 404/419 markers.
  • Lane results: targeted unit/support/system/onboarding/review-pack/read-only Pest lanes passed; dirty-only Pint passed; git diff --check passed.