TenantAtlas/specs/341-canonical-link-query-cleanup/plan.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

5.7 KiB
Raw Permalink Blame History

Implementation Plan: Spec 341 - Canonical Link / Query Cleanup

Branch: 341-canonical-link-query-cleanup | Date: 2026-05-31 | Spec: specs/341-canonical-link-query-cleanup/spec.md
Input: Candidate canonical-link-query-cleanup from docs/product/spec-candidates.md + repo inspection of legacy scope query parsing seams.

Summary

Inventory and remove remaining legacy “scope hint” query parsing (tenant, managed_environment_id, etc.) in shared request-scoping seams and align canonical link generation so that:

  • workspace hubs are workspace-wide unless explicitly filtered via environment_id;
  • environment-bound pages are route-owned and do not accept legacy query aliases as authority; and
  • “clear filter” behavior returns to clean canonical URLs.

This is contract hardening; it must not introduce new abstractions, persistence, or UI frameworks.

Technical Context

  • Language/Version: PHP 8.4.15, Laravel 12.52.x
  • Primary Dependencies: Filament v5, Livewire v4, Pest v4
  • Storage: PostgreSQL (no schema changes planned)
  • Testing: Pest Feature tests (navigation + scope contracts)
  • Validation Lanes: fast-feedback (Feature); browser only if later proven necessary for visible UX behaviors that cannot be asserted reliably in Feature tests
  • Target Platform: apps/platform (Sail locally; Dokploy/container posture unchanged)
  • Constraints:
    • no compatibility redirects or “legacy alias preservation”
    • no new packages, migrations, queues, scheduler, storage changes
    • deny-as-not-found semantics remain authoritative

UI / Surface Guardrail Plan

  • Guardrail scope: existing reachable surfaces; navigation + scope contract hardening
  • Affected routes/pages/actions/states (inventory-driven):
    • workspace hubs that accept environment narrowing via environment_id and expose “clear filter” behavior
    • environment-bound pages under /admin/workspaces/{workspace}/environments/{environment}/... that must remain route-owned
    • shared request-scoping seams that must not treat legacy query keys as authority
  • State layers in scope: URL/query + route parameters + session workspace context
  • Handling mode: review-mandatory (scope/authority semantics)
  • Required tests or manual smoke: Feature contract tests for clean vs filtered hub URLs and legacy alias rejection/ignore behavior; browser smoke only if required later
  • UI/Productization coverage decision: existing pages changed / navigation semantics changed; no new reachable surface added; do not update docs/ui-ux-enterprise-audit/* unless implementation materially changes navigation entries or routes (not expected)

Shared Pattern & System Fit

  • Cross-cutting feature marker: yes
  • 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/*
  • Shared abstractions reused: existing hub filter contract helpers, WorkspaceContext, deny-as-not-found semantics, existing guard-test patterns
  • New abstraction introduced?: none
  • Spread control: inventory-driven; limit changes to URL/query scope semantics and canonical link generation only

OperationRun UX Impact

N/A — no OperationRun start/completion/link UX changes.

Implementation Approach

Phase 1 — Repo truth inventory + failing tests first

  • inventory every remaining legacy scope query parsing seam (query keys only, not DB naming)
  • add/adjust Feature tests that fail on todays behavior and encode the intended contract

Phase 2 — Remove legacy query scope hint parsing in shared seams

  • remove or strictly ignore legacy scope hints in:
    • EnsureWorkspaceSelected
    • EnsureEnvironmentContextSelected
    • OperateHubShell
    • EnvironmentRequiredPermissions (query-hint handling only)
  • ensure out-of-scope requests preserve deny-as-not-found semantics
  • ensure link generation:
    • never emits legacy scope query keys
    • uses environment_id only for workspace hub narrowing
    • does not treat environment_id as a replacement for route-owned environment pages

Phase 4 — Regression guards

  • add/extend guard tests that block:
    • parsing legacy scope keys as authority
    • generating navigation URLs containing forbidden scope query keys

Phase 5 — Validation + close-out

  • run the narrowest Feature tests
  • run pint on dirty files and git diff --check

Test Governance Check

  • Test purpose / classification: Feature
  • Affected validation lanes: fast-feedback (Feature)
  • Narrowest proving command(s):
    • cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Navigation --filter=Spec341
  • Fixture / helper cost risks: none expected; reuse existing workspace/environment factories + navigation harness helpers
  • Escalation path: document-in-feature if a bounded exception is proven necessary; otherwise treat legacy alias preservation as a blocker

Deployment / Ops Impact

No migrations, env vars, queues, scheduler, storage, or asset pipeline changes are planned.

Constitution Check (subset)

  • Proportionality: no new persistence/abstractions/taxonomy introduced
  • Compatibility posture: legacy alias preservation is out of scope
  • Scope & isolation: route-owned environment remains authoritative; hub narrowing is environment_id only; deny-as-not-found semantics preserved