TenantAtlas/specs/314-workspace-hub-navigation-context-contract/plan.md
ahmido d85ef4cc1c Spec 314: enforce workspace hub navigation context contract (#369)
## Summary
- add a shared workspace hub registry for canonical workspace-scoped navigation entry
- keep sidebar and global workspace hub URLs free of inherited environment query and filter state
- add focused feature and browser coverage for workspace hub shell and data-scope contracts

## Validation
- 54 focused feature tests passed (205 assertions)
- 1 browser smoke test passed (361 assertions)
- `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent`
- `git diff --check`

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #369
2026-05-16 09:54:29 +00:00

417 lines
23 KiB
Markdown

# Implementation Plan: Workspace Hub Navigation Context Contract
**Branch**: `314-workspace-hub-navigation-context-contract` | **Date**: 2026-05-16 | **Spec**: `specs/314-workspace-hub-navigation-context-contract/spec.md`
**Input**: Feature specification from `specs/314-workspace-hub-navigation-context-contract/spec.md`
## Summary
Implement a hard-cutover workspace hub navigation contract so sidebar/global navigation into workspace-scoped hubs always opens workspace-wide. The implementation creates a narrow workspace hub registry, centralizes clean sidebar/global URL generation, bypasses remembered Managed Environment state for workspace hub entry, and neutralizes environment-like persisted table filters where they can override sidebar/global intent.
Spec 313 is the source of truth for the problem evidence and high-risk pages. Spec 315/316/317 remain follow-ups and must not be pulled into this implementation.
## Technical Context
**Language/Version**: PHP 8.4.15, Laravel 12.52, Filament 5.2.1, Livewire 4.1.4
**Primary Dependencies**: Filament admin panel, Livewire, Pest 4.3.1, PostgreSQL through Sail
**Storage**: PostgreSQL; no migration or data model change planned
**Testing**: Pest Feature/Livewire tests plus focused Pest Browser smoke
**Validation Lanes**: confidence, browser, `git diff --check`
**Target Platform**: Laravel monolith in `apps/platform`
**Project Type**: web application
**Performance Goals**: navigation URL generation and registry lookups are static/lightweight; no additional DB queries in sidebar generation beyond existing visibility checks unless required for existing authorization
**Constraints**: no Graph calls, no queued work, no migrations, no legacy compatibility layer, no route alias support for sidebar/global workspace hub entry
**Scale/Scope**: all workspace hubs from Spec 313, with explicit exclusions for Stored Reports environment route and Support Request action-only surface
## UI / Surface Guardrail Plan
- **Guardrail scope**: workflow/context hardening for existing operator-facing workspace hubs.
- **Native vs custom classification summary**: native Filament navigation/pages/resources; no custom UI system.
- **Shared-family relevance**: navigation, shell/context state, table filter state, evidence/report viewers, governance lists.
- **State layers in scope**: shell, URL-query, page table filters, persisted/session filters, Livewire mount state, remembered environment state.
- **Audience modes in scope**: operator-MSP and support-platform only; customer/read-only rendered content is not changed except Customer Review Workspace default scope.
- **Decision/diagnostic/raw hierarchy plan**: no new decision hierarchy; preserve existing pages and make default scope truthful.
- **Raw/support gating plan**: unchanged.
- **One-primary-action / duplicate-truth control**: no action hierarchy change; prevent scope signal duplication by making shell and data scope agree.
- **Handling modes by drift class or surface**: hidden environment filters on workspace hub sidebar/global entry are hard-stop candidates; Environment CTA and full clear-filter drift are documented follow-ups.
- **Repository-signal treatment**: review-mandatory for any new page-specific context handling; prefer registry/helper path.
- **Special surface test profiles**: global-context-shell, monitoring-state-page, exception-coded-surface.
- **Required tests or manual smoke**: focused Feature/Livewire tests plus browser smoke for Spec 313 critical flows.
- **Exception path and spread control**: none for sidebar/global workspace hub entry.
- **Active feature PR close-out entry**: Guardrail / Exception / Smoke Coverage.
## Shared Pattern & System Fit
- **Cross-cutting feature marker**: yes.
- **Systems touched**:
- `apps/platform/app/Support/Navigation/WorkspaceSidebarNavigation.php`
- `apps/platform/app/Providers/Filament/AdminPanelProvider.php`
- `apps/platform/app/Support/Tenants/TenantPageCategory.php`
- `apps/platform/app/Support/Navigation/NavigationScope.php`
- `apps/platform/app/Support/OperateHub/OperateHubShell.php`
- `apps/platform/app/Support/Workspaces/WorkspaceContext.php`
- `apps/platform/app/Support/Filament/CanonicalAdminTenantFilterState.php`
- affected Filament pages/resources from Spec 313
- **Shared abstractions reused**: `TenantPageCategory`, `NavigationScope`, `WorkspaceContext`, `CanonicalAdminTenantFilterState`, existing Filament page/resource URL APIs where safe.
- **New abstraction introduced? why?**: likely `App\Support\Navigation\WorkspaceHubRegistry`, because more than two pages need the same route/page identity and environment-param stripping rule.
- **Why the existing abstraction was sufficient or insufficient**: existing helpers classify route scope or filter state, but no helper owns workspace hub identity, clean URL generation, and persisted environment-like filter neutralization together.
- **Bounded deviation / spread control**: registry may answer only workspace hub identity and entry cleanup rules; it must not become a product IA framework or provider registry.
## OperationRun UX Impact
- **Touches OperationRun start/completion/link UX?**: no.
- **Central contract reused**: `OperationRunLinks::index()` remains the Operations collection link helper; changes may be limited to clean workspace hub navigation.
- **Delegated UX behaviors**: N/A.
- **Surface-owned behavior kept local**: Operations table/filter UI remains local to `Operations`.
- **Queued DB-notification policy**: N/A.
- **Terminal notification path**: N/A.
- **Exception path**: none.
## Provider Boundary & Portability Fit
- **Shared provider/platform boundary touched?**: yes.
- **Provider-owned seams**: ProviderConnection record actions, credentials, health/verification actions remain provider-owned and unchanged.
- **Platform-core seams**: workspace hub entry contract, workspace navigation URLs, shell/environment context, query-filter stripping.
- **Neutral platform terms / contracts preserved**: Workspace, Managed Environment, provider connection, workspace hub.
- **Retained provider-specific semantics and why**: Provider Connections may retain Microsoft-specific provider values where already stored; this spec must not add provider-specific platform navigation truth.
- **Bounded extraction or follow-up path**: document remaining explicit environment CTA/filter behavior for Spec 315; legacy tenant naming cleanup for Spec 317.
## Constitution Check
- Inventory-first: no inventory truth changes.
- Read/write separation: read/navigation only; no mutating behavior added.
- Graph contract path: no Graph calls.
- Deterministic capabilities: existing capability resolvers remain in force.
- RBAC-UX: workspace membership and capability checks remain server-side; non-members remain 404.
- Workspace isolation: workspace remains selected context and workspace-wide queries must enforce workspace membership.
- Tenant isolation: tenant-owned rows in workspace hubs must be limited to entitled Managed Environments.
- Run observability: no long-running, remote, queued, or scheduled work.
- Automation: N/A.
- Data minimization: no new sensitive data storage.
- Test governance: Feature/Livewire + browser lanes are explicit and bounded.
- Proportionality: new registry is justified by current Spec 313 evidence and more than two concrete surfaces.
- No premature abstraction: registry is allowed because navigation/scope correctness affects isolation and there are many concrete surfaces.
- Persisted truth: no persisted truth added.
- Behavioral state: no new status/state family.
- UI semantics: no badge/status taxonomy.
- Shared pattern first: registry attaches to existing navigation/shell/filter helpers.
- Provider boundary: hardens platform-core navigation and removes provider-adjacent hidden environment inference.
- V1 explicitness / few layers: direct registry + helper updates, no framework.
- Spec discipline / bloat check: proportionality review is in `spec.md`.
- Filament-native UI: existing native Filament pages/resources remain; no styling changes.
## Test Governance Check
- **Test purpose / classification by changed surface**:
- Unit/Feature: registry contents and URL cleanup helpers.
- Feature/Livewire: shell/data/filter state for workspace hubs.
- Browser: critical Spec 313 flows across navigation/reload/back-forward.
- **Affected validation lanes**: confidence and browser.
- **Why this lane mix is narrowest sufficient proof**: helper behavior is deterministic; Livewire proves table state; browser catches hydration/session/back-forward drift found by Spec 313.
- **Narrowest proving commands**:
- `cd apps/platform && ./vendor/bin/sail artisan test --filter=WorkspaceHub`
- `cd apps/platform && ./vendor/bin/sail artisan test --filter=Spec314WorkspaceHubNavigationContextSmoke`
- `git diff --check`
- **Fixture / helper / factory / seed / context cost risks**: tests need explicit workspaces, two Managed Environments, user membership/capability setup, and seeded rows for Provider Connections/Operations/Decision/Register pages where proving row scope.
- **Expensive defaults or shared helper growth introduced?**: no implicit global fixture widening; any new setup helper must be explicit and local to Spec 314 tests unless already reusable.
- **Heavy-family additions, promotions, or visibility changes**: one explicit browser smoke only.
- **Surface-class relief / special coverage rule**: no visual/styling test; global-context-shell and monitoring-state-page state coverage required.
- **Closing validation and reviewer handoff**: reviewer checks no broad rebaseline, no unbounded browser family, no hidden helper default expansion.
- **Budget / baseline / trend follow-up**: none expected.
- **Review-stop questions**: lane fit, hidden stale environment state, workspace entitlement leakage, compatibility shims.
- **Escalation path**: document-in-feature.
- **Active feature PR close-out entry**: Guardrail / Exception / Smoke Coverage.
- **Why no dedicated follow-up spec is needed**: sidebar/global workspace hub contract is the dedicated slice; CTA, clear-filter, legacy cleanup, and durable browser guards already have follow-up specs 315-318.
## Project Structure
### Documentation (this feature)
```text
specs/314-workspace-hub-navigation-context-contract/
|-- spec.md
|-- plan.md
|-- tasks.md
`-- checklists/
`-- requirements.md
```
### Source Code (repository root)
Likely runtime surfaces for later implementation:
```text
apps/platform/app/
|-- Providers/Filament/AdminPanelProvider.php
|-- Support/
| |-- Navigation/WorkspaceHubRegistry.php
| |-- Navigation/WorkspaceSidebarNavigation.php
| |-- Navigation/NavigationScope.php
| |-- Tenants/TenantPageCategory.php
| |-- OperateHub/OperateHubShell.php
| |-- Workspaces/WorkspaceContext.php
| |-- Filament/CanonicalAdminTenantFilterState.php
| |-- ManagedEnvironmentLinks.php
| `-- OperationRunLinks.php
|-- Filament/
| |-- Resources/ProviderConnectionResource.php
| `-- Pages/
| |-- Monitoring/Operations.php
| |-- Monitoring/FindingExceptionsQueue.php
| |-- Monitoring/EvidenceOverview.php
| |-- Governance/GovernanceInbox.php
| |-- Governance/DecisionRegister.php
| `-- Reviews/CustomerReviewWorkspace.php
`-- Http/Controllers/
|-- ClearEnvironmentContextController.php
`-- OpenFindingExceptionsQueueController.php
```
Likely tests for later implementation:
```text
apps/platform/tests/
|-- Feature/Navigation/
| |-- WorkspaceHubRegistryTest.php
| `-- WorkspaceHubSidebarUrlContractTest.php
|-- Feature/Workspaces/
| `-- WorkspaceHubContextContractTest.php
|-- Feature/ProviderConnections/
| `-- ProviderConnectionsWorkspaceHubContractTest.php
|-- Feature/Monitoring/
| |-- FindingExceptionsQueueWorkspaceHubContractTest.php
| |-- OperationsWorkspaceHubContractTest.php
| `-- EvidenceOverviewWorkspaceHubContractTest.php
|-- Feature/Governance/
| `-- DecisionRegisterWorkspaceHubContractTest.php
|-- Feature/Reviews/
| `-- CustomerReviewWorkspaceHubContractTest.php
`-- Browser/
`-- Spec314WorkspaceHubNavigationContextSmokeTest.php
```
**Structure Decision**: Laravel monolith under `apps/platform`; add one support class under `App\Support\Navigation` if implementation confirms no existing support class can own the contract cleanly.
## Complexity Tracking
| Violation | Why Needed | Simpler Alternative Rejected Because |
|---|---|---|
| New registry/support contract | Workspace hub identity and cleanup rules cross many pages and URL helpers | Page-by-page patches would preserve the fragmentation Spec 313 identified |
## Proportionality Review
- **Current operator problem**: stale environment context can silently filter workspace hubs reached from sidebar/global navigation.
- **Existing structure is insufficient because**: `TenantPageCategory`, `NavigationScope`, `WorkspaceSidebarNavigation`, `OperateHubShell`, page URL builders, and table filter helpers each own partial behavior.
- **Narrowest correct implementation**: one registry that lists workspace hubs and forbidden environment query/filter keys, then use it in central navigation and shared filter cleanup.
- **Ownership cost created**: maintain registry when workspace hubs are added/reclassified; keep contract tests updated.
- **Alternative intentionally rejected**: page-local query stripping, because Provider Connections, Operations, Finding Exceptions, Reviews, Evidence, Governance, Audit, and Alerts need the same rule.
- **Release truth**: current-release truth from Spec 313 browser evidence.
## Technical Approach
1. Add or formalize `WorkspaceHubRegistry`.
- Registry answers whether a route/page is a workspace hub.
- Registry exposes the forbidden sidebar/global environment query keys.
- Registry exposes environment-like persisted filter keys to neutralize.
- Registry includes all in-scope Spec 313 workspace hubs and explicit exclusions in tests/docs.
2. Centralize clean workspace hub sidebar/global URL generation.
- Update `WorkspaceSidebarNavigation` and `AdminPanelProvider` navigation items to use clean URL generation.
- Bypass resource/page `getUrl()` behavior if it injects remembered environment state.
- Ensure `OperationRunLinks::index()` is called for workspace-wide Operations without environment params.
3. Stop remembered environment from becoming workspace hub default scope.
- Review `OperateHubShell`, `TenantPageCategory`, `NavigationScope`, `WorkspaceContext`, and Provider Connection tenant inference.
- Keep remembered environment usable only for switcher convenience.
4. Neutralize persisted environment-like filters on sidebar/global workspace hub entry.
- Extend or wrap `CanonicalAdminTenantFilterState` rather than adding one-off page patches where possible.
- Apply targeted page fixes only where current Livewire/table lifecycle makes a shared helper insufficient.
5. Fix critical offenders.
- Provider Connections: no sidebar/global `managed_environment_id`; workspace-wide default query.
- Finding Exceptions Queue: no sidebar/global `tenant`; no stale persisted environment filter.
- Operations: no sidebar/global `managed_environment_id`, `tenant_scope`, or table filter mismatch.
- Decision Register: clean workspace URL opens for authorized users without environment filter.
- Customer Reviews/Reviews/Evidence/Governance/Audit/Alerts: sidebar/global entry is workspace-wide and safe.
6. Browser verify focused Spec 313 flows.
## Existing Repository Surfaces
Spec 313 code ownership map and current code inspection identify these hotspots:
- `WorkspaceSidebarNavigation::build()` emits many workspace hub URLs through page/resource helpers.
- `AdminPanelProvider::navigationItems()` duplicates several workspace hub navigation entries.
- `ProviderConnectionResource::getUrl()` currently can add `managed_environment_id` from scoped/remembered context.
- `ProviderConnectionResource::resolveContextTenantExternalId()` can use `WorkspaceContext::lastTenantId()`.
- `ManagedEnvironmentLinks::providerConnectionsUrl()` adds `managed_environment_id` from an environment.
- `OperationRunLinks::index()` adds `managed_environment_id`, `tenant_scope`, `activeTab`, `problemClass`, and nested `tableFilters`.
- `FindingExceptionsQueue` has `tenant` query state and a clear action that only removes table state.
- `OpenFindingExceptionsQueueController` redirects with `tenant=<external id>`.
- `CustomerReviewWorkspace` accepts `tenant` or `managed_environment_id`, converts it to a table filter, and clear only removes table filters.
- `EvidenceOverview` is a reference pattern because clear redirects to a clean URL and resets persisted search/filter state.
- `GovernanceInbox` and `DecisionRegister` accept environment query filters and use clean links for clear actions.
- `DecisionRegister::canAccess()` and `ensureRegisterIsVisible()` are currently data/query dependent and can reject clean workspace entry.
- `CanonicalAdminTenantFilterState::sync()` can persist or forget tenant-sensitive filters based on active shell tenant.
## Domain / Model Implications
- No model changes.
- No persisted entity changes.
- No migration.
- No seed data change.
- Workspace hub registry is code-level contract only.
## UI / Filament Implications
- Existing Filament pages/resources stay native.
- No page redesign.
- No new panels.
- Admin panel path remains `/admin`.
- Panel provider registration remains in `apps/platform/bootstrap/providers.php`.
- Global search behavior is unchanged; do not enable global search for Provider Connections or other sensitive resources.
- Destructive actions are not added or changed.
- No new assets expected.
## Livewire Implications
- Livewire page `mount()` and table hydration order matter for persisted filters.
- Tests must cover session-persisted table filters and `tableDeferredFilters` where pages use them.
- Livewire v4.1.4 APIs only.
- Avoid adding broad Livewire state machinery; use focused page/helper changes.
## RBAC / Policy Implications
- Preserve existing workspace membership and capability checks.
- Workspace-wide data scope must still apply Managed Environment access entitlement.
- Do not use hidden environment filters as authorization.
- Decision Register must distinguish workspace authorization from empty workspace state.
- Provider Connections credential-adjacent actions remain protected by existing policies/capabilities.
## Audit / Logging / Evidence Implications
- No new audit logging required for navigation/read behavior.
- Existing audit logs for mutating actions must remain unchanged.
- Browser verification screenshots may be stored under `specs/314-workspace-hub-navigation-context-contract/artifacts/screenshots/` if useful.
## Data / Migration Implications
- No migrations.
- No seeders.
- No backfills.
- No compatibility fields.
- No data cleanup.
## Implementation Phases
1. **Contract and tests first**
- Create registry contract tests for workspace hub entries and forbidden query params.
- Add sidebar/global URL tests covering the full registry.
- Add remembered-environment and persisted-filter regression tests for critical hubs.
2. **Registry and clean URL generation**
- Implement `WorkspaceHubRegistry`.
- Update `WorkspaceSidebarNavigation` and `AdminPanelProvider` to use registry-backed clean URL generation.
- Bypass page/resource `getUrl()` methods only when they inject environment scope.
3. **Shell and remembered environment isolation**
- Adjust shell/context resolution so workspace hubs from sidebar/global entry are tenantless.
- Ensure remembered environment is only switcher convenience for workspace hubs.
4. **Persisted filter safety**
- Extend shared helper for environment-like filter neutralization.
- Apply critical page integrations for Provider Connections, Finding Exceptions Queue, Operations, Customer Reviews, Reviews, Evidence, Governance Inbox, Decision Register, Audit Log, and Alerts.
5. **Critical page fixes**
- Fix Provider Connections, Finding Exceptions Queue, Operations, Decision Register, Customer Review Workspace, Reviews, Evidence Overview.
6. **Validation and browser verification**
- Run focused tests.
- Run focused browser smoke flows from Spec 313.
- Record remaining follow-ups for 315/316/317.
## Test Strategy
Required tests:
- `it_workspace_hub_sidebar_urls_do_not_include_environment_query_params`
- `it_sidebar_from_environment_dashboard_opens_workspace_hubs_without_environment_context`
- `it_remembered_environment_does_not_affect_workspace_hub_sidebar_urls`
- `it_provider_connections_sidebar_entry_is_workspace_wide`
- `it_finding_exceptions_queue_sidebar_entry_is_workspace_wide`
- `it_operations_sidebar_entry_does_not_carry_managed_environment_filter`
- `it_decision_register_clean_workspace_url_opens_for_authorized_workspace_user`
- `it_persisted_environment_table_filters_do_not_override_workspace_hub_sidebar_intent`
Recommended exact lanes:
```bash
cd apps/platform && ./vendor/bin/sail artisan test --filter=WorkspaceHub
cd apps/platform && ./vendor/bin/sail artisan test --filter=ProviderConnectionsWorkspaceHub
cd apps/platform && ./vendor/bin/sail artisan test --filter=FindingExceptionsQueueWorkspaceHub
cd apps/platform && ./vendor/bin/sail artisan test --filter=OperationsWorkspaceHub
cd apps/platform && ./vendor/bin/sail artisan test --filter=DecisionRegisterWorkspaceHub
cd apps/platform && ./vendor/bin/sail artisan test --filter=CustomerReviewWorkspaceHub
cd apps/platform && ./vendor/bin/sail artisan test --filter=EvidenceOverviewWorkspaceHub
cd apps/platform && ./vendor/bin/sail artisan test --filter=Spec314WorkspaceHubNavigationContextSmoke
git diff --check
```
## Browser Verification Plan
Required pages:
- Provider Connections
- Finding Exceptions Queue
- Operations
- Decision Register
- Customer Reviews
- Evidence
- Reviews
- Governance Inbox
Required flows:
- Environment Dashboard -> Sidebar -> Page
- Workspace Overview -> Sidebar -> Page
- Reload after sidebar entry
- Back/forward for Provider Connections, Customer Reviews, Finding Exceptions Queue, Operations, and Decision Register
Verify:
- shell context
- URL query params
- visible filters
- table filters
- row scope where seeded data proves it
Screenshots may be saved under:
```text
specs/314-workspace-hub-navigation-context-contract/artifacts/screenshots/
```
## Rollout Considerations
- Hard cutover only; no compatibility layer.
- No env vars.
- No migrations.
- No queues or scheduler changes.
- No storage/volume changes.
- Staging validation should run focused tests and browser smoke before production promotion once production exists.
## Risk Controls
- Add registry contract tests so future workspace hubs cannot leak environment query params silently.
- Keep Environment CTA filters out of this spec except where they block sidebar/global distinction.
- Preserve environment-owned route behavior.
- Keep Provider Connections action authorization untouched.
- Record any remaining URL/filter drift as 315/316/317 follow-up, not hidden implementation scope.
## Spec Preparation Notes
- Candidate was directly supplied by the user and is supported by Spec 313.
- `docs/product/spec-candidates.md` currently says no safe automatic next-best-prep target remains, but this is an explicit manual promotion from completed Spec 313 audit evidence.
- Existing Specs 311, 312, and 313 are completed/historical context and are not modified by this preparation.
- The repository provides Bash helpers for feature creation and plan setup, but no local `tasks` or `analyze` command was found. Preparation analysis is performed by checklist and consistency checks in this package.