TenantAtlas/specs/251-commercial-entitlements-billing-state/data-model.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

8.8 KiB

Data Model: Commercial Entitlements and Billing-State Maturity

Date: 2026-04-28
Branch: 251-commercial-entitlements-billing-state

Overview

This slice adds no new table. Persisted truth stays in existing workspace_settings rows, while the commercial lifecycle overlay and action-family outcomes remain derived.

Persisted Truth

1. Workspace Commercial Lifecycle Setting Aggregate

Persistence: Existing App\Models\WorkspaceSetting rows
Ownership: Workspace-owned
Scope: One workspace, no new tenant-owned or platform-owned persistence

The slice reuses explicit settings keys under the existing entitlements domain.

Setting key Type Nullable Validation Notes
entitlements.commercial_lifecycle_state string yes when present, must be one of trial, grace, active_paid, suspended_read_only null means the workspace has never been explicitly set and resolves to the implicit default active_paid
entitlements.commercial_lifecycle_reason string yes required on every explicit lifecycle state change; trimmed; max 500 chars Operator-entered rationale shown on system and contextual admin surfaces

Write rules:

  • Lifecycle mutation happens from the system plane only and updates state plus rationale together through the existing workspace settings write/audit path.
  • The future Change commercial state action is confirmation-protected and requires explicit rationale for every explicit lifecycle transition, including an explicit return to active_paid.
  • Once a platform operator explicitly sets active_paid, that remains a stored state like the other three values. null is reserved for untouched workspaces only.

Relationships:

  • workspace_settings.workspace_id anchors lifecycle truth to the workspace.
  • workspace_settings.updated_by_user_id remains the attribution source for state change metadata.

Existing Substrate Truth Reused

2. Workspace Entitlement Substrate Summary

Persistence: Existing Spec 247 workspace entitlement settings + code-owned plan-profile catalog
Owner: WorkspaceEntitlementResolver

This slice does not remodel the substrate. It reuses:

  • plan_profile
  • managed_tenant_activation_limit
  • review_pack_generation_enabled
  • substrate rationale/source/current-usage metadata

The lifecycle overlay may warn or restrict after substrate resolution, but it must never expand access beyond what the substrate already allows.

Code-Owned Truth

3. Commercial Lifecycle State Catalog Entry

Persistence: none, code-owned
Ownership: Product/runtime configuration
Scope: current release only

Field Type Required Notes
id string yes Stable internal identifier stored in entitlements.commercial_lifecycle_state
label string yes Operator-facing state label
description string yes Short explanation for system detail and contextual messaging
onboarding_outcome string yes allow or block
review_pack_start_outcome string yes allow, warn, or block
preserves_read_only_history bool yes Whether existing review/evidence/generated-pack consumption remains explicitly preserved
is_default bool yes Exactly one default entry: active_paid

Behavior matrix:

State Onboarding activation Review-pack starts Existing review/evidence/download access
trial allow allow allow
active_paid allow allow allow
grace block warn (start still allowed) allow
suspended_read_only block block allow

Derived Truth

4. Effective Commercial Lifecycle Decision

Persistence: none, derived at runtime
Owner: bounded WorkspaceCommercialLifecycleResolver

Field Type Required Notes
workspace_id int yes Workspace being evaluated
state string yes Effective lifecycle state
label string yes Operator-facing label
source string yes default_active_paid or workspace_setting; any rendered source label must come from one shared mapping
rationale string no Explicit operator rationale when source is workspace_setting
last_changed_at datetime no Derived from the most recent lifecycle-related WorkspaceSetting row
last_changed_by string no Derived actor attribution
entitlement_summary object yes Existing Spec 247 substrate summary reused for support/context
action_decisions object yes Per-action-family outcomes described below

5. Commercial Lifecycle Action Decision

Persistence: none, derived at runtime

Field Type Required Notes
action_key string yes One of managed_tenant_activation, review_pack_start, review_history_read, evidence_read, generated_pack_read
outcome string yes allow, warn, block, or allow_read_only
reason_family string no commercial_lifecycle, entitlement_substrate, or null when fully allowed
message string no Operator-safe explanation or warning
lifecycle_state string yes Effective state that produced the action decision
underlying_entitlement_key string no Present for onboarding/review-pack start decisions to preserve substrate traceability

Decision ordering rules:

  • The substrate entitlement decision runs first.
  • If the substrate already blocks the action, the lifecycle overlay must not replace that reason.
  • If the substrate allows the action, the lifecycle overlay may warn or block according to the state matrix.
  • Authorization is not part of this derived decision; 404 and 403 semantics remain outside and happen earlier.

Supporting Derived View Models

6. System Workspace Commercial Lifecycle View Model

Persistence: none
Consumer: App\Filament\System\Pages\Directory\ViewWorkspace

Contains:

  • effective lifecycle state, label, rationale, and last-change attribution
  • the two in-scope action-family outcomes
  • the reused entitlement substrate summary for support context
  • the one dominant mutation affordance metadata for Change commercial state

7. Contextual Admin Lifecycle Gate View Models

Persistence: none
Consumers: ManagedTenantOnboardingWizard, review-pack entry surfaces, and suspended read-only history surfaces

Contains:

  • the immediate action-family outcome (allow, warn, block, or allow_read_only)
  • one operator-safe explanation
  • enough substrate context to keep lifecycle blocks distinct from underlying entitlement blocks

Derived Query Dependencies

Need Source Notes
Underlying plan-profile and entitlement truth WorkspaceEntitlementResolver Remains the canonical substrate
Lifecycle last-change attribution existing workspace_settings.updated_by_user_id and timestamps Derived from lifecycle-related rows only
Active managed-tenant usage existing tenant/workspace runtime truth Reused from the substrate summary
Existing review/history/evidence/download availability existing review pack, review, evidence snapshot, and RBAC truth No new persistence needed
Review-pack no-run proof existing review_packs and operation_runs tables Used only in tests to prove blocked starts do not write new run state

State Transitions

There is no new table-backed lifecycle entity. State changes are explicit workspace-setting transitions plus audit entries.

From To Trigger Consequence
null (implicit default) any explicit state platform operator saves lifecycle state on the system detail page workspace now has explicit commercial posture, rationale, and attribution
trial grace platform operator state change new managed-tenant activation blocks; review-pack starts remain allowed with warning
grace suspended_read_only platform operator state change onboarding and new review-pack starts block; history/evidence/download remain available
suspended_read_only active_paid platform operator state change future starts again defer to underlying entitlement truth
any explicit state another explicit state platform operator state change previous state is replaced; audit history preserves the transition trail

Boundaries Explicitly Preserved

  • No new billing/customer/subscription entity exists.
  • No new automated timers, expiry jobs, renewal reminders, or scheduled transitions are introduced.
  • No new broad suspension contract is added for unrelated mutable surfaces.
  • Existing read-only review/evidence/generated-pack access remains governed by current RBAC and redaction rules.