# Quickstart: Spec 136 Admin Panel Canonical Tenant Resolution Full Rollout ## Goal Finish the canonical tenant rollout for workspace-admin flows, preserve tenant-panel-native behavior, and leave the feature ready for small, test-driven implementation slices. ## Expected implementation slices 1. Freeze the final rollout manifest and classify surfaces as Type A, Type B, or Type C. 2. Standardize canonical admin resolver usage through `OperateHubShell`. 3. Roll out `CanonicalAdminTenantFilterState` across persisted tenant-filter surfaces. 4. Deliver Wave 1 high-risk tenant-sensitive resource fixes. 5. Deliver Wave 2 governance, restore, and inventory alignment. 6. Deliver Wave 3 workspace-wide tenant-default, diagnostics, search parity, and guard expansion. 7. Finish with direct filter-state tests, regression coverage, and manual tenant-switch verification. ## Recommended implementation order 1. Update the rollout manifest and guard file list first. 2. Normalize support-layer resolver and filter-state usage before touching individual resources. 3. Fix one high-risk resource family at a time and run focused tests after each slice. 4. Align widget and page pairs together instead of fixing them independently. 5. Finish with global-search parity, guard expansion, and developer guidance. ## Focused verification commands Run all commands from the repository root. ```bash vendor/bin/sail artisan test --compact tests/Feature/Guards/AdminTenantResolverGuardTest.php vendor/bin/sail artisan test --compact tests/Feature/Filament/TableStatePersistenceTest.php vendor/bin/sail artisan test --compact --filter='CanonicalAdminTenantFilterState|PolicyResource|BackupSchedule|BackupSet|FindingResource|BaselineCompareLanding|RestoreRunResource|InventoryItemResource|PolicyVersionResource|ProviderConnectionResource|TenantDiagnostics|InventoryCoverage|InventoryKpiHeader|AuditLog|EntraGroup' vendor/bin/sail bin pint --dirty --format agent ``` ## Manual tenant-switch verification per wave ### Wave 1 - Select Tenant A in the workspace-admin shell. - Visit representative Type A surfaces in Wave 1 and confirm header context, table/query results, and sensitive actions align. - Switch to Tenant B and confirm stale tenant filters are cleared or reseeded before data renders. ### Wave 2 - Re-check inventory and governance pages plus their embedded widgets. - Confirm widget KPIs, page summaries, record links, and detail pages remain aligned after a tenant switch. - Validate that shared resources preserve tenant-panel behavior under `/admin/t/{tenant}/...`. ### Wave 3 - Re-check workspace-wide datasets with tenant-default behavior. - Confirm base dataset stays workspace-wide while header tenant, filter defaults, deep links, and persisted filters update to the new canonical admin tenant. - Verify admin search and direct links remain tenant-safe or explicitly disabled where planned. ## Scenario matrix to cover in tests ### Type A hard tenant-sensitive surfaces - header tenant, query tenant, widget tenant, and action tenant all match - no valid canonical tenant produces the defined safe no-tenant-selected behavior - wrong-tenant sensitive actions are blocked safely ### Type B workspace-wide tenant-default surfaces - base dataset remains workspace-wide - tenant-default header, filter state, and deep links align to the canonical admin tenant - stale persisted tenant filters are cleared or reseeded after a tenant switch ### Shared panel-aware resources - admin panel uses the canonical admin tenant rule - tenant panel preserves panel-native `Filament::getTenant()` behavior - direct URLs and search paths do not bypass list parity ### Guardrail - a new raw `Filament::getTenant()` or `Tenant::current()` read in a guarded admin file fails CI - approved tenant-panel-native exception files remain explicitly allowed ## Future-surface developer rule - New `/admin/...` tenant-sensitive surfaces must resolve tenant context through `OperateHubShell` or `app/Filament/Concerns/ResolvesPanelTenantContext.php`. - Shared resources must keep tenant-panel behavior panel-native and must not let remembered admin context override `/admin/t/{tenant}/...`. - Any list surface that uses `persistFiltersInSession()` and tenant-derived defaults must call `CanonicalAdminTenantFilterState::sync()` before render. - If global search cannot be kept list/detail-safe in admin context, disable it explicitly instead of relying on implicit scoping. ## Out of scope during implementation - dependency or asset changes - panel bootstrap or routing redesign - unrelated CLI, queue, or scheduled-context resolver refactors - broad stylistic rewrites of tenant-panel resources that are already correct