TenantAtlas/specs/184-dashboard-recovery-honesty/data-model.md
2026-04-09 01:19:36 +02:00

121 lines
6.4 KiB
Markdown

# Data Model: Dashboard Recovery Posture Honesty
## Existing Evidence 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-input posture is not calmly healthy |
| `headline` | string | Operator-facing headline for the backup-input truth |
| `supportingMessage` | string nullable | Supporting backup-health explanation |
| `healthyClaimAllowed` | boolean | Whether the surface may speak positively about backup-input health |
| `primaryActionTarget` | action target nullable | Canonical backup drillthrough |
| `positiveClaimBoundary` | string | Canonical statement that backup health reflects backup inputs only and does not prove restore success |
### RestoreRun
Existing tenant-owned operational record of restore activity.
| Field | Type | Meaning |
|------|------|---------|
| `id` | integer | Restore-run identity |
| `tenant_id` | integer | Tenant scope |
| `backup_set_id` | integer nullable | Backup set used for the run |
| `status` | string | Restore lifecycle status |
| `is_dry_run` | boolean | Whether the record is preview-only |
| `results` | array/json | Item-, foundation-, and assignment-level execution outcomes |
| `metadata` | array/json | Additional execution and preview metadata, including `non_applied` and scope basis |
| `completed_at` | datetime nullable | Terminal completion timestamp |
| `operationRun` | relation nullable | Linked `OperationRun` for umbrella execution outcome |
### RestoreResultAttention
Existing per-run derived truth from `RestoreSafetyResolver::resultAttentionForRun(...)`.
| State | Follow-up required | Meaning |
|------|--------------------|---------|
| `not_executed` | no | Preview-only or not-yet-executed record; proves preview truth only |
| `failed` | yes | Execution failed; no recovery claim can be made |
| `partial` | yes | Execution reached terminal state but some items or assignments failed or only partially applied |
| `completed_with_follow_up` | yes | Execution completed, but skipped or non-applied work still weakens confidence |
| `completed` | no | No visible follow-up remains, but tenant-wide recovery is still not proven |
Relevant fields carried by the value object:
| Field | Type | Meaning |
|------|------|---------|
| `state` | string | One of the five result-attention states above |
| `summary` | string | Operator-facing explanation of the outcome |
| `followUpRequired` | boolean | Whether the result weakens confidence or needs action |
| `primaryNextAction` | string | Recommended next action for the run |
| `recoveryClaimBoundary` | string | Canonical claim-boundary identifier for the run outcome |
| `tone` | string | Summary tone for UI presentation |
## Derived Surface Projection
### Recovery Evidence Summary
This spec does **not** add a new persisted entity. It adds a derived tenant-level dashboard projection that combines existing backup health and restore evidence at render time.
| Field | Type | Persisted | Meaning |
|------|------|-----------|---------|
| `tenantId` | integer | no | Tenant scope |
| `backupPosture` | string | no | Current `TenantBackupHealthAssessment.posture` |
| `relevantRestoreHistoryPresent` | boolean | no | Whether the tenant has any executed, non-preview restore history |
| `latestRelevantRestoreRunId` | integer nullable | no | The most recent executed restore run relevant to overview continuity |
| `latestRelevantAttentionState` | string nullable | no | Result-attention state for the latest relevant run |
| `overviewState` | string | no | Canonical state key: `unvalidated`, `weakened`, or `no_recent_issues_visible` |
| `headline` | string | no | Operator-facing dashboard headline for the recovery-evidence condition |
| `summary` | string | no | Supporting summary text for the state |
| `claimBoundary` | string | no | Text that prevents the summary from becoming a proof claim |
| `action` | object nullable | no | Nested action payload with `label`, `url`, `disabled`, and `helperText`, matching the contract `ActionLink` shape |
### Overview State Rules
| Overview state | Entry rule | Required surface effect |
|------|------------|-------------------------|
| `unvalidated` | No executed, non-preview restore history exists for the tenant | Dashboard must show that recovery confidence is unvalidated and provide a next action into restore history |
| `weakened` | Latest relevant restore history resolves to `failed`, `partial`, or `completed_with_follow_up` | Needs Attention must surface the weakened condition and link to the exact run or canonical restore-run list fallback |
| `no_recent_issues_visible` | Relevant restore history exists and the latest relevant attention is `completed` | The dashboard may say no recent restore issues are visible, but must preserve the non-proof boundary |
Operator-facing copy may say that recovery evidence is not yet known, but the canonical derived state remains `unvalidated`.
### Non-qualifying restore records
The following records do **not** count as relevant restore history for overview confidence:
- `is_dry_run = true`
- `status in [draft, scoped, checked, previewed]`
- Any record whose `RestoreResultAttention.state` is `not_executed`
## Relationships
| Source | Relationship | Target | Use in this spec |
|------|--------------|--------|------------------|
| Tenant | has many | BackupSet | Existing backup-input truth via `TenantBackupHealthResolver` |
| Tenant | has many | RestoreRun | Existing restore-history truth used for overview evidence |
| RestoreRun | belongs to | BackupSet | Supports drillthrough context |
| RestoreRun | optionally belongs to | OperationRun | Contributes operation outcome to `RestoreResultAttention` |
## Derived Continuity Context
The canonical restore-run list receives a **non-persisted page context** from the dashboard for fallback continuity.
| Field | Type | Meaning |
|------|------|---------|
| `recovery_posture_reason` | query string | Why the user arrived on the restore-run list from the dashboard |
Suggested reason values:
- `no_history`
- `failed`
- `partial`
- `completed_with_follow_up`
- `no_recent_issues_visible`
These are list-continuity reasons only. They are not new persisted domain states.