TenantAtlas/specs/185-workspace-recovery-posture-visibility/data-model.md
ahmido 53e799fea7 Spec 185: workspace recovery posture visibility (#216)
## Summary
- add Spec 185 workspace recovery posture visibility artifacts under `specs/185-workspace-recovery-posture-visibility`
- promote tenant backup health and recovery evidence onto the workspace overview with separate metrics, attention ordering, calmness coverage, and tenant-dashboard drill-throughs
- batch visible-tenant backup/recovery derivation to keep the workspace overview query-bounded
- align follow-up fixes from the authoritative suite rerun, including dashboard truth-alignment fixtures, canonical backup schedule tenant context, guard-path cleanup, smoke-fixture credential removal, and robust theme asset manifest handling

## Testing
- `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent`
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/Filament/PanelThemeAssetTest.php tests/Feature/Guards/DerivedStateConsumerAdoptionGuardTest.php`
- focused regression pack for the previously failing cases passed
- full suite JUnit run passed: `3401` tests, `18849` assertions, `0` failures, `0` errors, `8` skips

## Notes
- no new schema or persisted workspace recovery model
- no provider-registration changes; Filament/Livewire stack remains on Filament v5 and Livewire v4
- no new destructive actions or global search changes

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #216
2026-04-09 12:57:19 +00:00

167 lines
9.8 KiB
Markdown

# Data Model: Workspace Recovery Posture Visibility
## Existing Source Truth Models
### TenantBackupHealthAssessment
Existing derived tenant-level backup-input assessment from `TenantBackupHealthResolver`.
| Field | Type | Meaning |
|------|------|---------|
| `tenantId` | integer | Tenant scope for the assessment |
| `posture` | string | `absent`, `stale`, `degraded`, or `healthy` backup-input posture |
| `primaryReason` | string nullable | Why the current backup posture is not calmly healthy |
| `headline` | string | Operator-facing headline for the backup truth |
| `supportingMessage` | string nullable | Supporting backup-health explanation |
| `healthyClaimAllowed` | boolean | Whether a positive backup-health statement is allowed |
| `primaryActionTarget` | action target nullable | Canonical tenant-local backup follow-up target |
| `positiveClaimBoundary` | string | Canonical statement that backup health reflects backup inputs only and does not prove restore success |
### Dashboard Recovery Evidence Projection
Existing tenant-level recovery-evidence projection from `RestoreSafetyResolver::dashboardRecoveryEvidence()`.
| Field | Type | Meaning |
|------|------|---------|
| `backup_posture` | string | Current tenant backup posture carried through for bounded recovery copy |
| `overview_state` | string | `unvalidated`, `weakened`, or `no_recent_issues_visible` |
| `headline` | string | Operator-facing headline for tenant recovery evidence |
| `summary` | string | Supporting explanation of the current evidence state |
| `claim_boundary` | string | Text that prevents the summary from becoming a recovery-proof claim |
| `latest_relevant_restore_run_id` | integer nullable | Most relevant executed restore run for continuity |
| `latest_relevant_attention_state` | string nullable | Existing `RestoreResultAttention` state for the relevant run |
| `reason` | string | Reason key such as `no_history`, `failed`, `partial`, `completed_with_follow_up`, or `no_recent_issues_visible` |
### Existing Workspace Overview Output Contracts
`WorkspaceOverviewBuilder` already emits derived `summary_metrics`, `attention_items`, and `calmness` for `/admin`.
| Projection | Existing role |
|-----------|---------------|
| `summary_metrics` | Workspace scan strip for scope, governance, activity, and alerts |
| `attention_items` | Bounded, prioritized tenant- or workspace-bound triage list |
| `calmness` | Honest empty-state and “nothing urgent” contract for the visible workspace slice |
## New Derived Projections For Spec 185
Spec 185 adds **derived** workspace projections only. No migration or persisted model is introduced.
### VisibleWorkspaceTenantRecoveryContext
Per-visible-tenant context carried inside `WorkspaceOverviewBuilder` before widget rendering.
| Field | Type | Persisted | Meaning |
|------|------|-----------|---------|
| `tenantId` | integer | no | Visible tenant identity |
| `tenantLabel` | string | no | Tenant name shown on workspace surfaces |
| `tenantRouteKey` | string | no | Tenant route identity for drillthrough |
| `backupHealthPosture` | string | no | Existing tenant backup-health posture |
| `backupHealthReason` | string nullable | no | Existing tenant backup-health primary reason |
| `backupHealthHeadline` | string | no | Backup-health headline for workspace reason text |
| `backupHealthSummary` | string nullable | no | Supporting backup-health explanation |
| `backupHealthBoundary` | string | no | Backup-input claim boundary inherited from tenant truth |
| `recoveryEvidenceState` | string | no | Existing tenant recovery-evidence overview state |
| `recoveryEvidenceReason` | string | no | Existing tenant recovery-evidence reason key |
| `recoveryEvidenceHeadline` | string | no | Recovery-evidence headline for workspace reason text |
| `recoveryEvidenceSummary` | string | no | Supporting recovery-evidence explanation |
| `recoveryEvidenceBoundary` | string | no | Recovery claim boundary inherited from tenant truth |
| `latestRelevantRestoreRunId` | integer nullable | no | Latest relevant restore run for continuity if needed later |
| `hasBackupAttention` | boolean | no | True when backup posture is `absent`, `stale`, or `degraded` |
| `hasRecoveryAttention` | boolean | no | True when recovery evidence is `weakened` or `unvalidated` |
| `workspacePrimaryDestination` | destination | no | Primary tenant-dashboard drillthrough payload |
### WorkspaceRecoverySummaryMetric
Derived stat-strip metric for cross-tenant recovery and backup visibility.
| Field | Type | Persisted | Meaning |
|------|------|-----------|---------|
| `key` | string | no | `backup_attention_tenants` or `recovery_attention_tenants` |
| `label` | string | no | Operator-facing metric label |
| `value` | integer | no | Count of visible tenants needing follow-up in that family |
| `category` | string | no | Distinct metric category such as `backup_health` or `recovery_evidence` |
| `description` | string | no | Bounded explanation of what the count means |
| `destination` | destination nullable | no | `tenant_dashboard` when exactly one visible tenant is affected, otherwise `choose_tenant` |
### WorkspaceRecoveryAttentionItem
Derived workspace triage item for one visible tenant backup or recovery weakness.
| Field | Type | Persisted | Meaning |
|------|------|-----------|---------|
| `key` | string | no | Stable item key such as `tenant_backup_absent` or `tenant_recovery_weakened` |
| `family` | string | no | `backup_health` or `recovery_evidence` |
| `urgency` | string | no | Relative severity tier used inside workspace ordering |
| `tenant_id` | integer | no | Visible tenant identity |
| `tenant_label` | string | no | Visible tenant label |
| `title` | string | no | Bounded item title |
| `body` | string | no | Short reason text explaining the weakness |
| `supporting_message` | string nullable | no | Optional claim boundary or supplemental follow-up explanation |
| `badge` | string | no | Family badge label |
| `badge_color` | string | no | Existing shared tone mapping |
| `reason_context` | object | no | `{ family, state, reason }` payload for tests and future continuity |
| `destination` | destination | no | Primary tenant-dashboard drillthrough or safe disabled state |
### WorkspaceRecoveryCalmnessContract
Derived calmness state with explicit domain coverage.
| Field | Type | Persisted | Meaning |
|------|------|-----------|---------|
| `is_calm` | boolean | no | True only when covered domains are quiet for visible tenants |
| `checked_domains` | list<string> | no | Must now include `backup_health` and `recovery_evidence` |
| `title` | string | no | Calm or non-calm summary title |
| `body` | string | no | Bounded explanation that names the covered domains |
| `next_action` | destination | no | Tenant dashboard, choose-tenant, switch-workspace, or existing workspace action target |
## Derived State Rules
### Backup Attention Eligibility
| Backup posture | Workspace backup attention? | Notes |
|---------------|-----------------------------|-------|
| `absent` | yes | Highest backup-health severity |
| `stale` | yes | Middle backup-health severity |
| `degraded` | yes | Lowest backup-health severity that still needs attention |
| `healthy` | no | Schedule follow-up may still exist at tenant level, but Spec 185 counts only non-healthy backup posture for workspace backup attention |
### Recovery Attention Eligibility
| Recovery state | Workspace recovery attention? | Notes |
|---------------|-------------------------------|-------|
| `weakened` | yes | Highest recovery-evidence severity |
| `unvalidated` | yes | Lower than `weakened`, but still attention-worthy |
| `no_recent_issues_visible` | no | Calm recovery evidence still carries a non-proof boundary and must not become a problem item |
### Attention Ordering Consequences
| Derived family | Internal order |
|---------------|----------------|
| `backup_health` | `absent``stale``degraded` |
| `recovery_evidence` | `weakened``unvalidated` |
Cross-family ordering remains integrated into the existing workspace priority model. The new families must rank above activity-only operations and alerts while preserving the current governance-first intent of the queue.
## Invariants
- All new workspace recovery and backup projections are derived at render time and are not persisted.
- All counts and items are computed only from visible tenants in the active workspace scope.
- Backup health and recovery evidence remain separate fields and separate families in every derived workspace structure.
- Any calm workspace statement is bounded to visible tenants and covered domains only.
- The tenant dashboard is the canonical destination for new workspace backup or recovery items; deeper tenant backup-set or restore-run pages remain secondary follow-up surfaces.
- No derived workspace projection may claim recovery proof or restore guarantee.
## Relationships
| Source | Relationship | Target | Use in this spec |
|------|--------------|--------|------------------|
| Tenant | has one derived | `TenantBackupHealthAssessment` | Source of backup posture for workspace aggregation |
| Tenant | has one derived | dashboard recovery evidence projection | Source of recovery-evidence state for workspace aggregation |
| Workspace overview | derives many | `VisibleWorkspaceTenantRecoveryContext` | Per-tenant visible context used by stats, attention, and calmness |
| Workspace overview | derives many | `WorkspaceRecoverySummaryMetric` | Separate backup and recovery portfolio counts |
| Workspace overview | derives many | `WorkspaceRecoveryAttentionItem` | Prioritized tenant-level triage items |
| Workspace overview | derives one | `WorkspaceRecoveryCalmnessContract` | Honest calmness and checked-domain statement |
## No Persistence Changes
Spec 185 introduces no new table, no new column, no new materialized view, no new cache artifact, and no migration. All new structures are transient builder- or widget-level projections over existing tenant truth.