# Feature Specification: Admin Inventory Navigation Cutover

**Feature Branch**: `301-admin-inventory-navigation-cutover`  
**Created**: 2026-05-14  
**Status**: Draft  
**Input**: User description: "mach als naechstes admin-inventory-navigation-cutover und mach mit 301 weiter"

## Spec Candidate Check *(mandatory - SPEC-GATE-001)*

- **Problem**: Inventory is already a repo-real admin surface under workspace and managed-environment routing, but `InventoryCluster` and `InventoryCoverage` still carry a blanket admin-hidden navigation rule. Operators can reach parts of Inventory through canonical URLs, links, or remembered environment context, while the sidebar still implies Inventory is not an admin-runtime surface.
- **Today's failure**: The admin sidebar hides Inventory even when an operator is inside a valid `/admin/workspaces/{workspace}/environments/{environment}` context. Current navigation tests protect both the intended workspace-home clean-sidebar rule and the stale blanket "admin can never see Inventory" rule, so a real product break is encoded as regression protection.
- **User-visible improvement**: Tenant operators can discover Inventory Items and Coverage from an environment-bound admin context without reopening tenant-owned navigation on the workspace home page.
- **Smallest enterprise-capable version**: Limit the change to Inventory Items, Inventory Coverage, and the Inventory cluster visibility contract. Keep workspace-home sidebar cleanliness intact and update tests to distinguish workspace-level navigation from environment-bound navigation.
- **Explicit non-goals**: No Entra Groups navigation decision, no generic tenant-owned surface audit, no navigation framework redesign, no system-panel changes, no workspace-home information-architecture rewrite, no tenant-panel dead-code retirement, and no new persisted state.
- **Permanent complexity imported**: No new models, tables, statuses, enums, services, registries, or UI frameworks. The lasting cost is a narrower navigation contract plus focused Filament feature/browser proof.
- **Why now**: `docs/product/spec-candidates.md` marks this as the immediate manual-promotion slice because Inventory is the clearest repo-verified navigation drift seam after the workspace-first managed-environment cutover work.
- **Why not local**: A one-line visibility flip would risk reintroducing tenant-owned navigation on workspace home. The repair must encode the distinction between workspace-scope and environment-scope navigation in tests.
- **Approval class**: Workflow Compression
- **Red flags triggered**: None. The slice changes no new truth model and introduces no framework or taxonomy.
- **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**:
  - `/admin/workspaces/{workspace}/environments/{environment}/inventory`
  - `/admin/workspaces/{workspace}/environments/{environment}/inventory/inventory-coverage`
  - `/admin/workspaces/{workspace}` as the workspace-home negative-control surface
- **Data Ownership**: Inventory rows and coverage truth remain managed-environment-owned records with `workspace_id` and `managed_environment_id` enforced by existing runtime and policy paths. No data model changes are in scope.
- **RBAC**: Workspace membership plus managed-environment membership remain required. Inventory visibility requires the existing environment view capability (`Capabilities::TENANT_VIEW`) through current policy/capability paths. Non-members remain deny-as-not-found. Members missing capability remain denied by existing capability checks.

For canonical-view specs, the spec MUST define:

- **Default filter behavior when tenant-context is active**: Environment-bound routes resolve their environment from the canonical route. Workspace-scoped routes may use remembered environment context for recovery and links, but must not register environment-owned sidebar navigation on workspace home.
- **Explicit entitlement checks preventing cross-tenant leakage**: Existing `OperateHubShell`, `WorkspaceContext`, `WorkspaceScopedTenantRoutes`, `ResolvesPanelTenantContext`, and resource/page `canAccess` or `canViewAny` checks remain the entitlement boundary. This slice must not bypass those paths.

## 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)**: navigation entry points, Filament cluster navigation, environment-scoped sidebar visibility
- **Systems touched**:
  - `apps/platform/app/Filament/Clusters/Inventory/InventoryCluster.php`
  - `apps/platform/app/Filament/Pages/InventoryCoverage.php`
  - `apps/platform/app/Filament/Resources/InventoryItemResource.php`
  - `apps/platform/app/Support/Navigation/NavigationScope.php`
  - `apps/platform/app/Support/OperateHub/OperateHubShell.php`
  - `apps/platform/tests/Feature/Filament/PanelNavigationSegregationTest.php`
  - `apps/platform/tests/Feature/Filament/InventoryCoverageAdminTenantParityTest.php`
- **Existing pattern(s) to extend**: `NavigationScope::shouldRegisterEnvironmentNavigation()`, workspace-scoped resource routing via `WorkspaceScopedTenantRoutes`, and current `OperateHubShell` environment context resolution.
- **Shared contract / presenter / builder / renderer to reuse**: `NavigationScope` and the current environment route/context helpers. No new navigation contract is introduced.
- **Why the existing shared path is sufficient or insufficient**: The shared path is sufficient for resources that already call `NavigationScope::shouldRegisterEnvironmentNavigation()`. It is insufficient only where Inventory cluster/page classes still short-circuit on `panel === admin` before considering environment context.
- **Allowed deviation and why**: none. Inventory should converge on the shared environment-navigation path.
- **Consistency impact**: Inventory Items and Inventory Coverage must follow the same environment-scope visibility rule while workspace home stays clean.
- **Review focus**: Reviewers must verify the implementation removes the stale blanket admin-hidden rule only for Inventory, does not make Entra Groups visible, and does not show environment-owned navigation on workspace home.

## 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
- **Shared OperationRun UX contract/layer reused**: N/A
- **Delegated start/completion UX behaviors**: N/A
- **Local surface-owned behavior that remains**: Existing Inventory "Run Inventory Sync" behavior remains unchanged and continues to use current OperationRun UX paths.
- **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?**: no
- **Boundary classification**: N/A
- **Seams affected**: N/A
- **Neutral platform terms preserved or introduced**: "workspace", "environment", "Inventory", and "Coverage" remain the operator-facing terms for this slice.
- **Provider-specific semantics retained and why**: Inventory item metadata may still include provider-specific policy type detail, but this slice does not change that provider-owned truth.
- **Why this does not deepen provider coupling accidentally**: The work is navigation visibility only and reuses current environment routing/context.
- **Follow-up path**: none

## 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 |
|---|---|---|---|---|---|---|
| Environment-bound admin sidebar Inventory cluster | yes | Native Filament cluster/resource navigation | navigation | shell, route context | no | Converges Inventory on existing environment-navigation rules |
| Inventory Coverage page navigation registration | yes | Native Filament page navigation | navigation | shell, page, route context | no | Visibility only; page behavior remains DB-only |
| Workspace home sidebar | yes, negative control | Native Filament panel navigation | navigation | shell | no | Must remain clean when no active environment context exists |

## 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 admin sidebar Inventory cluster | Secondary Context | Operator needs to inspect observed inventory or coverage after choosing an environment | Inventory entry points in the environment sidebar | Inventory item list and coverage table remain inside their pages | Secondary because the sidebar helps resume the workflow, not make the inventory decision itself | Follows Workspace -> Managed Environment -> Inventory | Removes need to know direct URLs |
| Workspace home sidebar | Secondary Context | Operator is reviewing workspace-wide state without an environment selected | Workspace-owned entries only | Environment-owned detail remains behind environment selection | It is a negative-control surface for scope clarity | Follows workspace overview IA | Prevents tenant-owned noise at workspace level |

## 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 |
|---|---|---|---|---|---|---|---|
| Environment-bound Inventory navigation | operator-MSP | Inventory Items and Coverage entries | Existing page-level filters, tables, basis links | Existing diagnostics remain inside existing pages | Open Inventory | Raw payloads remain out of navigation | Navigation only links to existing Inventory truth |
| Workspace home sidebar | operator-MSP | Workspace-level entries only | N/A | N/A | Choose or open an environment through existing workspace flows | Inventory entries hidden without environment context | Workspace home does not duplicate environment inventory status |

## 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 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Environment-bound Inventory sidebar | Navigation / Sidebar | Cluster navigation | Open Inventory Items or Coverage | Sidebar navigation item | N/A | Existing page actions only | N/A | `/admin/workspaces/{workspace}/environments/{environment}/inventory` | `/admin/workspaces/{workspace}/environments/{environment}/inventory/{record}` | Workspace and environment route path | Inventory | Entry availability reflects active environment context | none |
| Inventory Coverage page | List / Table / Read-only | Read-only derived report page | Review coverage gaps | Page navigation | no row inspect | Existing table/filter controls | N/A | `/admin/workspaces/{workspace}/environments/{environment}/inventory/inventory-coverage` | N/A | Workspace and environment route path | Coverage | Coverage state and follow-up guidance | 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 |
|---|---|---|---|---|---|---|---|---|---|---|
| Environment-bound Inventory navigation | Tenant operator | Continue to observed Inventory within selected environment | Sidebar navigation | Where do I inspect current inventory for this environment? | Inventory Items and Coverage navigation labels | None in navigation | Environment context only | Navigation only | Open Inventory / Open Coverage | none |
| Inventory Coverage page | Tenant operator | Decide which Inventory policy families need follow-up | Read-only report table | Which inventory types are covered or need follow-up? | Coverage state, type, guidance, observed count | Existing detailed basis links and type keys | coverage state, observed item count, restore/dependency metadata | Read-only page; existing Inventory Sync action remains on Inventory Items | Open inventory items | none |

## 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**: Inventory is discoverable only through direct or remembered routes in contexts where it should be first-class environment navigation.
- **Existing structure is insufficient because**: The shared `NavigationScope` rule exists but Inventory cluster/page classes bypass it with a blanket admin-panel block.
- **Narrowest correct implementation**: Remove or narrow the blanket admin-hidden rule for Inventory only and prove workspace-home remains clean.
- **Ownership cost**: Focused navigation tests plus one browser smoke if the sidebar behavior changes visibly.
- **Alternative intentionally rejected**: A generic tenant-owned surface audit is deferred to the next candidate because it would widen this immediate repair.
- **Release truth**: Current-release truth.

### 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.

## Testing / Lane / Runtime Impact *(mandatory for runtime behavior changes)*

- **Test purpose / classification**: Feature plus one Browser smoke if visible sidebar rendering is changed
- **Validation lane(s)**: confidence, browser
- **Why this classification and these lanes are sufficient**: Feature tests can prove navigation registration, route generation, workspace-home absence, environment-bound presence, and RBAC/context isolation. Browser proof is justified only for the actual sidebar rendering contract because this is a user-visible navigation repair.
- **New or expanded test families**: Focused expansion of `tests/Feature/Filament/PanelNavigationSegregationTest.php`, `InventoryCoverageAdminTenantParityTest.php`, and optionally one `tests/Browser/Spec301InventoryNavigationCutoverSmokeTest.php`.
- **Fixture / helper cost impact**: Low. Reuse current `createUserWithTenant`, `WorkspaceContext`, `ManagedEnvironmentLinks`, and Inventory fixtures.
- **Heavy-family visibility / justification**: No heavy-governance family. One bounded browser smoke is allowed because the product break is navigation visibility.
- **Special surface test profile**: standard-native-filament
- **Standard-native relief or required special coverage**: Native Filament navigation is sufficient; no custom UI proof is needed beyond the sidebar smoke if implemented.
- **Reviewer handoff**: Confirm lane fit, no hidden Entra Groups scope, no generic route audit implementation, and workspace-home negative controls remain explicit.
- **Budget / baseline / trend impact**: Low; one focused browser smoke at most.
- **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/InventoryCoverageAdminTenantParityTest.php tests/Feature/Filament/InventoryHubDbOnlyTest.php tests/Feature/Filament/InventoryPagesTest.php`
  - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Browser/Spec301InventoryNavigationCutoverSmokeTest.php` if the browser smoke is added
  - `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent`

## User Scenarios & Testing *(mandatory)*

### User Story 1 - Inventory appears in environment-bound admin navigation (Priority: P1)

As a tenant operator working inside a selected managed environment, I need Inventory entry points in the admin sidebar so I can inspect observed items and coverage without knowing direct URLs.

**Why this priority**: This is the product break named by the candidate. Inventory already has runtime access, but the sidebar hides it.

**Independent Test**: In an admin request path matching `/admin/workspaces/{workspace}/environments/{environment}`, assert `InventoryCluster`, `InventoryItemResource`, and `InventoryCoverage` register navigation while preserving current authorization checks.

**Acceptance Scenarios**:

1. **Given** an authenticated operator with workspace and environment membership, **When** they open the canonical environment route, **Then** Inventory Items and Coverage are visible in the environment-bound sidebar.
2. **Given** a valid environment-bound route, **When** `InventoryCoverage::shouldRegisterNavigation()` is evaluated, **Then** it returns true through the shared environment-navigation contract.
3. **Given** `InventoryItemResource::getUrl('index', panel: 'admin', tenant: $environment)`, **When** the URL is generated, **Then** the path starts with `/admin/workspaces/{workspace}/environments/{environment}/` and not `/admin/t/`.
4. **Given** `InventoryCoverage::getUrl(panel: 'admin', tenant: $environment)`, **When** the URL is generated after this slice, **Then** the path resolves to the canonical workspace/environment Inventory Coverage route rather than a flat `/admin/inventory/inventory-coverage` route.

---

### User Story 2 - Workspace home remains clean (Priority: P2)

As an operator on the workspace home page, I need the sidebar to show workspace-level navigation only, even if the system remembers my last environment, so I do not mistake tenant-owned Inventory work for workspace-wide state.

**Why this priority**: The intended workspace-home clean-sidebar rule is still valid and must not be undone while fixing Inventory.

**Independent Test**: With a remembered environment in session, open the workspace home route and assert Inventory Items, Coverage, and other environment-owned entries are not present.

**Acceptance Scenarios**:

1. **Given** a workspace home route and a remembered environment in session, **When** the sidebar renders, **Then** Inventory navigation is absent.
2. **Given** no active environment context, **When** Inventory cluster/page navigation registration is evaluated, **Then** the result does not make Inventory visible on workspace home.

---

### User Story 3 - Inventory Coverage follows canonical context (Priority: P3)

As a tenant operator, I need Inventory Coverage to resolve the same managed environment as the Inventory Items list so coverage truth is scoped to the selected environment and not a stale remembered or query-hint target.

**Why this priority**: `InventoryCoverage` currently has route/context proof, but its navigation registration still protects the wrong admin-hidden assumption.

**Independent Test**: Seed two managed environments in one workspace, give the operator access to both, open Coverage through the canonical route for one environment, and assert coverage rows come from that environment only.

**Acceptance Scenarios**:

1. **Given** two environments with different coverage truth, **When** the operator opens Coverage from the first environment route, **Then** only the first environment's coverage is shown.
2. **Given** an invalid workspace/environment pair, **When** the operator opens Inventory or Coverage, **Then** the response remains deny-as-not-found.

## Edge Cases

- Workspace home with remembered environment must not register Inventory.
- Livewire update requests should use the referer path through `NavigationScope::effectivePath()` and preserve the same environment-bound vs workspace-bound decision.
- Invalid workspace/environment route pair must remain not found.
- Operators without environment membership must not see or access Inventory.
- Operators with environment membership but missing view capability must remain denied by existing capability checks.
- Entra Groups must stay out of scope even though it appears in the same candidate group.

## Requirements *(mandatory)*

### Functional Requirements

- **FR-301-001**: Inventory cluster navigation MUST register in the admin panel when the current request is an environment-bound admin surface.
- **FR-301-002**: Inventory Coverage navigation MUST register in the admin panel when the current request is an environment-bound admin surface.
- **FR-301-003**: Inventory Items navigation MUST keep using the current environment-navigation contract and remain visible only on environment-bound admin surfaces.
- **FR-301-004**: Inventory navigation MUST remain absent from workspace-home sidebar routes where no active environment route context exists, even when a remembered environment exists in session.
- **FR-301-005**: Inventory Coverage MUST resolve managed-environment context through the canonical admin route or existing remembered environment contract without adding a new query/filter state.
- **FR-301-006**: Inventory Coverage URL generation MUST align to the canonical workspace/environment Inventory Coverage route when an environment context is supplied.
- **FR-301-007**: The implementation MUST update navigation tests so they no longer protect the stale blanket rule that Inventory can never register in the admin panel.
- **FR-301-008**: The implementation MUST preserve deny-as-not-found behavior for wrong workspace/environment pairs and non-members.
- **FR-301-009**: The implementation MUST NOT make Entra Groups visible or decide its navigation posture.
- **FR-301-010**: The implementation MUST NOT introduce a new navigation framework or route audit artifact.

### Non-Functional Requirements

- **NFR-301-001**: The slice must stay DB-only for Inventory page rendering and must not add outbound Graph calls or background work to navigation/page load.
- **NFR-301-002**: Filament v5 and Livewire v4 behavior must remain compatible with the current panel provider registration model.
- **NFR-301-003**: No new assets are registered.
- **NFR-301-004**: No new persistence, schema, queue, cron, provider, or OperationRun lifecycle change is introduced.
- **NFR-301-005**: Tests must stay focused and must not broaden into a tenant-owned surface route audit.

### RBAC / Security Requirements

- **SEC-301-001**: UI navigation visibility is not authorization. Server-side `canAccess`, `canViewAny`, policy, and capability checks remain the source of truth.
- **SEC-301-002**: Workspace non-members and environment non-members must receive not-found semantics through existing routes/context resolution.
- **SEC-301-003**: Member-without-capability denial must remain enforced by the existing capability resolver.

### Auditability / Observability Requirements

- **AUD-301-001**: This navigation-only slice introduces no new audit event.
- **AUD-301-002**: Existing Inventory Sync audit and OperationRun behavior remain unchanged.

### Data / Truth-Source Requirements

- **DATA-301-001**: Inventory remains last-observed managed-environment-owned truth.
- **DATA-301-002**: Coverage remains derived from the current Inventory Sync basis in `OperationRun.context`.
- **DATA-301-003**: No new snapshot, backup, or inventory source of truth is introduced.

## Success Criteria *(mandatory)*

- **SC-301-001**: Environment-bound admin navigation shows Inventory Items and Coverage for entitled operators.
- **SC-301-002**: Workspace-home navigation remains free of Inventory and other tenant-owned entries when no environment context is active.
- **SC-301-003**: The focused Filament navigation tests distinguish workspace-home absence from environment-bound presence.
- **SC-301-004**: Inventory Coverage continues to show only the selected environment's coverage truth.
- **SC-301-005**: No Entra Groups, route-audit, system-panel, provider-boundary, asset, schema, or OperationRun changes are included.

## Assumptions

- `301` is intentionally requested by the user and is free in `specs/`.
- The current branch may be ahead of `origin/platform-dev`, but the working tree was clean before Spec Kit execution.
- The existing `/admin/workspaces/{workspace}/environments/{environment}` route family is the canonical route family for this slice.
- The current `InventoryItemResource` already has a View page, so global search destination eligibility remains satisfied if global search is enabled.

## Risks

- A too-broad change could expose all tenant-owned navigation on workspace home.
- A too-local change could make the cluster visible while leaving Coverage hidden.
- Browser-only confidence would be weak without explicit feature tests for `shouldRegisterNavigation()`.
- Updating historical completed cutover specs would corrupt implementation history; they must remain context only.

## Out of Scope

- Entra Groups navigation.
- Tenant-owned surface route audit.
- Navigation contract split.
- Tenant-panel dead-code retirement.
- System panel changes.
- Workspace-home IA redesign.
- New provider capability semantics.
- New persisted state, migrations, models, or services.
- Any Graph API contract changes.

## Follow-up Spec Candidates

- `tenant-owned-surface-route-audit`
- `admin-directory-groups-cutover`
- `navigation-contract-split`, only if drift remains after the first three candidates
- `tenant-panel-dead-code-retirement`

## Manual Promotion Notes

- **Selected candidate title**: `admin-inventory-navigation-cutover`
- **Source location**: `docs/product/spec-candidates.md`, Admin Workspace Navigation & Tenant-owned Surface Repair candidate group.
- **Why selected**: User explicitly promoted it and requested number `301`; the candidate is the first recommended item in the group and is identified as the only immediately implementation-ready slice.
- **Close alternatives deferred**: `tenant-owned-surface-route-audit`, `admin-directory-groups-cutover`, `navigation-contract-split`, and `tenant-panel-dead-code-retirement` require separate product decisions or follow this repair.
- **Roadmap relationship**: UI and product maturity polish plus workspace-first managed-environment cutover follow-through.
- **Completed-spec guardrail result**: Specs `279` through `300` are treated as historical/contextual completed or in-flight cutover evidence and are not modified by this preparation.
