Automated commit and PR created by Copilot per user request. Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #287
7.8 KiB
Data Model: Plans, Entitlements & Billing Readiness
Date: 2026-04-27
Branch: 247-plans-entitlements-billing-readiness
Overview
This slice adds no new table. Persisted truth stays in existing workspace_settings rows, while plan defaults and effective entitlement decisions remain derived.
Persisted Truth
1. Workspace Entitlement Settings Aggregate
Persistence: Existing App\Models\WorkspaceSetting rows
Ownership: Workspace-owned
Scope: One workspace, no tenant-owned persistence, no system-plane mutation
The slice reuses explicit settings keys under an entitlements domain.
| Setting key | Type | Nullable | Validation | Notes |
|---|---|---|---|---|
entitlements.plan_profile |
string | yes | must match a code-owned plan-profile identifier when present | null means use the code-owned default profile |
entitlements.managed_tenant_limit_override_value |
int | yes | integer, >= 0 |
Explicit override for onboarding activation limit |
entitlements.managed_tenant_limit_override_reason |
string | yes | required when the paired override value is present; trimmed; max 500 chars | Operator-entered rationale shown on admin and system surfaces |
entitlements.review_pack_generation_override_value |
bool | yes | boolean | Explicit override for whether new Generate pack, Regenerate, and Export executive pack actions are allowed |
entitlements.review_pack_generation_override_reason |
string | yes | required when the paired override value is present; trimmed; max 500 chars | Operator-entered rationale shown on admin and system surfaces |
Write rules:
- Saving the section may update several
WorkspaceSettingrows in one page submission, but each row continues to use the existingSettingsWriteraudit path. - Resetting an override clears both the override value and its rationale, returning effective truth to the selected plan profile or code-owned default profile.
- Lowering the managed-tenant limit below current usage does not mutate tenant records; it only changes future activation eligibility.
Relationships:
workspace_settings.workspace_idanchors all persisted truth to a workspace.workspace_settings.updated_by_user_idremains the attribution source for last change metadata.
Code-Owned Truth
2. Workspace Plan Profile Catalog Entry
Persistence: none, code-owned
Ownership: Product/runtime configuration
Scope: first-slice only
| Field | Type | Required | Notes |
|---|---|---|---|
id |
string | yes | Stable internal identifier stored in entitlements.plan_profile |
label |
string | yes | Operator-facing plan profile label on settings and system surfaces |
description |
string | yes | Concise explanation of what the profile allows |
managed_tenant_limit_default |
int | yes | Default active managed-tenant activation limit |
review_pack_generation_default |
bool | yes | Default allow/block state for new review-pack generation |
is_default |
bool | yes | Exactly one profile is the code-owned fallback when no workspace setting exists |
Rules:
- The catalog is intentionally bounded to the first slice and must not grow into a broader entitlement matrix in this feature.
- The catalog is not operator-editable and is not a contract, invoice, or subscription record.
Derived Truth
3. Effective Workspace Entitlement Decision
Persistence: none, derived at runtime
Owner: bounded WorkspaceEntitlementResolver
| Field | Type | Required | Notes |
|---|---|---|---|
workspace_id |
int | yes | Workspace being evaluated |
plan_profile_id |
string | yes | Effective profile after applying the code-owned default fallback |
key |
string | yes | One of the two first-slice entitlement keys |
effective_value |
int or bool | yes | Final value after plan defaults plus any workspace override |
source |
string | yes | plan_profile_default or workspace_override |
rationale |
string | no | Override reason when source is workspace_override; otherwise optional plan-profile description |
current_usage |
int | no | Active managed-tenant count for the limit-based key; null for the boolean key |
remaining_capacity |
int | no | Derived only for the limit-based key |
is_blocked |
bool | yes | Whether the current action should stop for business-state reasons |
block_reason |
string | no | Operator-facing explanation used on onboarding and review-pack surfaces when blocked |
last_changed_at |
datetime | no | Derived from the most recent entitlement-related WorkspaceSetting row if present |
last_changed_by |
string | no | Derived actor attribution for settings and system visibility |
Key catalog:
| Entitlement key | Value type | Used by |
|---|---|---|
managed_tenant_activation_limit |
int | ManagedTenantOnboardingWizard completion eligibility and summary |
review_pack_generation_enabled |
bool | ReviewPackService, tenant dashboard widget, review register, tenant review view, review-pack list/detail actions |
Behavior rules:
managed_tenant_activation_limitcomparescurrent_usageto the effective limit and blocks only future onboarding activation.review_pack_generation_enabled=falseblocks new generate, regenerate, and executive-pack export attempts beforeReviewPackorOperationRuncreation.- Existing review-pack downloads and already-generated artifacts remain outside this entitlement decision.
Supporting Derived View Models
4. Workspace Entitlement Section Read Model
Persistence: none
Consumer: App\Filament\Pages\Settings\WorkspaceSettings
Contains:
- effective plan profile label and description
- both entitlement decisions
- editable override values plus rationale inputs
- current managed-tenant usage summary
- last changed attribution for the
entitlementsdomain
5. System Workspace Entitlement Summary Read Model
Persistence: none
Consumer: App\Filament\System\Pages\Directory\ViewWorkspace and resources/views/filament/system/pages/directory/view-workspace.blade.php
Contains:
- read-only effective plan profile label
- both entitlement decisions with source and rationale
- last changed attribution
- current managed-tenant usage summary
Derived Query Dependencies
| Need | Source | Notes |
|---|---|---|
| Active managed-tenant usage | existing tenant/workspace runtime truth | Count active managed tenants for the current workspace only; no persisted counter needed |
| Last change attribution | existing workspace_settings.updated_by_user_id and timestamps |
Derived from entitlement-related settings rows only |
| Review-pack run creation proof | existing review_packs and operation_runs behavior |
Used only in tests to prove blocked attempts create no new run |
State Transitions
No new persisted lifecycle state is introduced.
Derived runtime states for the limit-based entitlement:
| State | Trigger | Consequence |
|---|---|---|
within_limit |
current_usage < effective_value |
Onboarding completion may proceed if all other existing checks pass |
at_limit |
current_usage >= effective_value |
Future onboarding completion is blocked with a truthful reason |
over_limit_after_lowering |
Workspace limit is lowered below current usage | Existing tenants stay active; future onboarding completion remains blocked until usage or limit changes |
Derived runtime states for the review-pack entitlement:
| State | Trigger | Consequence |
|---|---|---|
enabled |
effective boolean value is true |
Existing review-pack start flow proceeds unchanged |
disabled |
effective boolean value is false |
New generate/regenerate/export attempts block before run creation |