# 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 won’t 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 Filament’s 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 repo’s current canonical setup (`App\Providers\Filament\AdminPanelProvider`).
- **Alternatives considered**:
  - Non-tenant-scoped pages → not applicable (TenantPilot is tenant-first).
