## 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
134 lines
9.2 KiB
Markdown
134 lines
9.2 KiB
Markdown
# Research: Spec 136 Admin Panel Canonical Tenant Resolution Full Rollout
|
|
|
|
## Decision 1: Use admin registration plus reachability to freeze the rollout manifest
|
|
|
|
**Decision**: Treat admin panel provider registration and direct admin page registration as the primary source of truth for admin-visible surfaces, but keep shared resources in scope when admin paths, deep links, embedded widgets, or dual-panel discovery can still execute their code in admin context.
|
|
|
|
**Rationale**:
|
|
- The codebase already exposes some resources directly in `AdminPanelProvider`, while others are tenant-scoped but still referenced from admin pages or shared navigation helpers.
|
|
- The spec cares about admin tenant drift, not only sidebar registration.
|
|
- Using reachability avoids missing shared resources that can still execute admin-path logic without appearing in admin navigation.
|
|
|
|
**Alternatives considered**:
|
|
- Limit the rollout strictly to resources registered in `AdminPanelProvider`: rejected because shared resources and pages can still create admin-path drift through direct URLs, deep links, or widgets.
|
|
- Treat every tenant resource as automatically in scope: rejected because some tenant-only surfaces have no admin-path behavior to harden.
|
|
|
|
## Decision 2: Keep `OperateHubShell` as the canonical admin resolver
|
|
|
|
**Decision**: Continue using `OperateHubShell::activeEntitledTenant(Request $request): ?Tenant` as the only canonical tenant resolver for workspace-admin tenant-sensitive behavior.
|
|
|
|
**Rationale**:
|
|
- The support layer already encodes the intended admin priority order and entitlement checks.
|
|
- Spec 135 established this as the correct canonical pattern.
|
|
- A second public resolver would reintroduce the same drift risk under a new name.
|
|
|
|
**Alternatives considered**:
|
|
- Introduce a new universal resolver service: rejected because the feature must preserve the admin-versus-tenant-panel distinction.
|
|
- Resolve tenant state separately in each resource or page: rejected because the defect class is inconsistent surface-level resolution.
|
|
|
|
## Decision 3: Persisted tenant-filter synchronization should standardize on `CanonicalAdminTenantFilterState`
|
|
|
|
**Decision**: Apply `CanonicalAdminTenantFilterState::sync()` as the standard synchronization primitive for admin surfaces that persist tenant-related filters in session.
|
|
|
|
**Rationale**:
|
|
- The helper already exists and clears or reseeds persisted tenant filter state based on the current canonical admin tenant.
|
|
- Filament v5 explicitly supports `persistFiltersInSession()`, so session-backed filter drift must be handled deliberately.
|
|
- `AlertDeliveryResource` and `AuditLog` already show the intended pattern.
|
|
|
|
**Alternatives considered**:
|
|
- Disable filter persistence on affected surfaces: rejected because persistence is an existing UX choice outside this feature.
|
|
- Hand-roll per-page session fixes: rejected because inconsistent local fixes are exactly what the rollout is trying to eliminate.
|
|
|
|
## Decision 4: Search parity should reuse the admin-aware global-search trait or fall back to disablement
|
|
|
|
**Decision**: Reuse `ScopesGlobalSearchToTenant` for rollout resources that stay globally searchable in admin context, and disable admin-path search when parity cannot be guaranteed cheaply.
|
|
|
|
**Rationale**:
|
|
- Filament v5 requires a View or Edit page for global-searchable resources.
|
|
- The existing trait already distinguishes admin-panel and tenant-panel behavior by using `OperateHubShell` in the admin panel and `Filament::getTenant()` elsewhere.
|
|
- The constitution requires non-member-safe, tenant-safe global search.
|
|
|
|
**Alternatives considered**:
|
|
- Leave search behavior implicit: rejected because search can bypass list-level scoping and create the same drift bug.
|
|
- Build a separate search-only resolver: rejected because the existing trait already captures the right panel split.
|
|
|
|
## Decision 5: Use `AlertDeliveryResource` and `AuditLog` as Type B reference patterns
|
|
|
|
**Decision**: Treat `AlertDeliveryResource` and `AuditLog` as the reference patterns for workspace-wide datasets with canonical tenant-default behavior.
|
|
|
|
**Rationale**:
|
|
- Both surfaces already combine workspace-wide data with synchronized tenant-default or tenant-filter behavior.
|
|
- Both already use `OperateHubShell` and `CanonicalAdminTenantFilterState` rather than raw panel-native tenant reads.
|
|
- They are good comparison points for `ProviderConnectionResource`, `AuditLog` guard expansion, and any `EntraGroupResource` workspace-wide follow-up behavior.
|
|
|
|
**Alternatives considered**:
|
|
- Use a pure tenant-scoped resource as the reference pattern: rejected because Type B surfaces have different requirements from Type A surfaces.
|
|
- Build a new shared reference helper first: rejected because the current reference patterns already exist in production code.
|
|
|
|
## Decision 6: Treat Inventory page and widget alignment as one rollout slice
|
|
|
|
**Decision**: Handle `InventoryCoverage` and `InventoryKpiHeader` together so the page shell and embedded KPI widget use the same tenant rule.
|
|
|
|
**Rationale**:
|
|
- The spec names `InventoryKpiHeader` as an explicit correction case.
|
|
- Widget drift is one of the exact defect classes the feature is intended to eliminate.
|
|
- Page-level tenant context is not trustworthy unless the widget and its linked drill-down behavior follow the same source.
|
|
|
|
**Alternatives considered**:
|
|
- Fix the page only: rejected because widget-only drift would remain.
|
|
- Leave the widget workspace-wide while the page is tenant-sensitive: rejected because it violates one-surface, one-source semantics.
|
|
|
|
## Decision 7: Shared tenant resources require panel-aware hardening even when admin navigation is absent
|
|
|
|
**Decision**: Keep shared tenant-sensitive resources such as `RestoreRunResource`, `BackupSetResource`, and other rollout targets in scope where their code can still be executed by admin paths, deep links, or shared helper logic, even if they do not register admin navigation.
|
|
|
|
**Rationale**:
|
|
- The spec explicitly calls out panel-safe behavior and shared-code review.
|
|
- Some resources are tenant-scoped in navigation yet still participate in admin-driven links, comparisons, or operational workflows.
|
|
- Drift can still occur inside shared methods, action URLs, and record-resolution logic.
|
|
|
|
**Alternatives considered**:
|
|
- Exclude tenant-routed resources from the rollout entirely: rejected because shared code can still carry unsafe resolver assumptions.
|
|
- Force admin registration for all tenant resources: rejected because the feature is about semantics, not information architecture redesign.
|
|
|
|
## Decision 8: Surface classification should be explicit and operational
|
|
|
|
**Decision**: Freeze the rollout using three operational classes:
|
|
- Type A hard tenant-sensitive: `PolicyResource`, `BackupScheduleResource`, `BackupSetResource`, `FindingResource`, `BaselineCompareLanding`, `RestoreRunResource`, `InventoryItemResource`, `PolicyVersionResource`, `TenantDiagnostics`, `InventoryCoverage`, `InventoryKpiHeader`
|
|
- Type B workspace-wide with tenant-default: `ProviderConnectionResource`, `AuditLog`, `EntraGroupResource` follow-up when admin path remains workspace-wide with tenant-default semantics
|
|
- Type C workspace-only: `AlertRuleResource`, `BaselineProfileResource`, `BaselineSnapshotResource`, `TenantResource`, and other workspace-owned admin surfaces with no tenant-sensitive execution path
|
|
|
|
**Rationale**:
|
|
- The rollout needs a stable manifest for guard coverage and test scope.
|
|
- The classes match the behavior contract described in the spec.
|
|
- Explicit classification prevents accidental over-scoping of workspace-wide surfaces.
|
|
|
|
**Alternatives considered**:
|
|
- Keep an informal list only: rejected because guard and task generation need explicit categories.
|
|
- Add a fourth ambiguous class: rejected because the spec requires ambiguous surfaces to be resolved before implementation.
|
|
|
|
## Decision 9: The guardrail should stay as a focused Pest architecture test
|
|
|
|
**Decision**: Expand `AdminTenantResolverGuardTest` rather than creating a new lint rule or analysis tool.
|
|
|
|
**Rationale**:
|
|
- The existing guard already scans selected canonical admin files for forbidden raw panel-native tenant reads.
|
|
- Pest is already the repo standard for architecture and regression guards.
|
|
- A focused allowlist and exception inventory is simpler to maintain than new tooling.
|
|
|
|
**Alternatives considered**:
|
|
- Add a PHPStan or ESLint-style custom rule: rejected because it is heavier than the feature requires.
|
|
- Rely on code review only: rejected because the feature explicitly asks for regression resistance and CI enforcement.
|
|
|
|
## Decision 10: No asset or panel bootstrap changes are needed
|
|
|
|
**Decision**: Keep the rollout entirely inside existing Filament resources, pages, widgets, support helpers, and tests with no new assets or panel-provider wiring changes.
|
|
|
|
**Rationale**:
|
|
- The defect is semantic and behavioral, not presentational.
|
|
- Existing admin and tenant panels already provide the right routing and discovery model.
|
|
- Avoiding asset and provider changes minimizes regression risk and keeps deployment unchanged.
|
|
|
|
**Alternatives considered**:
|
|
- Add panel-specific assets or hooks to manage tenant state in the browser: rejected because the canonical source is server-side and already exists.
|
|
- Change panel registration or routing: rejected because the feature explicitly excludes panel redesign. |