## Summary - remove remaining legacy scope query hint parsing from shared workspace and environment scoping seams so hubs only narrow via explicit `environment_id` - align canonical link generation across workspace hubs, provider connections, audit log, alerts, and decision register flows - add focused Spec 341 regression coverage for canonical link/query behavior and legacy alias rejection - include the Spec 341 artifacts and move the review screenshots into `specs/341-canonical-link-query-cleanup/artifacts/screenshots/` - ignore local `.playwright-mcp` browser tool output so it does not pollute future commits or pull requests ## Validation - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Navigation --filter=Spec341` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Navigation/Spec341CanonicalLinkQueryCleanupTest.php tests/Feature/Navigation/WorkspaceHubEnvironmentFilterContractTest.php tests/Feature/ProviderConnections/ProviderConnectionsWorkspaceHubContractTest.php` - `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent` - `git diff --check` ## Notes - Livewire v4 compliance unchanged - Filament provider registration remains in `apps/platform/bootstrap/providers.php` - no globally searchable resource behavior was changed in this slice - no destructive action behavior was changed - no new Filament assets; deploy `filament:assets` posture is unchanged Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #413
14 KiB
Feature Specification: Spec 341 - Canonical Link / Query Cleanup
Feature Branch: 341-canonical-link-query-cleanup
Created: 2026-05-31
Status: Draft
Input: Candidate canonical-link-query-cleanup from docs/product/spec-candidates.md + repo inspection of remaining legacy scope query hints in middleware/shell after Specs 338–340 and Spec 339.
Spec Candidate Check (mandatory — SPEC-GATE-001)
- Problem: The workspace/environment scope contract is now repo-real (Specs 314–322, 338–339), but some remaining URL/query seams still interpret legacy scope query keys (
tenant,managed_environment_id, etc.) as “environment hints”. That reintroduces hidden scope, weakens trust for credential-adjacent and environment-bound surfaces, and makes deep links less predictable. - Today's failure: Repo inspection shows remaining legacy query parsing in shared request-scoping seams (e.g. environment/tenant selection middleware and
OperateHubShell) that can treat?tenant=or?managed_environment_id=as scope hints outside workspace hubs. This undermines the “explicit or route-owned” scope rule and increases the risk of accidental scope drift resurfacing. - User-visible improvement: Operators can share and reload admin links confidently: workspace hubs are workspace-wide by default and only narrow via explicit
environment_id; environment-bound pages are route-owned and do not accept legacy query aliases as authority; “clear filter” links return to clean canonical URLs; and guard tests block reintroducing legacy query scope behavior. - Smallest enterprise-capable version: Inventory remaining legacy scope query parsing, remove it (or make it strictly ignore-only with safe fallback), align canonical link generation across hubs/shell/middleware seams, and add targeted tests to prevent regressions.
- Explicit non-goals:
- No new UI shell/sidebar/topbar redesign.
- No new routes or panels.
- No new persisted entities, enums, or abstraction frameworks.
- No RBAC model or capability registry changes.
- No provider/OAuth redesign (Spec 281 family).
- No Graph integration changes.
- Permanent complexity imported: A small, explicit inventory + a small set of guard/contract tests around canonical URL/query semantics. No new runtime taxonomy or UI framework.
- Why now: Specs 338–340 and Spec 339 hardened scope/authority. The next risk is “scope drift through links and query parsing” reappearing as features continue. This cleanup locks the contract so future work cannot accidentally revive legacy hints.
- Why not local: Fixing a single page’s link generator is insufficient because the drift sits in shared request-scoping seams. The smallest correct slice must cover the shared parsing/link seams and prove behavior with tests.
- Approval class: Core Enterprise (scope/authorization safety hardening).
- Red flags triggered: Cross-surface navigation semantics + shared middleware/shell seams. Defense: bounded to removing legacy query hint parsing and aligning canonical URL generation; no new frameworking/persistence; tests make the change reviewable.
- Score: Nutzen: 2 | Dringlichkeit: 2 | Scope: 1 | Komplexität: 1 | Produktnähe: 1 | Wiederverwendung: 2 | Gesamt: 9/12
- Decision: approve.
Summary
Canonicalize admin navigation and request scope semantics so that:
- Workspace hubs remain workspace-wide unless explicitly filtered by
environment_id. - Environment-bound pages derive environment context only from route parameters (not legacy query aliases).
- Legacy scope query keys do not grant authority, do not silently narrow results, and do not reintroduce “hidden environment context”.
- Shared seams (
EnsureWorkspaceSelected,EnsureEnvironmentContextSelected,OperateHubShell) do not parse legacy query scope hints for authority.
This is a hardening / cleanup slice: it removes legacy scope query hint parsing and aligns link/query semantics with the existing scope contract.
Completed-Spec Guardrail Result
Related specs are context only and must not be rewritten:
- Workspace hub contracts and legacy alias guards: Specs 314–322, 317, 338.
- Credential-adjacent authority hardening: Spec 339.
- Post-scope browser verification gate: Spec 340.
No specs/341-* package existed before this prep package was created.
Spec Scope Fields (mandatory)
- Scope: canonical-view (navigation + link/query contract hygiene).
- Primary routes / surfaces affected (contract-level; exact list is inventory-driven):
- Workspace hubs that accept environment narrowing via
environment_id(e.g. Governance Inbox, Decision Register, Review Register, Evidence Overview, Audit Log, Alerts, Provider Connections index, Customer Review Workspace). - Environment-bound pages under
/admin/workspaces/{workspace}/environments/{environment}/...that must not accept legacy query scope hints. - Shared request-scoping seams that currently inspect legacy query keys:
apps/platform/app/Http/Middleware/EnsureWorkspaceSelected.phpapps/platform/app/Support/Middleware/EnsureEnvironmentContextSelected.phpapps/platform/app/Support/OperateHub/OperateHubShell.phpapps/platform/app/Filament/Pages/EnvironmentRequiredPermissions.php(query-hint cleanup only)
- Workspace hubs that accept environment narrowing via
- Data Ownership: No schema changes. This slice changes URL/query handling and link generation only.
- RBAC:
- No new capabilities.
- Existing 404 vs 403 semantics remain authoritative.
environment_idis a filter hint only; it must be validated against current workspace context + actor entitlement.
For canonical-view surfaces:
- Default filter behavior when tenant-context is active: Workspace hub clean URLs are workspace-wide and must not inherit remembered environment context, Filament tenant fallback, session table filters, or legacy query keys. If narrowed, the page must show an explicit
environment_idfilter state. - Explicit entitlement checks preventing cross-tenant leakage: Any requested
environment_idmust resolve to an environment in the current workspace that the actor can access; foreign/out-of-scope IDs must fail as not found and must not leak existence.
UI Surface Impact (mandatory — UI-COV-001)
Does this spec add, remove, rename, or materially change any reachable UI surface?
- No UI surface impact
- Existing page changed
- New page/route added
- Navigation changed
- Filament panel/provider surface changed
- New modal/drawer/wizard/action added
- New table/form/state added
- Customer-facing surface changed
- Dangerous action changed
- Status/evidence/review presentation changed
- Workspace/environment context presentation changed
UI/Productization Coverage (UI-COV-001)
- Route/page/surface: Cross-surface link + query semantics for workspace hubs and environment-bound pages (no new UI surface).
- Current page archetype: scope-contract / navigation semantics (global-context-shell + workspace hub filter contract).
- Design depth: Domain Pattern Surface (scope/authority hardening) — minimal visible UX change expected.
- Repo-truth level: repo-verified (existing hub filter contracts + shared middleware/shell code).
- Existing pattern reused: Spec 314/315/316 hub contracts + Spec 317 legacy alias cleanup + Spec 338 contract tests + existing navigation helpers.
- New pattern required: none (tighten and converge; do not invent a new link-normalization framework).
- Screenshot required: no (unless implementation introduces visible copy changes; then add one targeted screenshot in the implementation PR only).
- Page audit required: no (no new archetype; contract hardening only).
- Customer-safe review required: no (scope contract applies broadly; not a customer-safe productization slice).
- Dangerous-action review required: no (no action behavior change; link/query semantics only).
- Coverage files to update (in implementation PR):
docs/ui-ux-enterprise-audit/route-inventory.md(only if routes/nav entries change materially; not expected)docs/ui-ux-enterprise-audit/design-coverage-matrix.md(no new surface; expectedno)N/A - no new reachable UI surface added; contract/URL semantics only
Cross-Cutting / Shared Pattern Reuse (mandatory)
- Cross-cutting feature?: yes.
- Interaction class(es): navigation deep links, scope presentation, URL/query semantics, “clear filter” behavior.
- Systems touched (expected):
apps/platform/app/Support/Navigation/WorkspaceHubNavigation.phpapps/platform/app/Support/Navigation/WorkspaceHubEnvironmentFilter.phpapps/platform/app/Filament/Concerns/UsesAdminEnvironmentFilterQueryParameter.phpapps/platform/app/Http/Middleware/EnsureWorkspaceSelected.phpapps/platform/app/Support/Middleware/EnsureEnvironmentContextSelected.phpapps/platform/app/Support/OperateHub/OperateHubShell.phpapps/platform/tests/Feature/Navigation/*
- Existing pattern(s) to extend: Explicit
environment_idfilter only for workspace hubs; route-owned environment for environment-bound pages; deny-as-not-found for out-of-scope. - Allowed deviation and why: none. This slice removes legacy behavior; it does not add a second link/query interpretation path.
- Consistency impact: One canonical environment filter key (
environment_id) for hubs; no legacy query alias authority anywhere; all “clear filter” links return to clean canonical URLs. - Review focus: “legacy query scope hints are not authority” + tests that make regressions obvious.
OperationRun UX Impact
N/A — no OperationRun start, link, or lifecycle semantics are changed in this slice.
Provider Boundary / Platform Core Check
- Shared provider/platform boundary touched?: no.
- N/A: This is platform scope/navigation hygiene. It must not interpret provider “tenant” identifiers as platform authority.
Proportionality Review
N/A — no new persisted entities, abstraction frameworks, enums/status families, or taxonomy systems are introduced.
Testing / Lane / Runtime Impact (mandatory for runtime behavior changes)
- Test purpose / classification: Feature (scope/link/query contract + regression guard).
- Validation lane(s): fast-feedback (Feature). Browser smoke is optional and only justified if implementation changes visible navigation/URL behavior that cannot be proven reliably in Feature tests alone.
- Planned validation commands:
cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Navigation --filter=Canonicalcd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Workspaces --filter=Scopecd apps/platform && ./vendor/bin/sail pint --dirty
Acceptance Criteria
- AC1: Workspace hubs accept
environment_idas the only environment-narrowing query key; legacy aliases (tenant,tenant_id,managed_environment_id,environment,tenant_scope,tableFilters) never establish filter authority. - AC2: Environment-bound routes derive environment context only from route params and do not parse legacy query aliases as scope hints.
- AC3: “Clear filter” returns to the clean canonical hub URL and clears any persisted hub filter state as per existing contracts.
- AC4: Out-of-scope
environment_idis rejected with deny-as-not-found semantics and does not leak environment existence. - AC5: Targeted Feature tests fail loudly on regression and pass after implementation; no new heavy-governance or browser family is introduced without an explicit spec decision.
User Scenarios & Testing (mandatory)
User Story 1 — Share a canonical workspace hub link (Priority: P1)
As a workspace operator, I can share a link to a workspace hub that is either workspace-wide (clean URL) or explicitly narrowed to one environment using environment_id, and the page shows scope/filter state correctly after reload/back/forward.
Independent Test: A Feature test renders each critical hub with clean URL and with ?environment_id=<id> and asserts filter state, clear-filter behavior, and no legacy query keys.
User Story 2 — Legacy query aliases never become authority (Priority: P1)
As a security reviewer, I can trust that legacy query keys cannot establish environment context or widen results on environment-bound pages or shared scoping middleware.
Independent Test: Feature tests verify that ?tenant= and ?managed_environment_id= are ignored or rejected consistently and never treated as an environment hint for authority.
User Story 3 — Guard tests prevent reintroduction (Priority: P2)
As a developer, I have regression guards that fail CI if new code introduces legacy query parsing or generates links containing legacy scope query keys.
Independent Test: A guard test scans/validates generated navigation URLs for forbidden query keys.
Out of Scope
- Any feature work that changes business logic, capabilities, policies, or data model.
- Any broad UI redesign, new surfaces, or new navigation architecture.
- Any provider/OAuth or credential workflow changes.
- Any compatibility redirects or preserving legacy scope query keys “just in case”.
Risks
- Some internal/shared surfaces may still rely on legacy query hints for environment selection. Implementation must replace that behavior with explicit route-owned context or explicit
environment_idon hubs, and prove it with tests. - Over-scoping this cleanup can become a refactor. Tasks must stay inventory-driven and bounded to canonical scope/query semantics only.
Assumptions
- The workspace/environment scope contract tests and hub filter contracts remain authoritative.
- This is pre-production: removing legacy scope query keys is allowed and preferred over compatibility layers.
Open Questions
None blocking. Any discovered “needed but unclear” legacy behavior must be recorded as a follow-up candidate rather than silently preserved.