Summary Dieses PR führt Spec 048: Backup/Restore UI Graph-Safety ein. Ziel: Backup/Restore-Screens in Filament sollen stabil und skalierbar bleiben, indem keine Microsoft Graph Calls beim UI-Rendern (mount/render/options/typeahead/labels) stattfinden. Stattdessen: DB-only Render + klare Fallbacks + Guard-Tests, die jede versehentliche UI-Graph-Nutzung sofort brechen. ⸻ Motivation / Problem Im aktuellen Stand rutschen Graph Calls gerne in: • Restore Wizard Group-Typeahead / getOptionLabelUsing (Graph /groups) • “Preview/Dry-Run” oder Label-Resolution im UI-Request Das führt zu: • langsamen/fragilen Pages (429/Timeout/Permissions) • schwerer Debugbarkeit im MSP-Scale • unerwarteten Abhängigkeiten vom Graph in reinen UI-Views ⸻ Scope (Phase 1, MVP) In scope • UI Render DB-only: Keine Graph Calls in Filament Render-Pfaden (Backup + Restore) • Fallback Labels für unresolved IDs: • Format: Unresolved (…<last8>) • Group Mapping UX (DB-only): • manuelle GUID Eingabe • GUID Validation • Helper-Text, wo Admins die Object ID finden • kein Graph-Search/typeahead • Fail-hard Guard Tests als Pest Feature Tests (HTTP GET): • Render Backup Sets Index • Render Restore Wizard • Tests assert: 200 OK + stable marker string Out of scope • Job-Orchestration Refactor (Actions wie “Capture snapshot”, “Rerun restore”, “dry-run execution”) → separater Spec/Feature • Entra Group Name Resolution (Group Inventory / Cache) → separater Modul-Scope ⸻ Deliverables • spec.md, plan.md, tasks.md • checklists/requirements.md (constitution gate) • Klar definierte Marker-Regeln für Guard-Tests (statische Headings, keine dynamischen Row-Werte) ⸻ Success Criteria • Guard-Tests schlagen zuverlässig fehl, sobald ein UI-Render Pfad Graph aufruft. • Restore Wizard bleibt bedienbar ohne Graph-Typeahead (GUID manual entry + Validation). • Keine DB-Migrations in dieser Phase. ⸻ Next Step Nach Review/Merge dieses Specs: 1. Implementation gemäß tasks.md (Remove UI Graph calls + Guard Tests) 2. Targeted Tests + Pint 3. Erst danach optional: eigener Spec für “job-based orchestration” (queued preview/execution) Co-authored-by: Ahmed Darrazi <ahmeddarrazi@adsmac.local> Reviewed-on: #54
157 lines
8.0 KiB
Markdown
157 lines
8.0 KiB
Markdown
# 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 story’s 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 3–4)**: 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 T003–T004; otherwise independent
|
||
- **US2 (P1)**: Depends on T003–T004; otherwise independent
|
||
|
||
### Parallel Opportunities
|
||
|
||
- T003 and T004 can be developed in parallel if split across files.
|
||
- US1 test work (T005–T006) and US2 test work (T008–T010) 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 1–2 (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
|
||
|