# Data Model: Backup/Restore UI Graph-Safety (048)

This phase introduces **no schema changes**. It hardens UI render boundaries and adds guard tests.

## Existing Entities (used by this feature)

### Tenant
- Purpose: Tenancy boundary for all reads/writes.
- Notes:
  - Filament panel is tenant-scoped via `external_id` slug.

### User
- Purpose: Authenticated actor; has tenant memberships/roles.

### BackupSet (`backup_sets`)
- Fields (selected):
  - `id`, `tenant_id`
  - `name`, `created_by`, `status`, `item_count`, `completed_at`
  - `metadata` (JSON)
  - `deleted_at` (soft deletes, via housekeeping migration)
- Indexes: `tenant_id,status`, `completed_at`
- Used in UI:
  - Backup Sets index (table rendering must be DB-only)

### BackupItem (`backup_items`)
- Fields (selected):
  - `id`, `tenant_id`, `backup_set_id`
  - `policy_id` (nullable), `policy_version_id` (nullable)
  - `policy_identifier`, `policy_type`, `platform`
  - `captured_at`
  - `payload` (JSON), `metadata` (JSON), `assignments` (JSON)
  - `deleted_at` (soft deletes)
- Constraints:
  - Unique: `(backup_set_id, policy_identifier, policy_type)`
- Used in UI:
  - Restore wizard item selection + metadata display (must not resolve external names via Graph)

### RestoreRun (`restore_runs`)
- Fields (selected):
  - `id`, `tenant_id`, `backup_set_id`
  - `requested_by`, `is_dry_run`, `status`
  - `requested_items` (JSON), `preview` (JSON), `results` (JSON)
  - `group_mapping` (JSON)
  - `failure_reason`, `started_at`, `completed_at`, `metadata` (JSON)
  - `deleted_at` (soft deletes)
- Used in UI:
  - Restore wizard render (Create page) including group mapping controls

## Relationships (high-level)

- `Tenant` has many `BackupSet`, `BackupItem`, `RestoreRun`.
- `BackupSet` has many `BackupItem`.
- `RestoreRun` belongs to `BackupSet`.

## Validation & State Transitions (relevant to this phase)

- No new state transitions introduced.
- The key invariant enforced by tests:
  - Rendering Backup/Restore UI pages must not invoke `GraphClientInterface`.
