TenantAtlas/specs/146-central-tenant-status-presentation/data-model.md
2026-03-16 19:17:35 +01: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.