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

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

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

  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:

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