TenantAtlas/specs/180-tenant-backup-health/data-model.md
ahmido 6f8eb28ca2 feat: add tenant backup health signals (#212)
## Summary
- add the Spec 180 tenant backup-health resolver and value objects to derive absent, stale, degraded, healthy, and schedule-follow-up posture from existing backup and schedule truth
- surface backup posture and reason-driven drillthroughs in the tenant dashboard and preserve continuity on backup-set and backup-schedule destinations
- add deterministic local/testing browser-fixture seeding plus a local fixture-login helper for the blocked drillthrough `403` scenario, along with the related spec artifacts and focused regression coverage

## Testing
- `vendor/bin/sail artisan test --compact tests/Feature/Auth/BackupHealthBrowserFixtureLoginTest.php tests/Feature/Console/TenantpilotSeedBackupHealthBrowserFixtureCommandTest.php`
- `vendor/bin/sail artisan test --compact tests/Unit/Support/BackupHealth/TenantBackupHealthResolverTest.php tests/Feature/Filament/DashboardKpisWidgetTest.php tests/Feature/Filament/NeedsAttentionWidgetTest.php tests/Feature/Filament/TenantDashboardTruthAlignmentTest.php tests/Feature/Filament/TenantDashboardTenantScopeTest.php tests/Feature/Filament/TenantDashboardDbOnlyTest.php tests/Feature/Filament/BackupSetListContinuityTest.php tests/Feature/Filament/BackupSetEnterpriseDetailPageTest.php tests/Feature/BackupScheduling/BackupScheduleLifecycleTest.php tests/Feature/Auth/BackupHealthBrowserFixtureLoginTest.php tests/Feature/Console/TenantpilotSeedBackupHealthBrowserFixtureCommandTest.php`

## Notes
- Filament v5 / Livewire v4 compliant; no panel-provider change was needed, so `bootstrap/providers.php` remains unchanged
- no new globally searchable resource was introduced, so global-search behavior is unchanged
- no new destructive action was added; existing destructive actions and confirmation behavior remain unchanged
- no new asset registration was added; the existing deploy-time `php artisan filament:assets` step remains sufficient
- the local fixture login helper route is limited to `local` and `testing` environments
- the focused and broader Spec 180 packs are green; the full suite was not rerun after these changes

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #212
2026-04-07 21:35:58 +00:00

10 KiB

Data Model: Tenant Backup Health Signals

Overview

This feature does not add or change a top-level persisted domain entity. It introduces a narrow derived tenant backup-health model over existing tenant-owned backup and schedule records and integrates that derived truth into dashboard and drillthrough surfaces.

The central design task is to make the tenant dashboard answer four operator-visible states without changing:

  • BackupSet, BackupItem, or BackupSchedule ownership
  • existing backup-quality source-of-truth rules
  • existing backup or schedule route identity
  • existing mutation, audit, or OperationRun responsibilities
  • the no-new-table and no-recovery-score boundary of the feature

Existing Persistent Entities

1. BackupSet

  • Purpose: Tenant-owned backup collection that records capture lifecycle state and groups captured backup items.
  • Existing persistent fields used by this feature:
    • id
    • tenant_id
    • workspace_id
    • name
    • status
    • item_count
    • metadata
    • completed_at
    • created_at
  • Existing relationships used by this feature:
    • tenant
    • items
    • restoreRuns

Notes

  • completed_at is the primary timestamp used to decide whether a completed backup basis exists and whether it is fresh enough.
  • No new backup_health or freshness_state column is introduced on backup_sets.

2. BackupItem

  • Purpose: Tenant-owned captured recovery input for one backed-up policy or foundation record.
  • Existing persistent fields used by this feature:
    • id
    • tenant_id
    • backup_set_id
    • payload
    • assignments
    • metadata
    • captured_at
  • Existing relationships used by this feature:
    • tenant
    • backupSet
    • policyVersion

Existing metadata signals used by this feature

Key Type Meaning
source string or null Direct source marker; may indicate metadata-only capture
snapshot_source string or null Copied source marker from a linked policy version
warnings array Warning messages that may imply metadata-only fallback or other quality concerns
assignments_fetch_failed boolean Assignment capture failed for the item
assignment_capture_reason string or null Explanatory capture reason; not all values are degradations
has_orphaned_assignments boolean One or more captured assignment targets were orphaned
integrity_warning string or null Existing integrity or redaction warning carried into the backup item

3. BackupSchedule

  • Purpose: Tenant-owned schedule configuration for automated backup execution.
  • Existing persistent fields used by this feature:
    • id
    • tenant_id
    • workspace_id
    • name
    • is_enabled
    • frequency
    • time_of_day
    • days_of_week
    • policy_types
    • last_run_status
    • last_run_at
    • next_run_at
    • timezone
    • created_at
  • Existing relationships used by this feature:
    • tenant
    • operationRuns

Notes

  • last_run_at, last_run_status, and next_run_at are sufficient to derive schedule_follow_up.
  • No new schedule_health_state or backup_health_state column is introduced.

Derived Inputs

1. BackupHealthConfig

This is configuration, not persistence.

Key Type Purpose
tenantpilot.backup_health.freshness_hours integer Defines the canonical age window for the latest relevant completed backup basis
tenantpilot.backup_health.schedule_overdue_grace_minutes integer Defines how far past next_run_at an enabled schedule may drift before the feature raises schedule_follow_up

Derived Models

All derived models in this section are lightweight concrete value objects in app/Support/BackupHealth/. The concrete file set is TenantBackupHealthAssessment.php, BackupFreshnessEvaluation.php, BackupScheduleFollowUpEvaluation.php, BackupHealthActionTarget.php, and BackupHealthDashboardSignal.php, with TenantBackupHealthResolver.php orchestrating them.

1. TenantBackupHealthAssessment

Tenant-level backup-health truth used by dashboard and drillthrough logic.

Field Type Source Notes
tenantId integer tenant context Identity
posture string derived One of absent, stale, degraded, healthy
primaryReason string or null derived One of no_backup_basis, latest_backup_stale, latest_backup_degraded, or schedule_follow_up; null only when posture is healthy and no remaining follow-up reason exists
headline string derived Primary operator-facing summary for dashboard surfaces
supportingMessage string or null derived Secondary operator-facing explanation
latestRelevantBackupSetId integer or null derived The backup set that currently governs posture
latestRelevantCompletedAt datetime or null derived from BackupSet.completed_at Null when no usable completed basis exists
qualitySummary BackupQualitySummary or null reused BackupQualityResolver output Reused quality truth for the latest relevant backup basis
freshnessEvaluation BackupFreshnessEvaluation derived Separates recency truth from degradation truth
scheduleFollowUp BackupScheduleFollowUpEvaluation derived Secondary caution about automation timing
healthyClaimAllowed boolean derived True only when the evidence supports a positive healthy statement and no unresolved schedule_follow_up remains
primaryActionTarget BackupHealthActionTarget derived Reason-driven drillthrough destination
positiveClaimBoundary string derived Explains that backup health does not imply recoverability or restore success

2. BackupFreshnessEvaluation

Derived recency truth for the latest relevant completed backup basis.

Field Type Source Notes
latestCompletedAt datetime or null BackupSet.completed_at Null when no usable completed basis exists
cutoffAt datetime derived from config and now() The point after which a backup basis becomes stale
isFresh boolean derived False when no basis exists or when latestCompletedAt is older than cutoffAt
policySource string derived Initially configured_window to make the canonical freshness rule explicit and testable

Rules

  • If there is no relevant completed backup basis, the feature does not produce fresh; it produces absent.
  • If a latest relevant completed backup basis exists but predates cutoffAt, the primary posture becomes stale.
  • stale outranks degraded as a primary posture when both conditions are true.

3. BackupScheduleFollowUpEvaluation

Derived automation follow-up truth for enabled schedules.

Field Type Source Notes
hasEnabledSchedules boolean derived from BackupSchedule.is_enabled False when no enabled schedules exist
enabledScheduleCount integer derived Informational count
overdueScheduleCount integer derived from next_run_at and grace window Counts enabled schedules that appear overdue
failedRecentRunCount integer derived from last_run_status Counts enabled schedules whose recent status indicates failure or warning
neverSuccessfulCount integer derived from last_run_at and schedule timing Counts enabled schedules with no success evidence even though they should already have produced it
needsFollowUp boolean derived True when schedule timing or status indicates operator review
primaryScheduleId integer or null derived Optional single record for direct continuity if the result is unambiguous
summaryMessage string or null derived Operator-facing explanation of the schedule caution

Rules

  • Schedule follow-up is secondary. It adds attention but does not upgrade a tenant into healthy.
  • Enabled schedules with next_run_at past the grace window or with missing success evidence after the schedule should already have produced its first successful run count toward schedule_follow_up.

4. BackupHealthActionTarget

Reason-driven drillthrough target chosen by the resolver.

Field Type Notes
surface string backup_sets_index, backup_set_view, or backup_schedules_index
recordId integer or null Used only when the target is a specific backup set
label string Operator-facing action label such as Open backup sets or Open latest backup
reason string The problem class the destination is expected to confirm

5. BackupHealthDashboardSignal

Shared dashboard-facing model for KPI, attention, and healthy-check rendering.

Field Type Source
title string derived
body string derived
tone string derived
badge string or null derived via shared badge primitives when the signal is rendered as an attention item
badgeColor string or null derived via shared badge primitives when the signal is rendered as an attention item
actionTarget BackupHealthActionTarget or null derived
actionDisabled boolean derived from authorization and target availability
helperText string or null derived

Validation Rules

  • absent applies when no usable completed backup basis exists for the tenant.
  • stale applies when the latest relevant completed backup basis exists but fails the freshness rule, regardless of whether it is also degraded.
  • degraded applies when the latest relevant completed backup basis is fresh enough but existing BackupQualitySummary shows material degradation.
  • healthy applies when a latest relevant completed backup basis exists, passes freshness, and shows no material degradation.
  • schedule_follow_up is additive and must never be used as proof of health.
  • If schedule_follow_up is the only remaining caution, posture may remain healthy, but primaryReason must be schedule_follow_up and healthyClaimAllowed must be false until the follow-up resolves.
  • Existing BackupQualitySummary produced by BackupQualityResolver remains the authority for degradation families and degraded item counts.
  • Dashboard summary truth must remain visible to entitled tenant-dashboard viewers even when a downstream action target is suppressed or disabled.