128 lines
5.1 KiB
Markdown
128 lines
5.1 KiB
Markdown
# Feature Specification: Backup/Restore UI Graph-Safety (Phase 1)
|
||
|
||
**Feature Branch**: `feat/048-backup-restore-ui-graph-safety`
|
||
**Created**: 2026-01-10
|
||
**Status**: Draft
|
||
|
||
## Purpose
|
||
|
||
Ensure Backup/Restore UI follows the same guardrails as Inventory:
|
||
|
||
- UI renders DB-only (no Microsoft Graph calls during render/mount/options/typeahead)
|
||
- UI still remains usable with safe fallbacks for unresolved external identifiers
|
||
- Add programmatic guard tests that fail if Graph is touched while rendering
|
||
|
||
This phase is intentionally minimal-change and high-safety.
|
||
|
||
## Clarifications
|
||
|
||
### Session 2026-01-10
|
||
|
||
- Q: Which pages must the fail-hard `GraphClientInterface` guard tests render? → A: Backup Sets index + Restore wizard.
|
||
- Q: How should `<masked-id>` be formatted in fallback labels? → A: `…<last8>`
|
||
|
||
### Session 2026-01-11
|
||
|
||
- Q: How should the fail-hard Graph guard tests be structured? → A: Feature tests that `actingAs(...)` then `GET` the Filament pages’ routes.
|
||
- Q: For the feature tests, should we assert only HTTP 200, or also a stable UI marker? → A: Assert HTTP 200 + a stable page marker string.
|
||
|
||
## Users
|
||
|
||
- Tenant Admin
|
||
- MSP Operator (within authorized tenant scope)
|
||
|
||
## User Stories
|
||
|
||
### US1 (P1): Backup Sets Index is Graph-safe
|
||
|
||
As a tenant admin, I can open the Backup Sets index page and it renders DB-only (no Graph calls during request/render/mount/options/typeahead).
|
||
|
||
**Maps to**: Scenario 1
|
||
|
||
### US2 (P1): Restore Wizard is Graph-safe incl. Group Mapping UI
|
||
|
||
As a tenant admin, I can open the Restore wizard page and the group mapping UI remains usable without any Graph calls (including typeahead/search/label resolution).
|
||
|
||
**Maps to**: Scenario 2 + Scenario 3
|
||
|
||
## User Scenarios & Testing
|
||
|
||
### Scenario 1: Open Backup pages without Graph access
|
||
- Given a user is authenticated and has access to a tenant
|
||
- When they open the Backup Sets index page
|
||
- Then the page renders successfully (HTTP 200) without any Graph calls
|
||
|
||
### Scenario 2: Open Restore Wizard without Graph access
|
||
- Given a user is authenticated and has access to a tenant
|
||
- When they open the Restore Run wizard page
|
||
- Then the wizard renders successfully (HTTP 200) without any Graph calls
|
||
|
||
### Scenario 3: Group mapping shows safe fallback labels
|
||
- Given the UI displays group IDs (e.g., in mapping fields)
|
||
- When the UI cannot resolve group names without Graph
|
||
- Then it shows safe fallback labels like:
|
||
- `Unresolved (…<last8>)`
|
||
- `Group (external): …<last8>`
|
||
|
||
## Stable Page Marker Rules (for Guard Tests)
|
||
|
||
Guard tests MUST assert a stable, static marker string in addition to HTTP 200.
|
||
|
||
Marker selection rules:
|
||
|
||
- MUST be static UI text that is not tenant data (avoid names, IDs, timestamps, counts)
|
||
- SHOULD be a column label, section heading, or primary action label rendered by Filament
|
||
- MUST be present on the initial GET without requiring any Livewire interaction
|
||
- MUST NOT depend on Microsoft Graph availability
|
||
|
||
Markers MUST be recorded in quickstart.md once chosen.
|
||
|
||
## Functional Requirements
|
||
|
||
- FR-001: Backup/Restore UI MUST NOT call Microsoft Graph during render/mount/options/typeahead.
|
||
- FR-002: The Restore Wizard group mapping controls MUST NOT call Graph for search results or label resolution.
|
||
|
||
### Group Mapping UX (DB-only)
|
||
|
||
When group mapping is required, the UI MUST remain Graph-free and MUST provide a DB-only safe input.
|
||
|
||
- For each unresolved source group, the UI shows a mapping row with:
|
||
- Source label: `<displayName or "Security group"> (…<last8>)`
|
||
- Target input:
|
||
- Allowed values:
|
||
- `SKIP` (skip assignment)
|
||
- A manually entered Entra ID group objectId (GUID/UUID string)
|
||
- Validation rules:
|
||
- If not `SKIP`, the value MUST be a syntactically valid UUID
|
||
- No network lookup/verification is performed in Phase 1 (Graph-free). Existence is validated later during preview/restore execution paths.
|
||
- Helper text MUST explain:
|
||
- “Paste the target Entra ID group Object ID (GUID). Names are not resolved in this phase.”
|
||
- “Use SKIP to omit the assignment.”
|
||
|
||
- FR-003: When names cannot be resolved DB-only, the UI MUST show safe fallback labels using masked identifiers.
|
||
- `<masked-id>` format: `…<last8>` (last 8 characters of the external identifier, prefixed with an ellipsis)
|
||
- FR-004: Add fail-hard Pest feature tests binding `GraphClientInterface` to throw on any invocation and verify:
|
||
- Backup Sets index renders OK (HTTP 200 + stable page marker)
|
||
- Restore wizard renders OK (HTTP 200 + stable page marker)
|
||
|
||
## Non-Functional Requirements
|
||
|
||
- NFR-001: No new Graph calls are introduced in UI code paths.
|
||
- NFR-002: No new tables are added in this phase.
|
||
- NFR-003: Changes should be low-risk and minimal surface area.
|
||
|
||
## Out of Scope
|
||
|
||
- Moving action handlers (snapshot capture, backup create, restore rerun, restore dry-run) to jobs.
|
||
- Creating new cache/inventory tables to support group search.
|
||
|
||
## Success Criteria
|
||
|
||
- SC-001: Guard tests reliably fail if any Backup/Restore UI render path touches Graph.
|
||
- SC-002: Backup and Restore wizard pages render successfully with Graph disabled.
|
||
- SC-003: Group mapping UI remains usable with DB-only fallback labels.
|
||
|
||
## Related Specs
|
||
|
||
- Follow-up (Phase 2): Backup/Restore job orchestration (TBD)
|