# Implementation Plan: Spec 136 Admin Panel Canonical Tenant Resolution Full Rollout **Branch**: `136-admin-canonical-tenant` | **Date**: 2026-03-11 | **Spec**: `specs/136-admin-canonical-tenant/spec.md` **Spec (absolute)**: `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/136-admin-canonical-tenant/spec.md` **Input**: `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/136-admin-canonical-tenant/spec.md` ## Summary Complete the rollout of the canonical admin tenant rule established in Spec 135 across all remaining admin-visible and admin-reachable shared tenant-sensitive surfaces. Workspace-admin flows under `/admin/...` will use `OperateHubShell::activeEntitledTenant(Request $request): ?Tenant` as the single tenant source for header context, queries, filters, widgets, links, and sensitive actions. Workspace-admin navigation will stay workspace-only except for baseline assets, so tenant-sensitive entry points move to the tenant panel under `/admin/t/{tenant}/...`. Admin surfaces with persisted tenant-related filters will standardize on `CanonicalAdminTenantFilterState`. Tenant-panel flows under `/admin/t/{tenant}/...` will keep panel-native `Filament::getTenant()` semantics. Global-search parity will be preserved through the existing admin-aware scoping pattern in `ScopesGlobalSearchToTenant` or explicit disablement where parity cannot be guaranteed cheaply. Implementation is organized into three rollout waves: 1. high-risk tenant-sensitive resources with sensitive actions or strong drift risk, 2. governance, restore, and inventory alignment surfaces, 3. workspace-wide tenant-default pages, diagnostics, widget alignment, and full guard expansion. ## Technical Context **Language/Version**: PHP 8.4 on Laravel 12 **Primary Dependencies**: Filament v5, Livewire v4, Pest v4, Laravel Sail **Storage**: PostgreSQL application database and session-backed Filament table state **Testing**: Pest feature and unit tests via `vendor/bin/sail artisan test --compact` **Target Platform**: Web application with Filament admin and tenant panels **Project Type**: Laravel monolith with Filament resources, pages, widgets, policies, support-layer helpers, and Pest guard tests **Performance Goals**: Keep monitoring and admin renders DB-only, keep tenant resolution deterministic per request, and avoid broader-than-visible scopes or stale session-driven tenant drift **Constraints**: - No dependency changes. - No new Graph calls, queued workflows, or scheduled workflows. - No panel-provider or routing redesign; provider registration remains in `bootstrap/providers.php` and panel routing remains intact. - No universal resolver abstraction that erases the distinction between workspace-admin and tenant-panel semantics. - Existing destructive and governance-sensitive actions must keep their current confirmation, authorization, and audit behavior while gaining tenant-target parity. - No new assets are introduced; deployment remains unchanged and does not add `filament:assets` work for this feature. **Scale/Scope**: Rollout across the canonical admin shell helper, session filter synchronization helper, admin-aware global-search behavior, 10+ affected resources/pages/widgets, the admin panel provider registration map, one architectural guard suite, and focused regression coverage for tenant switching, stale filters, search parity, and sensitive actions ## Constitution Check *GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.* - **Inventory-first / snapshots**: PASS — the feature changes request-time resolution and session-backed filter state only; inventory, backup, and snapshot storage remain unchanged. - **Read/write separation**: PASS — no new write workflow is introduced. Existing destructive and governance-sensitive actions remain existing actions and are only hardened to keep visible tenant and execution tenant aligned. - **Graph contract path**: PASS — no Graph calls or contract-registry changes are required. - **Deterministic capabilities**: PASS — no capability registry changes; existing Gates, policies, and capability helpers remain authoritative. - **RBAC-UX planes**: PASS — `/admin/...` and `/admin/t/{tenant}/...` stay explicitly separate. Admin canonical tenant logic applies only in the admin path, tenant-panel-native logic applies only in tenant routes. - **Workspace isolation**: PASS — workspace-admin routes remain workspace-scoped and tenant-safe, with deny-as-not-found preserved for non-members or out-of-scope access. - **Tenant isolation**: PASS — Type A and Type B rollout surfaces will keep tenant entitlement checks aligned across query, widgets, links, detail access, and actions. - **Global search safety**: PASS — any rollout resource that remains globally searchable must either use admin-safe scoped search with a View page present or disable global search where parity cannot be guaranteed. - **Run observability**: PASS — no new `OperationRun` types or lifecycle behavior. Monitoring remains DB-only at render time. - **Ops-UX lifecycle / summary counts / notifications**: PASS — unchanged. - **BADGE-001**: PASS — badge meanings remain centralized; only the tenant context feeding those views is normalized. - **UI-NAMING-001**: PASS — existing operator-facing phrases such as tenant labels, safe-state messages, and filter labels remain domain-first and implementation-neutral. - **Filament Action Surface Contract**: PASS WITH EXEMPTION — affected resources and pages mostly keep their current action surfaces. The rollout verifies tenant-target parity for existing actions instead of changing action inventory. - **Filament UX-001**: PASS WITH EXEMPTION — no layout redesign is needed; the feature only tightens tenant semantics and explicit safe-state behavior. - **Livewire v4.0+ compliance**: PASS — all affected Filament screens remain on the supported Filament v5 / Livewire v4 stack. - **Provider registration location**: PASS — no provider changes are required; Laravel 12 provider registration remains in `bootstrap/providers.php`. - **Global-search hard rule**: PASS — `PolicyResource`, `PolicyVersionResource`, and `EntraGroupResource` already have View pages where search parity matters; rollout design requires those resources to retain View-page-backed parity or disable admin-path global search. - **Destructive action safety**: PASS — `BackupScheduleResource`, `BackupSetResource`, `RestoreRunResource`, `FindingResource`, and `PolicyVersionResource` retain existing destructive or governance-sensitive actions; rollout scope is to preserve confirmation + authorization while guaranteeing the action tenant matches the visible tenant. - **Asset strategy**: PASS — no new panel assets, no `FilamentAsset::register()`, and no deployment change beyond existing processes. ## Phase 0 — Research Summary Research findings are recorded in `specs/136-admin-canonical-tenant/research.md`. Key decisions: - Treat admin panel provider registration plus direct admin page registration as the source of truth for which surfaces are truly admin-visible, while still reviewing shared resources whose code can run in both panels. - Keep `OperateHubShell::activeEntitledTenant()` as the only canonical admin tenant resolver instead of inventing a second abstraction. - Standardize persisted tenant-filter synchronization through `CanonicalAdminTenantFilterState` wherever `persistFiltersInSession()` and tenant-related filters coexist. - Reuse the existing `ScopesGlobalSearchToTenant` admin-aware search pattern for searchable rollout resources, and disable admin-path search if parity is not cheap or safe. - Treat `AlertDeliveryResource` and `AuditLog` as reference patterns for workspace-wide datasets with canonical tenant-default behavior. - Expand `AdminTenantResolverGuardTest` from a narrow allowlist to the full rollout surface set with explicit, documented exceptions for tenant-panel-native files. ## Phase 1 — Design & Contracts ### Data Model Design details are recorded in `specs/136-admin-canonical-tenant/data-model.md`. Key design points: - No schema changes are required. - The feature models request-time surface classification, tenant-resolution state, persisted filter state, sensitive action parity, and guard coverage as behavioral entities. - Shared resources are treated as panel-aware execution surfaces rather than purely admin or purely tenant objects. - Persisted filter state is never trusted without synchronization against the current canonical admin tenant. ### Contracts Internal behavior contracts are recorded in `specs/136-admin-canonical-tenant/contracts/admin-tenant-resolution-rollout.yaml`. Contract scope: - workspace-admin canonical tenant rule versus tenant-panel-native rule - Type A, Type B, and Type C surface classifications - rollout expectations for the named resources, pages, and widgets - search parity rules and no-context behavior - guard coverage and exception inventory expectations ### Quickstart Implementation and verification steps are recorded in `specs/136-admin-canonical-tenant/quickstart.md`. ### Post-Design Constitution Re-check - **Inventory-first / snapshots**: PASS — unchanged. - **Read/write separation**: PASS — the design only normalizes read, filter, link, and action-target semantics. - **Graph contract path**: PASS — still no Graph activity. - **RBAC-UX**: PASS — design keeps 404 for non-members or out-of-scope tenant access and 403 only after scope membership is established for capability-gated mutations. - **Workspace isolation**: PASS — admin routes remain workspace-scoped even when tenant is a shell concept rather than a route parameter. - **Tenant isolation**: PASS — list, detail, widget, search, and action paths are designed to use one tenant rule per surface. - **Global search safety**: PASS — the design explicitly requires admin-safe search parity for searchable resources or explicit disablement. - **Run observability / Ops-UX lifecycle**: PASS — unchanged. - **BADGE-001 / UI-NAMING-001**: PASS — centralized badge rendering and product wording remain intact. - **Filament Action Surface Contract**: PASS WITH EXEMPTION — no new destructive actions, no new action-surface inventory. - **Livewire v4.0+ compliance**: PASS — unchanged Filament v5 / Livewire v4 stack. - **Provider registration location**: PASS — no panel or provider changes; `bootstrap/providers.php` remains correct. - **Asset strategy**: PASS — still no asset registration or deployment delta. ## Project Structure ### Documentation (this feature) ```text specs/136-admin-canonical-tenant/ ├── plan.md ├── research.md ├── data-model.md ├── quickstart.md ├── contracts/ │ └── admin-tenant-resolution-rollout.yaml └── tasks.md ``` ### Source Code (repository root) ```text app/ ├── Providers/Filament/ │ └── AdminPanelProvider.php ├── Support/ │ ├── OperateHub/ │ │ └── OperateHubShell.php │ └── Filament/ │ ├── CanonicalAdminTenantFilterState.php │ └── ScopesGlobalSearchToTenant.php ├── Filament/ │ ├── Pages/ │ │ ├── Monitoring/ │ │ │ └── AuditLog.php │ │ ├── BaselineCompareLanding.php │ │ ├── InventoryCoverage.php │ │ └── TenantDiagnostics.php │ ├── Resources/ │ │ ├── PolicyResource.php │ │ ├── BackupScheduleResource.php │ │ ├── BackupSetResource.php │ │ ├── FindingResource.php │ │ ├── RestoreRunResource.php │ │ ├── InventoryItemResource.php │ │ ├── PolicyVersionResource.php │ │ ├── ProviderConnectionResource.php │ │ ├── EntraGroupResource.php │ │ └── AlertDeliveryResource.php │ └── Widgets/ │ ├── Inventory/ │ │ └── InventoryKpiHeader.php │ └── Operations/ ├── Models/ └── Policies/ tests/ ├── Feature/ │ ├── Guards/ │ ├── Filament/ │ ├── Monitoring/ │ └── Spec085/ └── Unit/ ``` **Structure Decision**: Keep implementation inside the existing Laravel / Filament monolith. Reuse `OperateHubShell`, `CanonicalAdminTenantFilterState`, and the existing admin-aware search trait instead of adding new infrastructure. Harden affected resources, pages, and widgets in place, then extend the current Pest guard and feature coverage. ## Phase 2 — Implementation Planning Implementation should be delivered in the following slices so `/speckit.tasks` can break work cleanly. 1. **Freeze the final surface inventory and classifications** - Use `AdminPanelProvider`, direct admin page registration, and shared resource reachability to finalize the rollout manifest. - Classify each target as Type A hard tenant-sensitive, Type B workspace-wide with tenant-default, or Type C workspace-only. - Keep tenant-only resources in the rollout only where shared code, admin deep links, cross-resource URLs, or dual-panel discovery can still create admin-path drift. 2. **Standardize support-layer resolver usage** - Keep `OperateHubShell::activeEntitledTenant(Request)` as the only public canonical admin tenant resolver. - Avoid introducing a second public resolver abstraction unless it is a thin, internal delegation wrapper for readability only. - Audit direct admin-path usages of `Tenant::current()` and `Filament::getTenant()` across the rollout set. 3. **Roll out persisted filter-state hardening** - Apply `CanonicalAdminTenantFilterState::sync()` to every affected admin surface that combines `persistFiltersInSession()` with tenant-related filters or tenant-default behavior. - Standardize stale-session behavior so old tenant state is cleared or reseeded before the surface renders. - Reuse `AlertDeliveryResource` and `AuditLog` as known-good reference patterns. 4. **Wave 1: high-risk tenant-sensitive resources** - Harden `PolicyResource`, `BackupScheduleResource`, `BackupSetResource`, and `FindingResource` so query, detail, filters, links, and sensitive actions align to the same tenant. - Verify destructive or governance-sensitive actions retain confirmation and server-side authorization while gaining tenant-target parity. 5. **Wave 2: governance, restore, and inventory alignment** - Harden `BaselineCompareLanding`, `RestoreRunResource`, `InventoryItemResource`, and `PolicyVersionResource`. - Treat `InventoryCoverage` and `InventoryKpiHeader` as one unit so page and widget cannot diverge. - Review `RestoreRunResource` and other shared tenant resources as panel-aware code paths even where admin navigation is intentionally absent. 6. **Wave 3: workspace-wide tenant-default, diagnostics, and search parity** - Harden `ProviderConnectionResource`, `TenantDiagnostics`, `AuditLog`, and `EntraGroupResource` follow-up behavior. - Keep workspace-wide datasets workspace-wide while synchronizing tenant-default labels, filters, deep links, and persisted state. - Preserve or explicitly disable admin-path global search where parity is not safe. 7. **Expand the guardrail and developer guidance** - Extend `AdminTenantResolverGuardTest` to the full rollout surface set. - Maintain a narrow, explicit exception inventory for tenant-panel-native files and other approved panel-native surfaces. - Update short developer guidance so future admin surfaces reuse the canonical rule and synchronized filter-state pattern. 8. **Finish with regression coverage and manual tenant-switch verification** - Add direct tests for `CanonicalAdminTenantFilterState`. - Add focused feature tests for wrong-tenant drift, stale filters, shared-surface panel behavior, search parity, and wrong-tenant sensitive-action prevention. - Record a manual tenant-switch check per rollout wave for representative Type A and Type B surfaces. ## Testing Strategy - Extend `tests/Feature/Guards/AdminTenantResolverGuardTest.php` to cover the full rollout manifest and exceptions. - Add direct unit or feature coverage for `CanonicalAdminTenantFilterState` behavior on tenant change, stale state, and invalid persisted state. - Add focused feature coverage for: - `PolicyResource`, `BackupScheduleResource`, `BackupSetResource`, and `FindingResource` tenant parity across list/detail/action paths, - `BaselineCompareLanding`, `InventoryCoverage`, and `InventoryKpiHeader` page-widget alignment, - `RestoreRunResource`, `InventoryItemResource`, and `PolicyVersionResource` shared resource parity across panel modes, - `ProviderConnectionResource`, `AuditLog`, and `EntraGroupResource` workspace-wide tenant-default behavior and search or deep-link safety, - representative 404 vs 403 authorization semantics for admin-path tenant-sensitive access. - Reuse existing Pest helpers, factories, and workspace or tenant session setup; avoid bespoke harnesses. - Run the minimum affected suite with Sail during implementation, then finish with `vendor/bin/sail bin pint --dirty --format agent`. ## Complexity Tracking No constitution violations or complexity exemptions are required for this plan.