TenantAtlas/specs/180-tenant-backup-health/contracts/tenant-backup-health.openapi.yaml
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

420 lines
12 KiB
YAML

openapi: 3.1.0
info:
title: Tenant Backup Health Surface Contracts
version: 1.0.0
description: >-
Internal reference contract for tenant backup-health surfaces. The application
continues to render HTML through Filament and Livewire. The vendor media types
below document the structured dashboard, backup-set, and backup-schedule models
that must be derivable before rendering. This is not a public API commitment.
paths:
/admin/t/{tenant}:
get:
summary: Tenant dashboard backup-health surface
description: >-
Returns the rendered tenant dashboard. The vendor media type documents the
backup-health summary, backup-health attention item, and healthy-check model
that the dashboard must expose.
parameters:
- name: tenant
in: path
required: true
schema:
type: integer
responses:
'200':
description: Rendered tenant dashboard
content:
text/html:
schema:
type: string
application/vnd.tenantpilot.tenant-backup-health-dashboard+json:
schema:
$ref: '#/components/schemas/TenantBackupHealthDashboardSurface'
'404':
description: Tenant scope is not visible because workspace or tenant membership is missing
/admin/t/{tenant}/backup-sets:
get:
summary: Backup-set list confirmation surface
description: >-
Returns the rendered backup-set list page. The vendor media type documents
how the latest relevant backup basis and no-backup posture are confirmed.
parameters:
- name: tenant
in: path
required: true
schema:
type: integer
responses:
'200':
description: Rendered backup-set list page
content:
text/html:
schema:
type: string
application/vnd.tenantpilot.backup-health-backup-set-collection+json:
schema:
$ref: '#/components/schemas/BackupSetCollectionSurface'
'403':
description: Viewer is in scope but lacks backup viewing capability
'404':
description: Tenant scope is not visible because workspace or tenant membership is missing
/admin/t/{tenant}/backup-sets/{backupSet}:
get:
summary: Backup-set detail confirmation surface
description: >-
Returns the rendered backup-set detail page. The vendor media type documents
the recency and quality facts that must confirm stale or degraded latest-backup posture.
parameters:
- name: tenant
in: path
required: true
schema:
type: integer
- name: backupSet
in: path
required: true
schema:
type: integer
responses:
'200':
description: Rendered backup-set detail page
content:
text/html:
schema:
type: string
application/vnd.tenantpilot.backup-health-backup-set-detail+json:
schema:
$ref: '#/components/schemas/BackupSetDetailSurface'
'403':
description: Viewer is in scope but lacks backup viewing capability for the linked backup-set detail surface
'404':
description: Backup set is not visible because workspace or tenant membership is missing
/admin/t/{tenant}/backup-schedules:
get:
summary: Backup-schedule follow-up confirmation surface
description: >-
Returns the rendered backup-schedule list page. The vendor media type documents
the schedule-follow-up facts that must confirm overdue or missed schedule execution.
parameters:
- name: tenant
in: path
required: true
schema:
type: integer
responses:
'200':
description: Rendered backup-schedule list page
content:
text/html:
schema:
type: string
application/vnd.tenantpilot.backup-health-schedule-collection+json:
schema:
$ref: '#/components/schemas/BackupScheduleCollectionSurface'
'403':
description: Viewer is in scope but lacks schedule viewing capability
'404':
description: Tenant scope is not visible because workspace or tenant membership is missing
components:
schemas:
TenantBackupHealthDashboardSurface:
type: object
required:
- summary
properties:
summary:
$ref: '#/components/schemas/BackupHealthSummary'
attentionItem:
description: Present when a backup-health caution remains. `healthyCheck` must be null in that case.
oneOf:
- $ref: '#/components/schemas/BackupHealthAttentionItem'
- type: 'null'
healthyCheck:
description: Present only when no backup-health attention item remains unresolved, including `schedule_follow_up`.
oneOf:
- $ref: '#/components/schemas/HealthyCheck'
- type: 'null'
BackupHealthSummary:
type: object
required:
- posture
- primaryReason
- headline
- tone
- healthyClaimAllowed
properties:
posture:
type: string
enum: [absent, stale, degraded, healthy]
description: Describes the state of the latest relevant backup basis itself.
primaryReason:
description: The active follow-up reason. This may be `schedule_follow_up` even when `posture` remains `healthy`.
oneOf:
- type: string
enum: [no_backup_basis, latest_backup_stale, latest_backup_degraded, schedule_follow_up]
- type: 'null'
headline:
type: string
supportingMessage:
type:
- string
- 'null'
tone:
type: string
enum: [danger, warning, success, gray]
latestRelevantBackupSetId:
type:
- integer
- 'null'
latestRelevantCompletedAt:
type:
- string
- 'null'
format: date-time
freshness:
$ref: '#/components/schemas/FreshnessEvaluation'
scheduleFollowUp:
$ref: '#/components/schemas/ScheduleFollowUpEvaluation'
healthyClaimAllowed:
type: boolean
description: True only when the backup basis is healthy and no unresolved `schedule_follow_up` or stronger caution remains.
actionTarget:
oneOf:
- $ref: '#/components/schemas/ActionTarget'
- type: 'null'
actionDisabled:
type: boolean
helperText:
type:
- string
- 'null'
positiveClaimBoundary:
type: string
BackupHealthAttentionItem:
type: object
required:
- title
- body
- badge
- badgeColor
properties:
title:
type: string
body:
type: string
badge:
type: string
badgeColor:
type: string
actionTarget:
oneOf:
- $ref: '#/components/schemas/ActionTarget'
- type: 'null'
actionDisabled:
type: boolean
helperText:
type:
- string
- 'null'
HealthyCheck:
type: object
required:
- title
- body
properties:
title:
type: string
body:
type: string
actionTarget:
oneOf:
- $ref: '#/components/schemas/ActionTarget'
- type: 'null'
FreshnessEvaluation:
type: object
required:
- isFresh
- policySource
properties:
latestCompletedAt:
type:
- string
- 'null'
format: date-time
cutoffAt:
type: string
format: date-time
isFresh:
type: boolean
policySource:
type: string
enum: [configured_window]
ScheduleFollowUpEvaluation:
type: object
required:
- hasEnabledSchedules
- needsFollowUp
properties:
hasEnabledSchedules:
type: boolean
enabledScheduleCount:
type: integer
overdueScheduleCount:
type: integer
failedRecentRunCount:
type: integer
neverSuccessfulCount:
type: integer
needsFollowUp:
type: boolean
summaryMessage:
type:
- string
- 'null'
ActionTarget:
type: object
required:
- surface
- label
- reason
properties:
surface:
type: string
enum: [backup_sets_index, backup_set_view, backup_schedules_index]
recordId:
type:
- integer
- 'null'
label:
type: string
reason:
type: string
BackupSetCollectionSurface:
type: object
required:
- postureConfirmation
- rows
properties:
latestRelevantBackupSetId:
type:
- integer
- 'null'
postureConfirmation:
type: string
description: Explicit confirmation of the current collection meaning, including `no usable completed backup basis exists` when the dashboard drillthrough is resolving a `no_backup_basis` state.
rows:
type: array
items:
$ref: '#/components/schemas/BackupSetRow'
BackupSetRow:
type: object
required:
- id
- name
- lifecycleStatus
- completedAt
- qualitySummary
properties:
id:
type: integer
name:
type: string
lifecycleStatus:
type: string
completedAt:
type:
- string
- 'null'
format: date-time
isLatestRelevant:
type: boolean
qualitySummary:
type: string
BackupSetDetailSurface:
type: object
required:
- header
- freshness
- qualitySummary
- postureConfirmation
properties:
header:
$ref: '#/components/schemas/BackupSetHeader'
freshness:
$ref: '#/components/schemas/FreshnessEvaluation'
qualitySummary:
type: string
postureConfirmation:
type: string
positiveClaimBoundary:
type: string
BackupSetHeader:
type: object
required:
- id
- name
- lifecycleStatus
properties:
id:
type: integer
name:
type: string
lifecycleStatus:
type: string
completedAt:
type:
- string
- 'null'
format: date-time
BackupScheduleCollectionSurface:
type: object
required:
- rows
- followUpPresent
properties:
followUpPresent:
type: boolean
summaryMessage:
type:
- string
- 'null'
rows:
type: array
items:
$ref: '#/components/schemas/BackupScheduleRow'
BackupScheduleRow:
type: object
required:
- id
- name
- isEnabled
- followUpState
properties:
id:
type: integer
name:
type: string
isEnabled:
type: boolean
lastRunStatus:
type:
- string
- 'null'
lastRunAt:
type:
- string
- 'null'
format: date-time
nextRunAt:
type:
- string
- 'null'
format: date-time
followUpState:
type: string
enum: [none, overdue, failed_recently, never_successful, disabled]
followUpMessage:
type:
- string
- 'null'