## Summary - turn the tenant registry into a workspace-scoped recovery triage surface with backup posture and recovery evidence columns - preserve workspace overview backup and recovery drilldown intent by routing multi-tenant cases into filtered tenant registry slices - add the Spec 186 planning artifacts, focused regression coverage, and shared triage presentation helpers ## Testing - `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Filament/TenantRegistryRecoveryTriageTest.php tests/Feature/Filament/WorkspaceOverviewSummaryMetricsTest.php tests/Feature/Filament/WorkspaceOverviewDrilldownContinuityTest.php tests/Feature/Filament/TenantResourceIndexIsWorkspaceScopedTest.php tests/Feature/Filament/WorkspaceOverviewAuthorizationTest.php tests/Feature/Guards/ActionSurfaceContractTest.php tests/Feature/Guards/FilamentTableStandardsGuardTest.php` ## Notes - no schema change - no new persisted recovery truth - branch includes the full Spec 186 spec, plan, research, data model, contract, quickstart, and tasks artifacts Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #217
167 lines
6.4 KiB
Markdown
167 lines
6.4 KiB
Markdown
# Data Model: Tenant Registry Recovery Triage
|
||
|
||
## Overview
|
||
|
||
Spec 186 adds no new persisted entity. The feature is a derived registry-view slice over existing tenant, backup-health, and recovery-evidence truth.
|
||
|
||
## Existing Persisted Inputs
|
||
|
||
### Tenant
|
||
|
||
- **Purpose**: Canonical tenant identity and lifecycle record for the workspace-scoped registry.
|
||
- **Key fields**:
|
||
- `id`
|
||
- `workspace_id`
|
||
- `external_id`
|
||
- `name`
|
||
- `tenant_id`
|
||
- `environment`
|
||
- `status`
|
||
- `domain`
|
||
- `created_at`
|
||
- **Derived fields already used by the registry**:
|
||
- `policies_count`
|
||
- `last_policy_sync_at`
|
||
- **Relationships**:
|
||
- belongs to one workspace
|
||
- has many memberships
|
||
- has many policies
|
||
- has many backup sets
|
||
- has many restore runs
|
||
|
||
### TenantBackupHealthAssessment
|
||
|
||
- **Purpose**: Existing derived tenant backup-health truth used by dashboard and workspace overview.
|
||
- **Persistence**: Not persisted.
|
||
- **Key fields**:
|
||
- `tenantId`
|
||
- `posture` = `absent | stale | degraded | healthy`
|
||
- `primaryReason` = `no_backup_basis | latest_backup_stale | latest_backup_degraded | schedule_follow_up | null`
|
||
- `headline`
|
||
- `supportingMessage`
|
||
- `latestRelevantBackupSetId`
|
||
- `latestRelevantCompletedAt`
|
||
- `positiveClaimBoundary`
|
||
- `primaryActionTarget`
|
||
- **Behavioral role in Spec 186**:
|
||
- provides the registry’s `Backup posture` value
|
||
- provides the backup-attention set for workspace drilldown intent
|
||
- contributes to triage rank
|
||
|
||
### Dashboard Recovery Evidence Payload
|
||
|
||
- **Purpose**: Existing derived tenant recovery-evidence truth built from restore history.
|
||
- **Persistence**: Not persisted.
|
||
- **Key fields**:
|
||
- `backup_posture`
|
||
- `overview_state` = `unvalidated | weakened | no_recent_issues_visible`
|
||
- `headline`
|
||
- `summary`
|
||
- `claim_boundary`
|
||
- `latest_relevant_restore_run_id`
|
||
- `latest_relevant_attention_state`
|
||
- `reason` = `no_history | failed | partial | completed_with_follow_up | no_recent_issues_visible`
|
||
- **Behavioral role in Spec 186**:
|
||
- provides the registry’s `Recovery evidence` value
|
||
- provides the recovery-attention set for workspace drilldown intent
|
||
- contributes to triage rank
|
||
|
||
## New Derived Read Models
|
||
|
||
### TenantRegistryTriageRow
|
||
|
||
- **Purpose**: Request-scoped row projection for the tenant registry.
|
||
- **Persistence**: Not persisted.
|
||
- **Fields**:
|
||
- `tenant_id`
|
||
- `tenant_route_key`
|
||
- `tenant_name`
|
||
- `environment`
|
||
- `lifecycle_status`
|
||
- `policies_count`
|
||
- `last_policy_sync_at`
|
||
- `backup_posture`
|
||
- `backup_reason`
|
||
- `recovery_evidence`
|
||
- `recovery_reason`
|
||
- `triage_rank`
|
||
- `next_action_url`
|
||
- **Validation rules**:
|
||
- `backup_posture` must come directly from `TenantBackupHealthAssessment::posture`
|
||
- `recovery_evidence` must come directly from `dashboardRecoveryEvidenceForTenants(...)[tenant]['overview_state']`
|
||
- `triage_rank` must be derived from the shared registry priority table, not hard-coded independently per column or filter
|
||
- `next_action_url` must resolve to an allowed destination in the current workspace and tenant scope
|
||
|
||
### TenantRegistryTriageIntent
|
||
|
||
- **Purpose**: Query-string driven list intent for opening the registry in a prefiltered triage state.
|
||
- **Persistence**: Not persisted.
|
||
- **Fields**:
|
||
- `backup_posture[]` optional array of `absent | stale | degraded | healthy`
|
||
- `recovery_evidence[]` optional array of `weakened | unvalidated | no_recent_issues_visible`
|
||
- `triage_sort` optional enum `default | worst_first`
|
||
- **Validation rules**:
|
||
- every `backup_posture[]` entry must be one of the canonical backup posture values
|
||
- every `recovery_evidence[]` entry must be one of the canonical recovery-evidence values
|
||
- if `backup_posture[]` is present for workspace backup attention, its intended set is `absent`, `stale`, and `degraded`
|
||
- if `recovery_evidence[]` is present for workspace recovery attention, its intended set is `weakened` and `unvalidated`
|
||
- workspace drilldowns that need weak-first behavior must set `triage_sort=worst_first` explicitly; manual registry filtering alone does not change the default calm-browsing sort
|
||
|
||
### WorkspaceAttentionDestination
|
||
|
||
- **Purpose**: Derived navigation target from workspace overview metrics or attention items.
|
||
- **Persistence**: Not persisted.
|
||
- **Fields**:
|
||
- `kind` = existing workspace-drilldown contract value already used by the current widgets; unchanged by this feature
|
||
- `url`
|
||
- `tenant_route_key` optional
|
||
- `filters` optional exact registry intent payload
|
||
- **Validation rules**:
|
||
- one affected visible tenant resolves to the existing single-tenant dashboard kind and opens `/admin/t/{tenant}`
|
||
- more than one affected visible tenant preserves the existing multi-tenant admin-plane kind while `url` now opens filtered `/admin/tenants`
|
||
- any registry destination must carry exact posture filter semantics, not a vague `needs attention` label
|
||
|
||
## Relationships
|
||
|
||
- **Tenant** has one derived `TenantBackupHealthAssessment` in registry context.
|
||
- **Tenant** has one derived dashboard recovery-evidence payload in registry context.
|
||
- **TenantRegistryTriageRow** combines one `Tenant` with one backup-health assessment and one recovery-evidence payload.
|
||
- **WorkspaceAttentionDestination** references either one specific tenant or one registry triage intent, but never both at once.
|
||
|
||
## Triage Ranking Model
|
||
|
||
### Canonical rank tiers
|
||
|
||
1. `backup_posture = absent`
|
||
2. `recovery_evidence = weakened`
|
||
3. `backup_posture = stale`
|
||
4. `recovery_evidence = unvalidated`
|
||
5. `backup_posture = degraded`
|
||
6. calm rows: `backup_posture = healthy` and `recovery_evidence = no_recent_issues_visible`
|
||
|
||
### Tie-breaker
|
||
|
||
- Rows inside the same tier are secondarily ordered by `tenant_name` ascending.
|
||
|
||
### Rule for dual-signal tenants
|
||
|
||
- If a tenant is weak in both domains, the highest active tier governs its `triage_rank`, but both posture signals remain visible in the row.
|
||
|
||
## State Transitions
|
||
|
||
There are no persisted state transitions in this feature.
|
||
|
||
### Derived transition rules
|
||
|
||
- A registry row moves between triage tiers only when the underlying backup-health or recovery-evidence truth changes.
|
||
- Registry intent transitions are URL-driven:
|
||
- unfiltered registry
|
||
- backup-filtered registry
|
||
- recovery-filtered registry
|
||
- manually refined registry
|
||
- cleared back to the default registry view
|
||
|
||
## Notes
|
||
|
||
- The registry continues to be the source of truth for tenant identity and lifecycle metadata in workspace context.
|
||
- The registry does not become the source of truth for full backup diagnostics, restore proof, or overall recoverability. |