TenantAtlas/specs/048-backup-restore-ui-graph-safety/tasks.md
2026-01-11 00:35:29 +01:00

157 lines
8.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Tasks: Backup/Restore UI Graph-Safety (Phase 1)
**Input**: Design documents from `/specs/048-backup-restore-ui-graph-safety/`
**Prerequisites**: plan.md (required), spec.md (required), research.md, data-model.md, contracts/, quickstart.md
**Tests**: REQUIRED (Pest). This feature explicitly adds guard tests (FR-004).
**Organization**: Tasks are grouped by user story to enable independent implementation and testing.
## Format: `- [ ] T### [P?] [US#?] Description with file path`
- **[P]**: Can run in parallel (different files, no dependencies)
- **[US#]**: Which user story this task belongs to (US1, US2)
- Include exact file paths in descriptions
---
## Phase 1: Setup (Shared Infrastructure)
**Purpose**: Confirm scope, lock stable UI markers as concrete strings, and ensure the contracts/quickstart reflect the intended test approach.
- [ ] T001 Confirm tenant-scoped admin URLs for target pages in specs/048-backup-restore-ui-graph-safety/contracts/admin-pages.openapi.yaml
- [ ] T002 Lock stable marker strings and record them in specs/048-backup-restore-ui-graph-safety/quickstart.md:
- Backup Sets index marker: `Created by`
- Restore wizard create marker: `Create restore run` (and wizard step: `Select Backup Set`)
---
## Phase 2: Foundational (Blocking Prerequisites)
**Purpose**: Shared test helpers and a clear boundary that fails-hard when Graph is touched.
**⚠️ CRITICAL**: No user story work should be considered “done” unless the fail-hard Graph binding is used in the storys feature tests.
- [ ] T003 [P] Create a fail-hard Graph client test double in tests/Support/FailHardGraphClient.php (implements App\\Services\\Graph\\GraphClientInterface and throws on any method)
- [ ] T004 Add a reusable binding helper for tests (either a helper function in tests/Pest.php or a trait in tests/Support/) that binds GraphClientInterface to FailHardGraphClient
**Checkpoint**: Foundation ready — both page-render tests can now be implemented.
---
## Phase 3: User Story 1 — Backup Sets index renders Graph-free (Priority: P1) 🎯 MVP
**Goal**: As a tenant admin, I can open the Backup Sets index page even when Graph is disabled.
**Independent Test**: A Pest feature test does an HTTP GET to the tenant-scoped Filament Backup Sets index route and asserts assertOk() + assertSee('Created by') — with Graph bound to fail-hard.
### Tests
- [ ] T005 [P] [US1] Add Pest feature test in tests/Feature/Filament/BackupSetGraphSafetyTest.php:
- bind GraphClientInterface to FailHardGraphClient (fail-hard on ANY invocation)
- HTTP GET App\\Filament\\Resources\\BackupSetResource::getUrl('index', tenant: $tenant)
- assertOk() + assertSee('Created by')
- [ ] T006 [US1] In tests/Feature/Filament/BackupSetGraphSafetyTest.php, add tenant isolation assertions (second tenant data must not render) while still using fail-hard Graph binding
### Implementation
- [ ] T007 [US1] Audit Backup Sets render path for any Graph usage and refactor to DB-only if needed in app/Filament/Resources/BackupSetResource.php and app/Filament/Resources/BackupSetResource/Pages/ListBackupSets.php
**Checkpoint**: Backup Sets index renders (assertOk() + assertSee('Created by')) with fail-hard Graph binding.
---
## Phase 4: User Story 2 — Restore wizard renders Graph-free + DB-only group mapping (Priority: P1)
**Goal**: As a tenant admin, I can open the Restore wizard page and interact with group mapping without any Graph calls in render/mount/options/typeahead.
**Independent Test**: Pest feature tests that (a) render the Restore wizard create page without Graph, and (b) render the group mapping section (using query params to preselect a backup set with group assignments) and verify fallback labels use `…<last8>`.
### Tests
- [ ] T008 [P] [US2] Add Pest feature test in tests/Feature/Filament/RestoreWizardGraphSafetyTest.php:
- bind GraphClientInterface to FailHardGraphClient (fail-hard on ANY invocation)
- HTTP GET App\\Filament\\Resources\\RestoreRunResource::getUrl('create', tenant: $tenant)
- assertOk() + assertSee('Create restore run') + assertSee('Select Backup Set')
- [ ] T009 [P] [US2] Extend tests/Feature/Filament/RestoreWizardGraphSafetyTest.php (or a second file):
- seed a BackupSet + BackupItem with group assignment targets (groupId present)
- HTTP GET create URL with `?backup_set_id=` (and optional `backup_item_ids`/`scope_mode`) to force group mapping render
- keep fail-hard Graph binding (no Graph/typeahead/label resolution allowed)
- [ ] T010 [US2] In the group mapping render test, assert all DB-only UX requirements:
- assertSee('…<last8>') masked fallback appears for source labels
- assertSee('Paste the target Entra ID group Object ID') helper text appears
- assertSee('Use SKIP to omit the assignment.') helper text appears
### Implementation
- [ ] T011 [US2] Remove Graph-dependent typeahead/search from group mapping controls in app/Filament/Resources/RestoreRunResource.php (no Graph/typeahead; remove getSearchResultsUsing paths)
- [ ] T012 [US2] Remove Graph-dependent option label resolution in app/Filament/Resources/RestoreRunResource.php (no Graph label resolution; remove getOptionLabelUsing paths)
- [ ] T013 [US2] Implement DB-only group mapping UX in app/Filament/Resources/RestoreRunResource.php:
- manual target group objectId input (GUID/UUID)
- GUID validation (if not SKIP)
- helper text: “Paste the target Entra ID group Object ID (GUID). Names are not resolved in this phase.” + “Use SKIP to omit the assignment.”
- no Graph/typeahead
- [ ] T014 [US2] Make unresolved group detection DB-only in app/Filament/Resources/RestoreRunResource.php (remove GroupResolver usage from unresolvedGroups() and any other render-time helpers)
- [ ] T015 [US2] Implement masked fallback label formatting `…<last8>` in app/Filament/Resources/RestoreRunResource.php (update formatGroupLabel() and ensure all source labels route through it)
- [ ] T016 [US2] Remove now-unused methods/imports after refactor (e.g., targetGroupOptions(), resolveTargetGroupLabel(), GroupResolver import) in app/Filament/Resources/RestoreRunResource.php
**Checkpoint**: Restore wizard renders (assertOk() + assertSee('Create restore run') + assertSee('Select Backup Set')) and group mapping renders DB-only; tests pass with fail-hard Graph binding.
---
## Phase 5: Polish & Cross-Cutting Concerns
**Purpose**: Keep docs and tooling aligned with the guardrail.
- [ ] T017 [P] Update specs/048-backup-restore-ui-graph-safety/quickstart.md with the final test file names and the exact `artisan test --filter=...` / file commands
- [ ] T018 [P] Update specs/048-backup-restore-ui-graph-safety/contracts/admin-pages.openapi.yaml if any page paths/markers changed during implementation
- [ ] T019 Run formatting (./vendor/bin/pint --dirty) and targeted tests (./vendor/bin/sail artisan test --filter=graph\-safety or the exact files)
---
## Dependencies & Execution Order
### Phase Dependencies
- **Setup (Phase 1)**: No dependencies
- **Foundational (Phase 2)**: Depends on Setup completion — BLOCKS both user stories
- **US1 + US2 (Phases 34)**: Depend on Foundational completion; can proceed in parallel
- **Polish (Phase 5)**: Depends on desired user stories being complete
### User Story Dependencies
- **US1 (P1)**: Depends on T003T004; otherwise independent
- **US2 (P1)**: Depends on T003T004; otherwise independent
### Parallel Opportunities
- T003 and T004 can be developed in parallel if split across files.
- US1 test work (T005T006) and US2 test work (T008T010) can be developed in parallel.
---
## Parallel Example
```bash
# Parallelizable work after Phase 2:
# - US1: tests/Feature/Filament/BackupSetGraphSafetyTest.php
# - US2: tests/Feature/Filament/RestoreWizardGraphSafetyTest.php
# - Shared helper: tests/Support/FailHardGraphClient.php
```
---
## Implementation Strategy
### MVP Scope (Recommended)
1. Phase 12 (setup + fail-hard Graph test binding)
2. Phase 3 (US1: Backup Sets index renders Graph-free)
3. Validate tests + stop
### Then
4. Phase 4 (US2: Restore wizard + group mapping Graph-free)
5. Phase 5 polish