TenantAtlas/specs/146-central-tenant-status-presentation/data-model.md
ahmido 6ca496233b feat: centralize tenant lifecycle presentation (#175)
## Summary
- add a shared tenant lifecycle presentation contract and referenced-tenant adapter for canonical lifecycle labels and helper copy
- align tenant, chooser, onboarding, archived-banner, and tenantless operation viewer surfaces with the shared lifecycle vocabulary
- add Spec 146 design artifacts, audit notes, and regression coverage for lifecycle presentation across Filament and onboarding surfaces

## Validation
- `vendor/bin/sail bin pint --dirty --format agent`
- `vendor/bin/sail artisan test --compact tests/Feature/Badges/TenantStatusBadgeTest.php tests/Unit/Badges/TenantBadgesTest.php tests/Unit/Tenants/TenantLifecycleTest.php tests/Unit/Support/Tenants/TenantLifecyclePresentationTest.php tests/Feature/Filament/TenantLifecyclePresentationAcrossTenantSurfacesTest.php tests/Feature/Filament/ReferencedTenantLifecyclePresentationTest.php tests/Feature/Filament/TenantLifecycleStatusDomainSeparationTest.php tests/Feature/Filament/TenantViewHeaderUiEnforcementTest.php tests/Feature/Onboarding/TenantLifecyclePresentationCopyTest.php tests/Feature/Onboarding/OnboardingDraftAuthorizationTest.php tests/Feature/Onboarding/OnboardingDraftLifecycleTest.php`

## Notes
- Livewire v4.0+ compliance preserved; this change is presentation-only on existing Filament v5 surfaces.
- Panel provider registration remains unchanged in `bootstrap/providers.php`.
- No global-search behavior changed; no resource was newly made globally searchable or disabled.
- No destructive actions were added or changed.
- No asset registration strategy changed; existing deploy flow for `php artisan filament:assets` remains unchanged.

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #175
2026-03-16 18:18:53 +00:00

116 lines
4.3 KiB
Markdown

# Data Model: Central Tenant Status Presentation
## 1. TenantLifecycleState
- Purpose: The canonical tenant lifecycle domain value already defined by Spec 143 and implemented in `TenantLifecycle`.
- Source: Existing tenant domain model.
- Fields:
- `value`: enum string
- Allowed values: `draft`, `onboarding`, `active`, `archived`
- `label`: string
- Allowed values: `Draft`, `Onboarding`, `Active`, `Archived`
- Relationships:
- Derived from one `Tenant`
- Referenced by one `TenantLifecyclePresentation`
- Validation rules:
- Must be one of the four canonical lifecycle values for normal presentation flow
- Non-canonical values must bypass canonical rendering and enter invalid-data fallback only
- State transitions:
- Not defined here; owned by Spec 143 and the tenant domain
## 2. TenantLifecyclePresentation
- Purpose: The authoritative UI presentation contract for a lifecycle state.
- Ownership: Presentation layer only; no persistence required.
- Fields:
- `value`: canonical lifecycle value
- `label`: canonical operator-facing label
- `badge_color`: concise badge/chip color token
- `badge_icon`: icon token for badge or chip rendering
- `short_description`: concise explanatory text for detail or selector surfaces
- `long_description`: longer helper text for infolists, banners, or canonical viewers
- `is_invalid_fallback`: boolean flag reserved for corrupted or unexpected input
- Relationships:
- Belongs to one `TenantLifecycleState` when canonical
- May be constructed from a referenced tenant in a canonical viewer
- Validation rules:
- Canonical values must always produce `is_invalid_fallback = false`
- Invalid fallback must never be used for `draft`, `onboarding`, `active`, or `archived`
- `label` must match the canonical lifecycle vocabulary for canonical values
## 3. TenantLifecyclePresentationVariant
- Purpose: Surface-specific density derived from the same underlying lifecycle meaning.
- Ownership: Presentation composition only.
- Fields:
- `surface`: enum-like string
- Expected values: `table`, `detail`, `selector`, `canonical_viewer`, `banner`
- `show_badge`: boolean
- `show_short_description`: boolean
- `show_long_description`: boolean
- `show_context_note`: boolean
- Relationships:
- Belongs to one `TenantLifecyclePresentation`
- Validation rules:
- Must not alter `value` or `label`
- May change density only, never meaning
## 4. ReferencedTenantLifecycleContext
- Purpose: Captures how lifecycle is shown when a tenant appears as context on another record, such as an operation run.
- Ownership: Canonical viewer presentation only.
- Fields:
- `tenant_id`: integer or null
- `tenant_name`: string or null
- `lifecycle_value`: canonical lifecycle value or invalid raw value
- `viewer_context`: string
- Expected examples: `operation_run`, `report`, `audit_reference`
- `context_note`: optional explanatory text describing why the referenced tenant may be non-active
- Relationships:
- References one `Tenant`
- Uses one `TenantLifecyclePresentation`
- Validation rules:
- Must only be constructed after existing viewer authorization succeeds
- Must not imply the canonical record is invalid when the tenant lifecycle is `onboarding` or `archived`
## 5. Existing Domain Models in Scope
### Tenant
- Existing model: `App\Models\Tenant`
- Relevant existing fields:
- `status`
- `deleted_at` / soft-delete state
- `workspace_id`
- `name`
- `domain`
- `app_status`
- `rbac_status`
- Relevant derived methods:
- `lifecycle()`
- `isDraft()`
- `isOnboarding()`
- `isArchived()`
### OperationRun
- Existing model: `App\Models\OperationRun`
- Relevant existing fields:
- `tenant_id`
- `workspace_id`
- `status`
- `outcome`
- `context`
- Role in this feature:
- Supplies referenced tenant context only
- No lifecycle ownership changes
- No `OperationRun` state machine changes
## 6. Invariants
- Tenant lifecycle presentation must remain exhaustive for canonical states.
- Lifecycle presentation must not redefine lifecycle transitions or authorization.
- Lifecycle and health-like domains must remain separate in the rendered UI.
- Surface-specific rendering may change density, but not label or semantic meaning.
- Invalid fallback is reserved exclusively for non-canonical lifecycle data.