## Summary - introduce a canonical admin tenant filter-state helper and route all in-scope workspace-admin tenant resolution through `OperateHubShell::activeEntitledTenant()` - align operations monitoring, operation-run deep links, Entra group admin list/view/search behavior, and shared context-bar rendering with the documented scope contract - add the Spec 135 design artifacts, architecture note, focused guardrail coverage, and non-regression tests for filter persistence, direct-record access, and global search safety ## Validation - `vendor/bin/sail bin pint --dirty --format agent` - `vendor/bin/sail artisan test --compact tests/Feature/Monitoring/OperationsKpiHeaderTenantContextTest.php tests/Feature/Monitoring/OperationsTenantScopeTest.php tests/Feature/Monitoring/OperationsCanonicalUrlsTest.php tests/Feature/Spec085/OperationsIndexHeaderTest.php tests/Feature/Spec085/RunDetailBackAffordanceTest.php tests/Feature/Filament/OperationRunListFiltersTest.php tests/Feature/Filament/EntraGroupAdminScopeTest.php tests/Feature/Filament/EntraGroupGlobalSearchScopeTest.php tests/Feature/DirectoryGroups/BrowseGroupsTest.php tests/Feature/Filament/EntraGroupEnterpriseDetailPageTest.php tests/Feature/Filament/PolicyVersionResolvedReferenceLinksTest.php tests/Feature/Filament/EntraGroupResolvedReferencePresentationTest.php tests/Feature/Guards/AdminTenantResolverGuardTest.php tests/Feature/OpsUx/OperateHubShellTest.php tests/Feature/Filament/Alerts/AlertsKpiHeaderTest.php tests/Feature/Alerts/AlertDeliveryDeepLinkFiltersTest.php` - `vendor/bin/sail artisan test --compact tests/Feature/Filament/TableStatePersistenceTest.php tests/Feature/Filament/TenantScopingTest.php tests/Feature/Filament/Alerts/AlertDeliveryViewerTest.php tests/Unit/Support/References/CapabilityAwareReferenceResolverTest.php` ## Notes - Filament v5 remains on Livewire v4.0+ compliant surfaces only. - No provider registration changes were needed; Laravel 12 provider registration remains in `bootstrap/providers.php`. - Entra group global search remains enabled and is now scoped to the canonical admin tenant contract. Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #164
5.1 KiB
Data Model: Spec 135 Canonical Tenant Context Resolution
Overview
This feature introduces no new database tables or persisted domain objects. Its data model is request-time and behavioral: it formalizes how existing workspace, tenant, filter, and record-access state combine into one canonical tenant-context outcome.
Entity: Tenant Panel Context
Purpose: Represents the panel-native tenant context for tenant-panel flows.
Source fields:
panel_idtenant_route_parameterfilament_tenanttenant_membership_status
Relationships:
- belongs to one current panel
- resolves to one entitled tenant or null
Validation rules:
- Only valid on tenant-panel-native surfaces.
- Must not be substituted with admin remembered-tenant fallback semantics.
- Non-members must receive deny-as-not-found behavior.
Entity: Admin Operational Tenant Context
Purpose: Represents the canonical active tenant for workspace-admin flows.
Source fields:
workspace_idfilament_tenant_idnullableremembered_tenant_idnullableresolved_tenant_idnullableresolution_sourceenum:filament,remembered,noneis_entitledboolean
Relationships:
- belongs to one current workspace
- may resolve to one tenant in that workspace
- is used by headers, widgets, filters, queries, record links, and search
Validation rules:
resolved_tenant_idmust be null when no entitled tenant exists.- If both
filament_tenant_idandremembered_tenant_idexist and disagree,filament_tenant_idwins. - Any resolved tenant must belong to the active workspace and pass tenant entitlement.
Entity: Tenant Context Conflict
Purpose: Captures the request state where more than one tenant source exists for the same admin request.
Fields:
filament_tenant_idremembered_tenant_idworkspace_idwinning_sourcelosing_source
Validation rules:
- Conflict only exists when both source values are present and different.
- Conflict resolution must be deterministic for the entire request.
- Losing source must not leak into filters, widgets, counts, or navigation labels.
Entity: Tenant-Sensitive Filter State
Purpose: Represents persisted or defaulted filter state whose valid values depend on the canonical tenant context.
Fields:
filter_nameraw_valuecanonical_tenant_idnullableworkspace_idis_valid_for_contextbooleanresolution_actionenum:apply,reset,ignore,replace
Relationships:
- belongs to one request flow
- may constrain one resource list or widget drill-down
Validation rules:
- Filter values must be revalidated whenever canonical tenant context changes.
- Filter option lists must never be broader than the underlying list/query scope.
- Invalid persisted tenant-sensitive values must not silently remain active after a tenant switch.
Entity: Scoped Record Access Path
Purpose: Represents any route or UI affordance that can reveal a tenant-sensitive record.
Fields:
surface_typeenum:list,detail,direct_url,deep_link,global_searchresource_nameworkspace_idcanonical_tenant_idnullablerecord_tenant_idnullableauthorization_outcomeenum:ok,not_found,forbidden
Relationships:
- points to one resource class and optional record
- uses one context resolver appropriate to its panel
Validation rules:
- Detail/direct/search access must never be broader than the corresponding list scope.
- Out-of-scope or missing-context access must produce deterministic bounded behavior.
- Membership failures remain
not_found; capability failures after membership is established remainforbidden.
Entity: Admin Surface Guardrail Exception
Purpose: Documents files that are allowed to use panel-native tenant reads without violating the admin guardrail.
Fields:
file_pathreasonpanel_semanticsenum:tenant_native,approved_panel_native_surfacereview_owner
Validation rules:
- Every exception must be explicit and stable.
- Admin-only files are not valid exceptions.
- Guardrail output must clearly distinguish violations from approved exceptions.
State Transitions
Admin request context state
-
no_context- No valid Filament tenant and no valid remembered tenant.
- Outcome: safe empty/not-found bounded behavior.
-
remembered_only- No valid Filament tenant, valid remembered tenant.
- Outcome: remembered tenant becomes canonical admin tenant.
-
filament_only- Valid Filament tenant, no remembered tenant.
- Outcome: Filament tenant becomes canonical admin tenant.
-
conflict- Valid Filament tenant and valid remembered tenant differ.
- Outcome: Filament tenant wins for the full request.
Invariants
- Tenant-panel-native files use panel-native tenant semantics.
- Workspace-admin files use the canonical admin resolver when resolving an operational tenant.
- Visible tenant context and effective query scope must always match within the same request.
- Persisted tenant-sensitive filter state is never trusted without revalidation.
- Direct record URLs and search results cannot bypass the same tenant boundary as the list surface.