## 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
23 KiB
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.phpapps/platform/app/Providers/Filament/AdminPanelProvider.phpapps/platform/app/Support/Tenants/TenantPageCategory.phpapps/platform/app/Support/Navigation/NavigationScope.phpapps/platform/app/Support/OperateHub/OperateHubShell.phpapps/platform/app/Support/Workspaces/WorkspaceContext.phpapps/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=WorkspaceHubcd apps/platform && ./vendor/bin/sail artisan test --filter=Spec314WorkspaceHubNavigationContextSmokegit 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)
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:
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:
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
-
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.
-
Centralize clean workspace hub sidebar/global URL generation.
- Update
WorkspaceSidebarNavigationandAdminPanelProvidernavigation 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.
- Update
-
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.
- Review
-
Neutralize persisted environment-like filters on sidebar/global workspace hub entry.
- Extend or wrap
CanonicalAdminTenantFilterStaterather than adding one-off page patches where possible. - Apply targeted page fixes only where current Livewire/table lifecycle makes a shared helper insufficient.
- Extend or wrap
-
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.
- Provider Connections: no sidebar/global
-
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 addmanaged_environment_idfrom scoped/remembered context.ProviderConnectionResource::resolveContextTenantExternalId()can useWorkspaceContext::lastTenantId().ManagedEnvironmentLinks::providerConnectionsUrl()addsmanaged_environment_idfrom an environment.OperationRunLinks::index()addsmanaged_environment_id,tenant_scope,activeTab,problemClass, and nestedtableFilters.FindingExceptionsQueuehastenantquery state and a clear action that only removes table state.OpenFindingExceptionsQueueControllerredirects withtenant=<external id>.CustomerReviewWorkspaceacceptstenantormanaged_environment_id, converts it to a table filter, and clear only removes table filters.EvidenceOverviewis a reference pattern because clear redirects to a clean URL and resets persisted search/filter state.GovernanceInboxandDecisionRegisteraccept environment query filters and use clean links for clear actions.DecisionRegister::canAccess()andensureRegisterIsVisible()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
tableDeferredFilterswhere 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
-
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.
-
Registry and clean URL generation
- Implement
WorkspaceHubRegistry. - Update
WorkspaceSidebarNavigationandAdminPanelProviderto use registry-backed clean URL generation. - Bypass page/resource
getUrl()methods only when they inject environment scope.
- Implement
-
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.
-
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.
-
Critical page fixes
- Fix Provider Connections, Finding Exceptions Queue, Operations, Decision Register, Customer Review Workspace, Reviews, Evidence Overview.
-
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_paramsit_sidebar_from_environment_dashboard_opens_workspace_hubs_without_environment_contextit_remembered_environment_does_not_affect_workspace_hub_sidebar_urlsit_provider_connections_sidebar_entry_is_workspace_wideit_finding_exceptions_queue_sidebar_entry_is_workspace_wideit_operations_sidebar_entry_does_not_carry_managed_environment_filterit_decision_register_clean_workspace_url_opens_for_authorized_workspace_userit_persisted_environment_table_filters_do_not_override_workspace_hub_sidebar_intent
Recommended exact lanes:
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:
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.mdcurrently 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
tasksoranalyzecommand was found. Preparation analysis is performed by checklist and consistency checks in this package.