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