TenantAtlas/specs/338-workspace-environment-resource-scope-contract/plan.md
ahmido e0c2cdb1f4 feat: enforce workspace and environment scope contract (Spec 338) (#409)
## 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
2026-05-31 01:36:08 +00:00

124 lines
7.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 TenantPilots 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.