## Summary - cut over `EntraGroupResource` to an environment-bound admin Directory Groups surface in the workspace-first runtime - adopt workspace-scoped admin list/detail URLs and add the bounded `Directory > Groups` navigation entry in the admin panel - keep workspace-home navigation clean while preserving existing scoped list, detail, and global-search behavior - update focused feature coverage and add a browser smoke for the rendered sidebar drilldown path - include the Spec 303 package under `specs/303-admin-directory-groups-cutover/` ## Testing - updated focused Pest coverage for admin navigation segregation, Entra group admin scoping, Entra group global search scoping, and directory group browsing - added browser smoke coverage in `apps/platform/tests/Browser/Spec303AdminDirectoryGroupsCutoverSmokeTest.php` ## Filament / Runtime Notes - remains compliant with Filament v5 on Livewire v4 - no provider registration changes; provider registration location remains `apps/platform/bootstrap/providers.php` - `EntraGroupResource` remains eligible for global search because it has a View page - no destructive actions were added or changed; confirmation and authorization behavior is unchanged - no asset registration changes; existing `cd apps/platform && php artisan filament:assets` deploy posture is unchanged Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #358
290 lines
31 KiB
Markdown
290 lines
31 KiB
Markdown
# Feature Specification: Admin Directory Groups Cutover
|
|
|
|
**Feature Branch**: `303-admin-directory-groups-cutover`
|
|
**Created**: 2026-05-14
|
|
**Status**: Draft
|
|
**Input**: User description: "Erstelle die naechste Spec als 303-admin-directory-groups-cutover. Entscheide und implementiere den admin role contract fuer EntraGroupResource als environment-bound Directory/Identity Surface im workspace-first Admin Runtime Modell."
|
|
|
|
## Spec Candidate Check *(mandatory - SPEC-GATE-001)*
|
|
|
|
- **Problem**: `EntraGroupResource` is already a scoped admin runtime surface with list, detail, and global-search behavior, but its navigation contract still preserves an older blanket admin-hidden assumption. Spec 302 identified this as the only real blocker for the next runtime repair.
|
|
- **Today's failure**: Operators can reach directory groups through direct/scoped admin paths and global search, while admin navigation still says Groups are never an admin surface. Current tests also protect that stale hidden assumption.
|
|
- **User-visible improvement**: Operators who are inside an active Workspace plus Managed Environment context can discover read-oriented Directory Groups consistently, while the workspace-home sidebar stays clean.
|
|
- **Smallest enterprise-capable version**: Make Entra Groups a secondary environment-bound Directory/Identity surface. Keep list/detail/global search scoped to the active Managed Environment, ensure search destinations use canonical admin View URLs, and update stale navigation/search tests.
|
|
- **Explicit non-goals**: No generic M365 Admin mirror, no broad Identity Center, no group lifecycle management, no group membership mutation workflow, no new admin actions, no tenant-panel dead-code cleanup, no navigation-contract-split except minimal test adjustment, no migrations, no assets.
|
|
- **Permanent complexity imported**: No new models, tables, statuses, enums, services, registries, provider adapters, or UI frameworks. The permanent cost is a documented admin role contract plus focused navigation/search/scope tests.
|
|
- **Why now**: `docs/product/spec-candidates.md` sequences `admin-directory-groups-cutover` directly after Spec 301 and Spec 302. Spec 302's audit matrix names Entra Groups product IA as the only blocker before the next runtime repair.
|
|
- **Why not local**: A local one-line navigation flip would risk workspace-home leakage or unscoped search/detail destinations. The contract must distinguish workspace-home cleanliness from environment-bound Directory visibility and keep server-side RBAC/context checks authoritative.
|
|
- **Approval class**: Workflow Compression
|
|
- **Red flags triggered**: One provider-facing surface is touched, but it is bounded as provider-owned Directory inventory and does not introduce a platform-core identity framework.
|
|
- **Score**: Nutzen: 2 | Dringlichkeit: 2 | Scope: 2 | Komplexitaet: 2 | Produktnaehe: 2 | Wiederverwendung: 1 | **Gesamt: 11/12**
|
|
- **Decision**: approve
|
|
|
|
## Spec Scope Fields *(mandatory)*
|
|
|
|
- **Scope**: canonical-view
|
|
- **Primary Routes**:
|
|
- Entra Groups collection route in the admin panel, resolved only with an active Managed Environment context.
|
|
- Entra Groups View route in the admin panel, resolved only for records in the active Managed Environment context.
|
|
- Workspace-home route `/admin/workspaces/{workspace}` as the negative-control surface.
|
|
- Canonical environment route `/admin/workspaces/{workspace}/environments/{environment}` as the positive-control surface.
|
|
- **Data Ownership**: Existing `EntraGroup` rows remain managed-environment-owned directory cache records. This spec does not change tables, columns, Graph payload storage, or snapshot truth.
|
|
- **RBAC**: Workspace membership and Managed Environment access are required for visibility and access. Existing server-side policy/capability checks remain the authority for list, detail, search, and any existing operation-start action. UI visibility is never authorization.
|
|
|
|
For canonical-view specs, the spec MUST define:
|
|
|
|
- **Default filter behavior when tenant-context is active**: The Groups list and global search are scoped to the active Managed Environment resolved by the workspace-first admin shell. If no Managed Environment context exists, list access must deny as not found and search must return no unsafe records.
|
|
- **Explicit entitlement checks preventing cross-tenant leakage**: Direct URL manipulation, stale remembered context, cross-workspace records, and cross-environment records must not reveal data. Non-members remain deny-as-not-found; members without the relevant capability remain denied by existing policy/capability semantics.
|
|
|
|
## Cross-Cutting / Shared Pattern Reuse *(mandatory when the feature touches notifications, status messaging, action links, header actions, dashboard signals/cards, alerts, navigation entry points, evidence/report viewers, or any other existing shared operator interaction family; otherwise write `N/A - no shared interaction family touched`)*
|
|
|
|
- **Cross-cutting feature?**: yes
|
|
- **Interaction class(es)**: Filament resource navigation, environment-bound sidebar visibility, global-search result destinations, read-only resource list/detail access.
|
|
- **Systems touched**:
|
|
- `apps/platform/app/Filament/Resources/EntraGroupResource.php`
|
|
- `apps/platform/app/Filament/Resources/EntraGroupResource/Pages/ListEntraGroups.php`
|
|
- `apps/platform/app/Filament/Resources/EntraGroupResource/Pages/ViewEntraGroup.php`
|
|
- `apps/platform/app/Filament/Concerns/ScopesGlobalSearchToTenant.php`
|
|
- `apps/platform/app/Filament/Concerns/ResolvesPanelTenantContext.php`
|
|
- `apps/platform/app/Filament/Concerns/WorkspaceScopedTenantRoutes.php`
|
|
- `apps/platform/app/Providers/Filament/AdminPanelProvider.php`
|
|
- `apps/platform/app/Support/Navigation/NavigationScope.php`
|
|
- `apps/platform/app/Support/OperateHub/OperateHubShell.php`
|
|
- focused tests under `apps/platform/tests/Feature/Filament/` and `apps/platform/tests/Feature/DirectoryGroups/`
|
|
- **Existing pattern(s) to extend**: `NavigationScope::shouldRegisterEnvironmentNavigation()`, `OperateHubShell` environment context resolution, `ScopesGlobalSearchToTenant`, `ResolvesPanelTenantContext`, `InteractsWithTenantOwnedRecords`, and the existing canonical admin route/link helpers.
|
|
- **Shared contract / presenter / builder / renderer to reuse**: Existing navigation/context/search traits and helpers. No new Directory navigation framework is introduced.
|
|
- **Why the existing shared path is sufficient or insufficient**: The shared paths already solve environment detection, scoped query/search, and tenant-owned record resolution. They are insufficient only where `EntraGroupResource::shouldRegisterNavigation()` still returns false for every admin context.
|
|
- **Allowed deviation and why**: No route-posture deviation is applied. `EntraGroupResource` adopts `WorkspaceScopedTenantRoutes`; the rendered sidebar link is registered explicitly in `AdminPanelProvider` because the runtime navigation contract uses explicit environment-bound entries for operator-facing surface links.
|
|
- **Consistency impact**: Directory Groups must follow the same workspace-home clean-sidebar rule and environment-bound visibility rule as migrated tenant-owned surfaces, without becoming a broader Identity Center.
|
|
- **Review focus**: Reviewers must verify the implementation removes only the stale Groups admin-hidden assumption, does not reopen workspace-home tenant-owned navigation, keeps search scoped, and does not introduce group mutation workflows.
|
|
|
|
## OperationRun UX Impact *(mandatory when the feature creates, queues, deduplicates, resumes, blocks, completes, or deep-links to an `OperationRun`; otherwise write `N/A - no OperationRun start or link semantics touched`)*
|
|
|
|
- **Touches OperationRun start/completion/link UX?**: no new OperationRun behavior.
|
|
- **Shared OperationRun UX contract/layer reused**: Existing directory group sync behavior, if still present, remains outside this spec's new behavior and must continue using existing operation-start, notification, and link helpers.
|
|
- **Delegated start/completion UX behaviors**: N/A for new behavior.
|
|
- **Local surface-owned behavior that remains**: Existing Groups list operation/header actions may remain only as pre-existing behavior. This spec must not add, promote, or redesign mutation/admin actions.
|
|
- **Queued DB-notification policy**: N/A.
|
|
- **Terminal notification path**: N/A.
|
|
- **Exception required?**: none.
|
|
|
|
## Provider Boundary / Platform Core Check *(mandatory when the feature changes shared provider/platform seams, identity scope, governed-subject taxonomy, compare strategy selection, provider connection descriptors, or operator vocabulary that may leak provider-specific semantics into platform-core truth; otherwise write `N/A - no shared provider/platform boundary touched`)*
|
|
|
|
- **Shared provider/platform boundary touched?**: yes, bounded to operator vocabulary and resource navigation.
|
|
- **Boundary classification**: mixed, with provider-owned Directory data inside platform-owned workspace/environment context.
|
|
- **Seams affected**: navigation label, resource label, global-search destination URL, empty-state copy if adjusted, tests that name the surface.
|
|
- **Neutral platform terms preserved or introduced**: Workspace, Managed Environment, Directory Groups, Directory inventory, environment-bound surface.
|
|
- **Provider-specific semantics retained and why**: "Microsoft Entra" and "Entra Group" remain where accuracy is required for the source object and provider cache. They must not become a broad platform-core identity framework.
|
|
- **Why this does not deepen provider coupling accidentally**: The implementation is limited to one existing provider-owned resource and does not add shared identity abstractions, provider capability registries, tables, or Graph adapters.
|
|
- **Follow-up path**: `navigation-contract-split` remains conditional after this spec; broader Directory/Admin Roles IA remains out of scope unless separately promoted.
|
|
|
|
## UI / Surface Guardrail Impact *(mandatory when operator-facing surfaces are changed; otherwise write `N/A`)*
|
|
|
|
| Surface / Change | Operator-facing surface change? | Native vs Custom | Shared-Family Relevance | State Layers Touched | Exception Needed? | Low-Impact / `N/A` Note |
|
|
|---|---|---|---|---|---|---|
|
|
| Workspace-home sidebar | yes, negative control | Native Filament navigation | navigation | shell, route context | no | Must remain clean; no Groups entry without active environment context |
|
|
| Environment-bound admin sidebar Directory Groups entry | yes | Native Filament resource navigation | navigation | shell, route context | no | Secondary Directory surface visible only in active Managed Environment context |
|
|
| Entra Groups list page | yes, contract clarification | Native Filament resource table | resource list, empty state | page, table, tenant-owned query | no | Read-oriented list remains scoped; no new actions |
|
|
| Entra Group View page | yes, destination contract | Native Filament View page/infolist | resource detail, global-search destination | page, record resolution | no | Scoped View destination must be canonical and not legacy `/admin/t` |
|
|
| Global search result | yes | Native Filament global search | search result link | shell, query, URL | no | Results remain environment-scoped and point to View page |
|
|
|
|
## Decision-First Surface Role *(mandatory when operator-facing surfaces are changed)*
|
|
|
|
| Surface | Decision Role | Human-in-the-loop Moment | Immediately Visible for First Decision | On-Demand Detail / Evidence | Why This Is Primary or Why Not | Workflow Alignment | Attention-load Reduction |
|
|
|---|---|---|---|---|---|---|---|
|
|
| Environment-bound Directory Groups navigation | Secondary Context | Operator needs to inspect directory group inventory for the selected environment | `Directory` group and `Groups` item | List and View pages | Secondary because it helps inspect context, not operate a full identity control plane | Workspace -> Managed Environment -> Directory Groups | Avoids direct URL knowledge without adding a broad Identity Center |
|
|
| Groups list | Secondary Context | Operator checks known groups for diagnostics, governance, restore mapping, or supportability | Group name, type, source/freshness signals already in model | View page diagnostics and existing enterprise detail sections | Not primary because it does not decide remediation by itself | Read-oriented directory inventory | Keeps Directory visibility separate from governance decision surfaces |
|
|
| Group View | Tertiary Evidence / Diagnostics | Operator inspects one group safely | Group identity and source details | Existing diagnostics/detail layout | Detail supports evidence and troubleshooting, not lifecycle management | Scoped inspection | Reduces cross-page reconstruction from search or references |
|
|
| Workspace-home sidebar | Secondary Context | Operator is at workspace level without an environment selected | Workspace-owned entries only | N/A | Negative-control surface | Workspace overview IA | Prevents environment-owned noise |
|
|
|
|
## Audience-Aware Disclosure *(mandatory when operator-facing surfaces are changed)*
|
|
|
|
| Surface | Audience Modes In Scope | Decision-First Default-Visible Content | Operator Diagnostics | Support / Raw Evidence | One Dominant Next Action | Hidden / Gated By Default | Duplicate-Truth Prevention |
|
|
|---|---|---|---|---|---|---|---|
|
|
| Directory Groups navigation | operator-MSP | Groups entry under Directory only in environment context | None in navigation | None in navigation | Open Groups | Hidden on workspace home and without environment context | Navigation only links to the list; it does not repeat status summaries |
|
|
| Groups list | operator-MSP, support-platform by capability | Known groups for current environment, type, last seen/freshness where available | Provider IDs and less common columns stay toggleable or detail-only | Raw payloads stay out of default list | Open group | Mutations, raw provider data, and cross-environment data | List scope is the truth; no duplicated environment selector |
|
|
| Group View | operator-MSP, support-platform by capability | Safe group identity summary | Existing enterprise detail diagnostics | Support/raw detail only where already gated by existing detail patterns | Inspect group | Mutation actions and cross-environment data | View adds evidence instead of restating list filters |
|
|
|
|
## UI/UX Surface Classification *(mandatory when operator-facing surfaces are changed)*
|
|
|
|
| Surface | Action Surface Class | Surface Type | Likely Next Operator Action | Primary Inspect/Open Model | Row Click | Secondary Actions Placement | Destructive Actions Placement | Canonical Collection Route | Canonical Detail Route | Scope Signals | Canonical Noun | Critical Truth Visible by Default | Exception Type / Justification |
|
|
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
| Directory Groups sidebar entry | Navigation / Sidebar | Resource navigation | Open Groups | Sidebar item | N/A | Existing page actions only | N/A | Admin Groups collection in active environment context | N/A | Active workspace and environment shell | Groups | Entry exists only when context is active | none |
|
|
| Groups list | List / Table | Read-oriented resource list | Open a group | Clickable row or identifier link | allowed if existing pattern remains | Existing safe secondary actions only | N/A | Admin Groups collection in active environment context | Admin Groups View route for record | Active environment route/session context | Groups | Group name, type, freshness/source signals | none |
|
|
| Group View | Detail / Evidence | Read-only View page | Inspect group | View page | N/A | Existing safe links in header/detail only | N/A | N/A | Admin Groups View route for record | Active environment and record ownership | Group | Group identity and source context | none |
|
|
| Global search result | Search / Navigation | Scoped result link | Open matching group | Search result URL | N/A | N/A | N/A | N/A | Admin Groups View route for record | Active environment context | Group | Matching group title | none |
|
|
|
|
## Operator Surface Contract *(mandatory when operator-facing surfaces are changed)*
|
|
|
|
| Surface | Primary Persona | Decision / Operator Action Supported | Surface Type | Primary Operator Question | Default-visible Information | Diagnostics-only Information | Status Dimensions Used | Mutation Scope | Primary Actions | Dangerous Actions |
|
|
|---|---|---|---|---|---|---|---|---|---|---|
|
|
| Directory Groups navigation | Tenant operator | Continue into directory group inventory for the selected environment | Navigation | Where can I inspect groups for this environment? | Directory / Groups navigation label | None | Environment context only | Navigation only | Open Groups | none |
|
|
| Groups list | Tenant operator, support operator | Determine whether a group is known and inspect it | Read-oriented table | Which groups are known for this managed environment? | Name, type, last seen/source cues already available | Provider IDs, raw/source detail, diagnostics | freshness/source availability, provider type | Existing behavior only; no new actions | Open Group | none added |
|
|
| Group View | Tenant operator, support operator | Inspect one group safely | View page | What is this group and what source context does it belong to? | Group identity and readable metadata | Raw/provider diagnostics if already present/gated | source, freshness, provider type | Read-only inspection | Return/list navigation, existing safe links | none added |
|
|
|
|
## Proportionality Review *(mandatory when structural complexity is introduced)*
|
|
|
|
- **New source of truth?**: no
|
|
- **New persisted entity/table/artifact?**: no
|
|
- **New abstraction?**: no
|
|
- **New enum/state/reason family?**: no
|
|
- **New cross-domain UI framework/taxonomy?**: no
|
|
- **Current operator problem**: Groups are scoped and reachable but undiscoverable in the correct environment-bound admin context.
|
|
- **Existing structure is insufficient because**: The resource bypasses the shared environment-navigation decision with a blanket admin-panel hidden check.
|
|
- **Narrowest correct implementation**: Update `EntraGroupResource` and focused tests to express the environment-bound Directory Groups contract while preserving scoped access/search.
|
|
- **Ownership cost**: Focused navigation, access, and global-search tests. No new architecture ownership.
|
|
- **Alternative intentionally rejected**: A broad Identity Center or M365 admin mirror is rejected because the current product need is only read-oriented Directory Groups visibility inside the selected environment.
|
|
- **Release truth**: Current-release runtime repair.
|
|
|
|
### Compatibility posture
|
|
|
|
This feature assumes a pre-production environment.
|
|
|
|
Backward compatibility, legacy aliases, migration shims, historical fixtures, and compatibility-specific tests are out of scope unless explicitly required by this spec.
|
|
|
|
Canonical replacement is preferred over preservation. Legacy `/admin/t` routes must not be revived.
|
|
|
|
## Testing / Lane / Runtime Impact *(mandatory for runtime behavior changes)*
|
|
|
|
- **Test purpose / classification**: Feature
|
|
- **Validation lane(s)**: confidence
|
|
- **Why this classification and these lanes are sufficient**: Feature tests can prove navigation registration, sidebar cleanliness/presence in response HTML, list/detail scope, global-search scoping, canonical result URLs, no-context denial, cross-environment denial, and no legacy route revival. One focused Browser smoke is required for the real rendered Filament sidebar link and Groups View drilldown.
|
|
- **New or expanded test families**: Focused updates to existing Filament and Directory Groups feature tests plus one explicit Spec 303 Browser smoke. No new heavy-governance family.
|
|
- **Fixture / helper cost impact**: Low. Reuse `createUserWithTenant`, `ManagedEnvironment` factories, `WorkspaceContext`, `ManagedEnvironmentLinks`, and current EntraGroup factories.
|
|
- **Heavy-family visibility / justification**: none.
|
|
- **Special surface test profile**: standard-native-filament
|
|
- **Standard-native relief or required special coverage**: Native Filament resource/navigation/search behavior; use feature tests for backend/context/search truth and one Browser smoke for rendered navigation.
|
|
- **Reviewer handoff**: Confirm lane fit, workspace-home negative controls, environment-bound positive controls, search URL canonicality, no `/admin/t`, and no new mutation actions.
|
|
- **Budget / baseline / trend impact**: Low; focused feature tests plus one narrow Browser smoke.
|
|
- **Escalation needed**: document-in-feature
|
|
- **Active feature PR close-out entry**: Guardrail / Exception / Smoke Coverage
|
|
- **Planned validation commands**:
|
|
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Filament/PanelNavigationSegregationTest.php tests/Feature/Filament/AdminTenantSurfaceParityTest.php tests/Feature/Filament/AdminSharedSurfacePanelParityTest.php tests/Feature/Filament/TenantOwnedResourceScopeParityTest.php tests/Feature/Filament/EntraGroupAdminScopeTest.php tests/Feature/Filament/EntraGroupGlobalSearchScopeTest.php tests/Feature/Filament/PolicyResourceAdminSearchParityTest.php tests/Feature/Filament/PolicyVersionAdminSearchParityTest.php`
|
|
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/DirectoryGroups/BrowseGroupsTest.php tests/Feature/Filament/EntraGroupEnterpriseDetailPageTest.php tests/Feature/Filament/EntraGroupResolvedReferencePresentationTest.php tests/Feature/Filament/PolicyVersionResolvedReferenceLinksTest.php tests/Browser/Spec303AdminDirectoryGroupsCutoverSmokeTest.php`
|
|
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Filament/InventoryCoverageAdminTenantParityTest.php tests/Feature/Filament/InventoryHubDbOnlyTest.php tests/Feature/Filament/InventoryPagesTest.php tests/Feature/Filament/GovernanceArtifacts/GovernanceArtifactAdminPanelRegistrationTest.php tests/Feature/Filament/GovernanceArtifacts/GovernanceArtifactEnvironmentContextTest.php tests/Feature/Filament/GovernanceArtifacts/GovernanceArtifactLegacyTenantPanelGuardTest.php tests/Feature/Operations/LegacyRunRoutesNotFoundTest.php`
|
|
- `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent`
|
|
- `git diff --check`
|
|
|
|
## User Scenarios & Testing *(mandatory)*
|
|
|
|
### User Story 1 - Groups are visible inside an active environment context (Priority: P1)
|
|
|
|
As a tenant operator working inside a selected Managed Environment, I need a secondary Directory Groups entry so I can inspect known directory groups without knowing a direct URL.
|
|
|
|
**Why this priority**: This resolves the exact stale navigation contract identified by Spec 302.
|
|
|
|
**Independent Test**: Render or evaluate the canonical environment-bound admin context and assert `EntraGroupResource` registers navigation while existing authorization checks still protect access.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** an authenticated user with workspace and environment membership, **When** the canonical environment route is active, **Then** Groups appears as an environment-bound Directory surface.
|
|
2. **Given** the same user on the Groups list, **When** records exist in the active environment and another environment, **Then** only active-environment groups are listed.
|
|
3. **Given** the environment context is missing, **When** the admin Groups list is requested, **Then** the response is deny-as-not-found and no groups are leaked.
|
|
|
|
---
|
|
|
|
### User Story 2 - Workspace home remains clean (Priority: P2)
|
|
|
|
As an operator on the workspace home page, I need the sidebar to stay workspace-focused, even if the system remembers my last environment, so I do not confuse environment-owned Directory inventory with workspace-wide state.
|
|
|
|
**Why this priority**: The workspace-home clean-sidebar rule is intentional and must survive the Groups cutover.
|
|
|
|
**Independent Test**: Open the workspace home route with a remembered Managed Environment in session and assert Groups/Directory Groups are absent.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** a workspace-home route and remembered environment context, **When** the sidebar renders, **Then** Groups is absent.
|
|
2. **Given** no active Managed Environment context, **When** `EntraGroupResource::shouldRegisterNavigation()` is evaluated for the admin panel, **Then** it returns false.
|
|
|
|
---
|
|
|
|
### User Story 3 - Global search stays scoped and lands on valid View pages (Priority: P3)
|
|
|
|
As an operator using global search, I need group results to only include the active environment and open the correct View page, so search cannot bypass context or send me to retired routes.
|
|
|
|
**Why this priority**: Global search is already enabled for `EntraGroupResource`; its safety depends on scoped queries and truthful destinations.
|
|
|
|
**Independent Test**: Seed matching groups in multiple workspaces/environments, run admin global search with and without active context, and assert results plus URLs.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** no active Managed Environment context, **When** admin global search runs for a matching group, **Then** no group results are returned.
|
|
2. **Given** matching groups in two environments, **When** admin global search runs with environment A active, **Then** only environment A's group appears.
|
|
3. **Given** a matching result, **When** its URL is inspected, **Then** it points to the canonical admin View destination for that group and does not contain `/admin/t`.
|
|
4. **Given** a user manipulates a View URL for a group in another workspace or environment, **When** the request is made, **Then** access is denied as not found.
|
|
|
|
## Edge Cases
|
|
|
|
- Remembered environment belongs to a different workspace than the current workspace session.
|
|
- Current user is a workspace member but not an environment member.
|
|
- Current user is an environment member but lacks the capability required by existing list/detail policy.
|
|
- A global-search result is generated from a record whose relation is not eager-loaded.
|
|
- A stale URL references a retired `/admin/t/{tenant}` path.
|
|
- A stale direct `/admin/entra-groups` URL is requested after cutover.
|
|
- Existing directory sync action remains present; the implementation must not create or promote new mutation/admin actions.
|
|
|
|
## Functional Requirements
|
|
|
|
- **FR-001**: `EntraGroupResource` MUST have an explicit admin contract as a secondary environment-bound Directory/Identity surface.
|
|
- **FR-002**: Entra Groups MUST NOT appear in workspace-home sidebar navigation when no active Managed Environment context exists.
|
|
- **FR-003**: Entra Groups MUST appear in the environment-bound admin context when the user has required workspace and environment access.
|
|
- **FR-004**: The Groups list MUST only show groups for the active Managed Environment.
|
|
- **FR-005**: The Group View page MUST deny access to records outside the active Managed Environment or workspace.
|
|
- **FR-006**: Admin global search MUST return no Entra Group records without an active authorized Managed Environment context.
|
|
- **FR-007**: Admin global search MUST remain scoped to the active Managed Environment and MUST NOT leak cross-workspace or cross-environment records.
|
|
- **FR-008**: Admin global-search result URLs MUST point to valid View destinations and MUST NOT use retired `/admin/t` or tenant-panel routes.
|
|
- **FR-009**: Existing RBAC, policy, and capability enforcement MUST remain server-side and MUST NOT rely on navigation visibility.
|
|
- **FR-010**: This spec MUST NOT introduce create, edit, delete, membership mutation, sync mutation, destructive group actions, or a broad Directory/Identity Center.
|
|
- **FR-011**: Existing Inventory, Policy, PolicyVersion, BackupSchedule, BackupSet, RestoreRun, Finding, EvidenceSnapshot, EnvironmentReview, StoredReport, and OperationRun routing/navigation behavior MUST NOT regress.
|
|
- **FR-012**: Filament v5 and Livewire v4 patterns MUST be preserved. No Livewire v3 or legacy Filament APIs may be introduced.
|
|
- **FR-013**: Provider registration MUST remain unchanged in `apps/platform/bootstrap/providers.php`.
|
|
- **FR-014**: No assets may be registered or changed by this spec.
|
|
|
|
## Non-Functional Requirements
|
|
|
|
- **NFR-001**: The implementation MUST remain a narrow runtime repair and avoid new abstractions unless repo evidence proves the existing shared helpers cannot express the contract.
|
|
- **NFR-002**: Tests MUST distinguish workspace-home sidebar cleanliness from environment-bound navigation visibility.
|
|
- **NFR-003**: Test fixture and helper cost MUST stay low and reuse existing workspace/environment helpers.
|
|
- **NFR-004**: UI copy MUST avoid implying TenantPilot is a full Microsoft 365 or Entra administration center.
|
|
|
|
## Acceptance Criteria
|
|
|
|
- Entra Groups has a written admin role contract as an environment-bound Directory/Identity surface.
|
|
- Workspace-home sidebar remains clean with and without remembered environment context.
|
|
- Environment-bound admin context can consistently reach Groups when RBAC/context allows.
|
|
- List and View access remain scoped and deny no-context, cross-environment, and cross-workspace access.
|
|
- Global search remains scoped and opens valid View destinations.
|
|
- Search and related links do not point to legacy `/admin/t` routes.
|
|
- Old blanket admin-hidden tests no longer protect Entra Groups incorrectly.
|
|
- Existing focused Inventory, Policy, Evidence, Review, and Operation routing tests remain green.
|
|
|
|
## Success Criteria
|
|
|
|
- Focused validation commands pass.
|
|
- No application code outside the scoped Entra Groups/navigation/search/tests surface is modified.
|
|
- No migrations, assets, provider registration, Graph adapters, jobs, or tenant-panel retirement changes are introduced.
|
|
- Reviewers can tell from `spec.md`, `plan.md`, and `tasks.md` why Groups is visible only in environment context and why this is not an M365 Admin mirror.
|
|
|
|
## Assumptions
|
|
|
|
- Spec 301 is completed and Inventory is the reference for environment-bound navigation without workspace-home leakage.
|
|
- Spec 302 is completed and its audit matrix is authoritative for Entra Groups as the next blocker.
|
|
- Existing Entra Group list/detail/global-search scoping is mostly correct and should be preserved unless tests reveal a narrow bug.
|
|
- Existing directory sync operation behavior is outside this spec unless a test must prove no new action was added.
|
|
|
|
## Risks
|
|
|
|
- Adding `WorkspaceScopedTenantRoutes` to `EntraGroupResource` affects direct admin URLs and related links, so focused route, search, reference-link, and browser-smoke tests must prove the canonical workspace/environment path.
|
|
- Navigation labels such as `Directory` could be mistaken for a larger Identity Center if copy and scope are not restrained.
|
|
- Existing tests may encode the blanket hidden assumption in more than one file.
|
|
|
|
## Open Questions
|
|
|
|
- None blocking. Route posture was verified during implementation; the narrow safe change is to use workspace/environment resource routes and keep scoped canonical View destinations away from `/admin/t`.
|
|
|
|
## Follow-up Spec Candidates
|
|
|
|
- `navigation-contract-split`, only if workspace-home and environment-bound assertions still collide after this cutover.
|
|
- `tenant-panel-dead-code-retirement`, only after active route/navigation dependencies no longer rely on retired tenant-panel assumptions.
|
|
- A broader Directory/Admin Roles IA spec only if future roadmap work explicitly promotes a Directory suite beyond read-oriented Groups.
|