TenantAtlas/specs/341-canonical-link-query-cleanup/spec.md
ahmido e324bd7bd6 feat: canonicalize admin scope links and queries (341) (#413)
## 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
2026-05-31 22:46:39 +00:00

14 KiB
Raw Permalink Blame History

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 338340 and Spec 339.

Spec Candidate Check (mandatory — SPEC-GATE-001)

  • Problem: The workspace/environment scope contract is now repo-real (Specs 314322, 338339), 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 338340 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 pages 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 314322, 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.php
      • apps/platform/app/Support/Middleware/EnsureEnvironmentContextSelected.php
      • apps/platform/app/Support/OperateHub/OperateHubShell.php
      • apps/platform/app/Filament/Pages/EnvironmentRequiredPermissions.php (query-hint cleanup only)
  • 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_id is 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_id filter state.
  • Explicit entitlement checks preventing cross-tenant leakage: Any requested environment_id must 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; expected no)
    • 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.php
    • apps/platform/app/Support/Navigation/WorkspaceHubEnvironmentFilter.php
    • apps/platform/app/Filament/Concerns/UsesAdminEnvironmentFilterQueryParameter.php
    • apps/platform/app/Http/Middleware/EnsureWorkspaceSelected.php
    • apps/platform/app/Support/Middleware/EnsureEnvironmentContextSelected.php
    • apps/platform/app/Support/OperateHub/OperateHubShell.php
    • apps/platform/tests/Feature/Navigation/*
  • Existing pattern(s) to extend: Explicit environment_id filter 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=Canonical
    • cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Workspaces --filter=Scope
    • cd apps/platform && ./vendor/bin/sail pint --dirty

Acceptance Criteria

  • AC1: Workspace hubs accept environment_id as 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_id is 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_id on 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.