## Summary - enforce the canonical workspace/environment scope contract for workspace hubs and environment-owned surfaces - replace first-party Operations deep links that leaked Filament `tableFilters[...]` internals with stable product-level query behavior - add the sidebar scope indicator and split environment-page navigation into explicit `Workspace-wide` and `Workspace admin` groups - remove redundant tenantless `All environments` scope badges from workspace-wide pages while preserving explicit environment filter affordances - include the Spec 338 artifacts, guard tests, and browser smoke coverage for the new contract ## Validation - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Navigation/Spec338EnvironmentSidebarSeparationTest.php tests/Feature/Navigation/Spec338OperationRunLinksQueryContractTest.php tests/Feature/Navigation/Spec338SidebarScopeIndicatorTest.php tests/Feature/Filament/PanelNavigationSegregationTest.php` - `cd apps/platform && ./vendor/bin/sail php vendor/bin/pest tests/Browser/Spec338ScopeContractSmokeTest.php --compact` ## Notes - Livewire v4 compliance unchanged - Filament provider registration remains in `bootstrap/providers.php` - no destructive action behavior changed - no migrations, env var changes, or new Filament asset registration Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #409
124 lines
7.2 KiB
Markdown
124 lines
7.2 KiB
Markdown
# Implementation Plan: Spec 338 - Workspace / Environment Resource Scope Contract
|
||
|
||
- Branch: `338-workspace-environment-resource-scope-contract`
|
||
- Date: 2026-05-30
|
||
- Spec: `specs/338-workspace-environment-resource-scope-contract/spec.md`
|
||
- Input: User-provided Spec 338 draft + repo inspection for link/query seams.
|
||
|
||
## Summary
|
||
|
||
Harden TenantPilot’s resource scope contract by tightening the canonical deep-link and query contract for workspace hubs and by eliminating first-party helper outputs that encode Filament internals (`tableFilters[...]`) as a product-level URL contract.
|
||
|
||
This is contract-first and targeted:
|
||
|
||
- `OperationRunLinks::index(..., operationType: ...)` must stop emitting `tableFilters[type][value]`.
|
||
- Evidence scope special casing under `/admin/evidence/*` must be either proven real and contractual, or removed as stale ambiguity.
|
||
- Environment-owned sidebar navigation must keep environment-owned entries primary and move workspace-wide/admin links into explicitly labeled cross-scope groups.
|
||
- Baseline ownership/navigation is regression-only (Spec 320 already completed; do not reopen).
|
||
|
||
## Technical Context
|
||
|
||
- Language/Version: PHP 8.4.15, Laravel 12.52.x.
|
||
- Primary Dependencies: Filament 5.2.x, Livewire 4.1.x, Pest 4.x, Tailwind CSS 4.x.
|
||
- Storage: PostgreSQL; no schema change expected.
|
||
- Testing: Pest Feature tests + minimal browser smoke only if navigation presentation is materially affected.
|
||
- Validation Lanes: fast-feedback (Feature) + browser (smoke, scoped).
|
||
- Target Platform: Sail locally; Dokploy/container deployment posture unchanged.
|
||
- Project Type: Laravel monolith under `apps/platform`.
|
||
- Constraints: No new persisted truth, migrations, packages, env vars, queue/scheduler changes, or route architecture rewrite.
|
||
|
||
## UI / Surface Guardrail Plan
|
||
|
||
- **Guardrail scope**: changed existing operator-facing scope/link behavior (navigation + deep links).
|
||
- **Affected surfaces**:
|
||
- Workspace hub links to Operations (`OperationRunLinks` and any `CanonicalNavigationContext` filter payload usage).
|
||
- Evidence Overview hub + “clear environment context” redirect behavior.
|
||
- Environment → workspace hub “filtered” links (`environment_id` must remain canonical).
|
||
- Environment sidebar grouping for workspace-wide/admin links.
|
||
- **Native vs custom**: native Filament + existing project navigation helpers; no custom UI framework.
|
||
- **Shared-family relevance**: navigation entry points, scope presentation, deep links, hub filtering, OperationRun “view in collection” links.
|
||
- **State layers in scope**: shell scope (route-owned), URL query contract, local table filter state (internal translation only).
|
||
- **Handling modes**: review-mandatory.
|
||
- **Required tests / smoke**:
|
||
- Feature tests for URL contract + helper output.
|
||
- Optional minimal browser smoke when sidebar/scope presentation changes are user-visible.
|
||
- **UI/Productization coverage**: no new routes/pages expected; capture screenshots only when needed to prove a scope regression fix.
|
||
|
||
## Shared Pattern & System Fit
|
||
|
||
- **Cross-cutting feature marker**: yes.
|
||
- **Systems touched (expected)**:
|
||
- `apps/platform/app/Support/OperationRunLinks.php`
|
||
- `apps/platform/app/Support/Navigation/CanonicalNavigationContext.php`
|
||
- `apps/platform/app/Support/Navigation/AdminSurfaceScope.php`
|
||
- `apps/platform/app/Support/Navigation/WorkspaceHubNavigation.php`
|
||
- `apps/platform/app/Http/Controllers/ClearEnvironmentContextController.php`
|
||
- `apps/platform/app/Support/Navigation/WorkspaceHubRegistry.php`
|
||
- `apps/platform/app/Support/Navigation/WorkspaceSidebarNavigation.php`
|
||
- **New abstraction introduced?**: `WorkspaceHubNavigation`, a narrow helper for environment-surface hub grouping and explicit `environment_id` URL carry.
|
||
- **Shared abstractions reused**: existing `AdminSurfaceScope` + hub registry + navigation context; do not create a second taxonomy framework.
|
||
- **Bounded deviation**: if Filament requires `tableFilters` internally, keep it internal (page-level translation) and keep first-party helper output contract stable.
|
||
|
||
## OperationRun UX Impact
|
||
|
||
Link semantics only (no new OperationRun types, no lifecycle changes):
|
||
|
||
- Stop emitting Filament internals as deep-link contract for operation type filtering.
|
||
- Decide between:
|
||
1) `operation_type=<canonical-code>` accepted by Operations page and mapped to internal table state, or
|
||
2) removing operation-type deep-linking entirely if safe mapping is not feasible without bloat.
|
||
|
||
## Implementation Approach
|
||
|
||
### Phase 1 — Repo truth + failing tests first
|
||
|
||
- Inventory current first-party helper outputs and navigation contexts that emit:
|
||
- `tableFilters[...]` (confirmed in `OperationRunLinks`; re-check `CanonicalNavigationContext` usage and call sites)
|
||
- legacy `/admin/evidence/*` special casing branches (`AdminSurfaceScope`, `ClearEnvironmentContextController`)
|
||
- Add failing tests that lock the desired contract:
|
||
- `OperationRunLinks::index(..., operationType: ...)` must not contain `tableFilters`.
|
||
- Evidence Overview is workspace hub; any `/admin/evidence/*` environment-scope handling is either intentional + tested or removed.
|
||
|
||
### Phase 2 — OperationRunLinks query contract
|
||
|
||
- Change `OperationRunLinks::index`:
|
||
- replace `tableFilters[type][value]` emission with a stable query key (`operation_type`) or remove operation-type deep linking.
|
||
- Update the Operations page boundary to translate `operation_type` into internal table state where needed (keep `environment_id` canonical).
|
||
|
||
### Phase 3 — Navigation context payload hygiene
|
||
|
||
- Re-check `CanonicalNavigationContext::toQuery()` usage:
|
||
- prefer keeping navigation metadata under `nav[...]` only,
|
||
- avoid emitting additional top-level filter payload that encodes `tableFilters` for hub filtering when `environment_id` is sufficient.
|
||
- Adjust the specific call sites (e.g. RelatedNavigationResolver contexts) that currently inject `tableFilters[managed_environment_id]` into query strings when linking to Operations.
|
||
|
||
### Phase 4 — Evidence scope special casing
|
||
|
||
- Verify actual route inventory for `/admin/evidence/*` beyond overview.
|
||
- Remove stale classification or redirect rules only when route inventory proves they are not real, or explicitly document + test the remaining route family if it is still reachable.
|
||
|
||
### Phase 5 — Validation and regression posture
|
||
|
||
- Split Environment sidebar IA:
|
||
- keep environment-owned resources in their domain groups,
|
||
- move workspace hub entries into “Workspace-wide” on environment pages,
|
||
- move workspace configuration/admin entries into “Workspace admin” on environment pages,
|
||
- preserve explicit `environment_id` only for workspace hubs that already accept that filter.
|
||
|
||
Run narrow tests first:
|
||
|
||
- `cd apps/platform && ./vendor/bin/sail artisan test --compact <new/updated Spec 338 tests>`
|
||
- `cd apps/platform && ./vendor/bin/sail pint --dirty --format agent`
|
||
- `git diff --check`
|
||
|
||
Run minimal browser smoke only if link/scope changes are user-visible in navigation:
|
||
|
||
- `cd apps/platform && php vendor/bin/pest tests/Browser --filter=Spec338 --compact`
|
||
|
||
## Deployment / Ops Impact
|
||
|
||
- Migrations: none expected.
|
||
- Env vars: none expected.
|
||
- Queues/scheduler: none expected.
|
||
- Filament assets: no new registered assets expected; `filament:assets` posture unchanged.
|