## 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
116 lines
4.3 KiB
Markdown
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.
|