TenantAtlas/specs/048-backup-restore-ui-graph-safety/research.md
ahmido b35e3a6518 spec: refine 048 guardrails (#54)
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
2026-01-10 23:37:22 +00:00

2.5 KiB
Raw Blame History

Research: Backup/Restore UI Graph-Safety (048)

Decision: Enforce Graph-safety via fail-hard feature renders

  • Decision: Add Pest feature tests that actingAs(...) and GET Filament page URLs while binding App\Services\Graph\GraphClientInterface to a fail-hard implementation (throws on any call).
  • Rationale: A full HTTP render exercises the real Filament request lifecycle (middleware, tenancy, resource/page boot) and will fail immediately if any UI render path touches Graph.
  • Alternatives considered:
    • Livewire component tests only → can miss route/middleware/tenancy boot and wont reflect “real render” regressions as reliably.
    • Binding Graph to NullGraphClient → would allow silent Graph usage to slip through.

Decision: Use Resource::getUrl() for stable Filament routes (tenant-scoped)

  • Decision: Use Filaments URL helpers in tests:
    • BackupSetResource::getUrl('index', tenant: $tenant)
    • RestoreRunResource::getUrl('create', tenant: $tenant)
  • Rationale: Avoids hardcoding route paths and keeps tests resilient to panel path / tenancy prefix changes.
  • Repo evidence:
    • tests/Feature/Filament/InventorySyncRunResourceTest.php uses ->get(InventorySyncRunResource::getUrl('index', tenant: $tenant)).
  • Alternatives considered:
    • Hardcoded /admin/t/{tenant}/... paths → brittle if the panel path or tenant prefix changes.

Decision: Assert HTTP 200 + stable marker

  • Decision: Guard tests assert ->assertOk() plus a stable marker string per page.
  • Rationale: Reduces false positives (e.g., a redirect to login) and makes failures easier to diagnose.
  • Alternatives considered:
    • Status-only (200) → may still pass with empty/partial output or wrong page.

Decision: Fallback label masking format

  • Decision: Mask unresolved external IDs as …<last8> (last 8 characters, prefixed with ellipsis).
  • Rationale: Keeps UI readable while avoiding full identifier disclosure.
  • Alternatives considered:
    • Full ID → increases accidental disclosure.
    • Hash → less readable for operators.

Decision: Filament panel + tenancy routing assumptions

  • Decision: Treat the Filament admin panel as tenant-scoped under the configured path/prefix:
    • Panel path: admin
    • Tenant route prefix: t
    • Tenant slug attribute: external_id
  • Rationale: This is the repos current canonical setup (App\Providers\Filament\AdminPanelProvider).
  • Alternatives considered:
    • Non-tenant-scoped pages → not applicable (TenantPilot is tenant-first).