## 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
112 lines
5.7 KiB
Markdown
112 lines
5.7 KiB
Markdown
# 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 today’s 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
|
||
|
||
### Phase 3 — Align canonical link generation
|
||
|
||
- 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
|