## Summary - complete Spec 136 canonical admin tenant rollout across admin-visible and shared Filament surfaces - add the shared panel-aware tenant resolver helper, persisted filter-state synchronization, and admin navigation segregation for tenant-sensitive resources - expand regression, guard, and parity coverage for admin-path tenant resolution, stale filters, workspace-wide tenant-default surfaces, and panel split behavior ## Validation - `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` ## Notes - Livewire v4.0+ compliance is preserved with Filament v5. - Provider registration remains unchanged in `bootstrap/providers.php`. - `PolicyResource` and `PolicyVersionResource` have admin global search disabled explicitly; `EntraGroupResource` keeps admin-aware scoped search with a View page. - Destructive and governance-sensitive actions retain existing confirmation and authorization behavior while using canonical tenant parity. - No new assets were introduced, so deployment asset strategy is unchanged and does not add new `filament:assets` work. Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #165
17 KiB
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:
- high-risk tenant-sensitive resources with sensitive actions or strong drift risk,
- governance, restore, and inventory alignment surfaces,
- 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.phpand 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:assetswork 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
OperationRuntypes 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, andEntraGroupResourcealready 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, andPolicyVersionResourceretain 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
CanonicalAdminTenantFilterStatewhereverpersistFiltersInSession()and tenant-related filters coexist. - Reuse the existing
ScopesGlobalSearchToTenantadmin-aware search pattern for searchable rollout resources, and disable admin-path search if parity is not cheap or safe. - Treat
AlertDeliveryResourceandAuditLogas reference patterns for workspace-wide datasets with canonical tenant-default behavior. - Expand
AdminTenantResolverGuardTestfrom 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.phpremains correct. - Asset strategy: PASS — still no asset registration or deployment delta.
Project Structure
Documentation (this feature)
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)
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.
- 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.
- 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()andFilament::getTenant()across the rollout set.
- Roll out persisted filter-state hardening
- Apply
CanonicalAdminTenantFilterState::sync()to every affected admin surface that combinespersistFiltersInSession()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
AlertDeliveryResourceandAuditLogas known-good reference patterns.
- Wave 1: high-risk tenant-sensitive resources
- Harden
PolicyResource,BackupScheduleResource,BackupSetResource, andFindingResourceso 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.
- Wave 2: governance, restore, and inventory alignment
- Harden
BaselineCompareLanding,RestoreRunResource,InventoryItemResource, andPolicyVersionResource. - Treat
InventoryCoverageandInventoryKpiHeaderas one unit so page and widget cannot diverge. - Review
RestoreRunResourceand other shared tenant resources as panel-aware code paths even where admin navigation is intentionally absent.
- Wave 3: workspace-wide tenant-default, diagnostics, and search parity
- Harden
ProviderConnectionResource,TenantDiagnostics,AuditLog, andEntraGroupResourcefollow-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.
- Expand the guardrail and developer guidance
- Extend
AdminTenantResolverGuardTestto 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.
- 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.phpto cover the full rollout manifest and exceptions. - Add direct unit or feature coverage for
CanonicalAdminTenantFilterStatebehavior on tenant change, stale state, and invalid persisted state. - Add focused feature coverage for:
PolicyResource,BackupScheduleResource,BackupSetResource, andFindingResourcetenant parity across list/detail/action paths,BaselineCompareLanding,InventoryCoverage, andInventoryKpiHeaderpage-widget alignment,RestoreRunResource,InventoryItemResource, andPolicyVersionResourceshared resource parity across panel modes,ProviderConnectionResource,AuditLog, andEntraGroupResourceworkspace-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.