## Summary - retire legacy `/admin/t` and active `/admin/tenants` product surfaces in favor of canonical workspace-scoped managed-environment routes - centralize runtime URL generation through `ManagedEnvironmentLinks` and update intended URL handling to reject legacy tenant paths - remove dormant tenant panel runtime, rename test helpers to the admin environment context, and add guard coverage for route/helper regressions ## Validation - targeted Feature guard, workspace, provider connection, required permissions, and Filament test lanes run under Sail - browser smoke coverage run for provider connection and workspace RBAC environment access flows - formatting and diff checks completed with Pint and `git diff --check` ## Notes - Filament remains on v5 with Livewire v4 - provider registration stays in `apps/platform/bootstrap/providers.php` - retired tenant resource global search is disabled and destructive action confirmation rules remain unchanged Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #352
315 lines
20 KiB
Markdown
315 lines
20 KiB
Markdown
# Implementation Plan: Managed Environment Canonical Route Cutover & Legacy Tenant Surface Retirement
|
|
|
|
**Branch**: `297-managed-environment-canonical-route-cutover` | **Date**: 2026-05-12 | **Spec**: [spec.md](/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/297-managed-environment-canonical-route-cutover/spec.md)
|
|
**Input**: Feature specification from `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/297-managed-environment-canonical-route-cutover/spec.md`
|
|
|
|
## Summary
|
|
|
|
Spec 297 completes the hard product cutover from legacy tenant surfaces to canonical workspace-managed-environment routes. The implementation retires active `/admin/tenants...` product routes, keeps `/admin/t...` dead, removes or permanently neutralizes `TenantPanelProvider`, replaces runtime link generation with one canonical managed-environment link contract, rejects legacy intended URLs, renames the old tenant-panel test helper with no alias, and adds guard tests that prevent backsliding.
|
|
|
|
This plan is preparation only. It does not implement application code.
|
|
|
|
## Technical Context
|
|
|
|
**Language/Version**: PHP 8.4.15
|
|
**Primary Dependencies**: Laravel 12.52.0, Filament 5.2.1, Livewire 4.1.4, Pest 4.3.1, Laravel Sail 1.52.0
|
|
**Storage**: PostgreSQL through Laravel/Sail for tests; no new storage planned
|
|
**Testing**: Pest via `./vendor/bin/sail artisan test --compact`; Browser tests only if visible navigation is touched
|
|
**Validation Lanes**: targeted Feature guards, Workspaces, ProviderConnections, RequiredPermissions, Filament, Spec 288 guard pack, Spec 293 cutover lane, optional Browser smoke
|
|
**Target Platform**: Laravel Sail local runtime and Gitea-compatible CI runners
|
|
**Project Type**: Laravel web application under `apps/platform`
|
|
**Performance Goals**: Route/link guards stay deterministic and focused; no new heavy or browser defaults
|
|
**Constraints**: no `/admin/t...` restoration, no `/admin/tenants...` compatibility surface, no TenantPanelProvider reactivation, no old helper alias, no DB/model rename, no broad localization or RBAC refactor
|
|
**Scale/Scope**: Route, link, intended URL, Filament resource registration, and test-helper cutover only
|
|
|
|
## Initial Repo Baseline
|
|
|
|
Preparation audit on 2026-05-12 found:
|
|
|
|
- Current branch before Spec Kit execution: `platform-dev`; Spec Kit switched to `297-managed-environment-canonical-route-cutover`.
|
|
- Working tree was clean before creating the spec package.
|
|
- `TenantPanelProvider` still exists at `apps/platform/app/Providers/Filament/TenantPanelProvider.php`.
|
|
- `apps/platform/bootstrap/providers.php` is already guarded by existing tests against registering `TenantPanelProvider`.
|
|
- `route:list --path=admin/tenants` currently shows four active Filament tenant resource routes: index, view, edit, memberships.
|
|
- `route:list --path=admin/workspaces` currently shows canonical environment routes under `/admin/workspaces/{workspace}/environments...` and workspace operations under `/admin/workspaces/{workspace}/operations...`.
|
|
- `rg` currently finds many active tests/runtime references to `TenantResource::getUrl(...)`, `TenantDashboard::getUrl(...)`, `TenantRequiredPermissions::getUrl(...)`, `/admin/t/...`, `/admin/tenants...`, and `setTenantPanelContext()`.
|
|
- The attempted `route:list --columns=...` option is unsupported in this Laravel version; retry without `--columns`.
|
|
|
|
The implementation must refresh `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/297-managed-environment-canonical-route-cutover/legacy-surface-audit.md` before editing runtime code.
|
|
|
|
## UI / Surface Guardrail Plan
|
|
|
|
- **Guardrail scope**: changed route/link/navigation contract for existing surfaces; no new product workflow.
|
|
- **Native vs custom classification summary**: Native Filament/resources/pages and shared link helpers. No custom Blade/Tailwind surface is planned.
|
|
- **Shared-family relevance**: navigation entry points, action links, notifications/toast actions, OperationRun links, provider/permission links, test context helpers.
|
|
- **State layers in scope**: route registration, URL helper, intended URL/session, Filament panel/resource registration, test panel/workspace/environment context.
|
|
- **Audience modes in scope**: operator-MSP and support-platform only through existing surfaces.
|
|
- **Decision/diagnostic/raw hierarchy plan**: existing environment/readiness/operations surfaces keep their hierarchy; the cutover only changes canonical route truth.
|
|
- **Raw/support gating plan**: unchanged; raw provider detail remains where existing policies allow it.
|
|
- **One-primary-action / duplicate-truth control**: do not add parallel actions to preserve legacy paths. Replace old destinations with canonical ones.
|
|
- **Handling modes by drift class or surface**: retire, replace, or document allowed technical reference. Unsafe or ambiguous legacy URL resolution falls back or 404s.
|
|
- **Repository-signal treatment**: review-mandatory for route-list output, source-scan allowlists, intended URL fallback, helper rename, and any remaining `Tenant` product copy in touched files.
|
|
- **Special surface test profiles**: `route-contract`, `standard-native-filament`, `global-context-shell`, `browser-smoke` if visible navigation changes.
|
|
- **Required tests or manual smoke**: targeted Pest guard tests first; Browser only when implementation touches visible navigation flows.
|
|
- **Exception path and spread control**: Allowed remaining technical `Tenant` references must be listed in `legacy-surface-audit.md` or final summary.
|
|
- **Active feature PR close-out entry**: Guardrail / Route Cutover / Smoke Coverage if browser proof was run.
|
|
|
|
## Shared Pattern & System Fit
|
|
|
|
- **Cross-cutting feature marker**: yes.
|
|
- **Systems touched**: Filament panel providers, TenantResource/TenantDashboard/TenantRequiredPermissions routes or links, WorkspaceRedirectResolver/intended URL support, OperationRunLinks, WorkspaceOverviewBuilder, provider/required-permissions link emitters, `tests/Pest.php`, guard tests, browser tests when route navigation is visible.
|
|
- **Shared abstractions reused**: existing workspace/environment routes, `WorkspaceContext`, `OperationRunLinks`, existing admin panel context helper, existing Spec 288/293 guard style.
|
|
- **New abstraction introduced? why?**: Only a bounded `ManagedEnvironmentLinks` helper if no existing repo-real helper owns canonical environment URLs. It exists to remove scattered route-name literals and prevent legacy URL generation.
|
|
- **Why the existing abstraction was sufficient or insufficient**: The canonical routes exist, but runtime link generation remains scattered and some helpers still emit old destinations.
|
|
- **Bounded deviation / spread control**: Technical `Tenant` model names and Microsoft tenant ID copy remain only where non-product or provider-specific.
|
|
|
|
## OperationRun UX Impact
|
|
|
|
- **Touches OperationRun start/completion/link UX?**: yes, route/link safety only.
|
|
- **Central contract reused**: `OperationRunLinks` and `admin.operations.index` / `admin.operations.view` with explicit workspace context.
|
|
- **Delegated UX behaviors**: preserve existing `View operation` / `Open operation` behavior.
|
|
- **Surface-owned behavior kept local**: environment/provider surfaces own only initiation inputs and page-local copy.
|
|
- **Queued DB-notification policy**: N/A.
|
|
- **Terminal notification path**: unchanged.
|
|
- **Exception path**: none.
|
|
|
|
## Provider Boundary & Portability Fit
|
|
|
|
- **Shared provider/platform boundary touched?**: yes.
|
|
- **Provider-owned seams**: Microsoft Entra tenant ID copy, Graph permission names, provider diagnostics payloads.
|
|
- **Platform-core seams**: route family, link generation, workspace/environment context, operations links, RBAC and access-scope semantics.
|
|
- **Neutral platform terms / contracts preserved**: workspace, managed environment, provider connection, target scope, required permissions, diagnostics, access scope, operation.
|
|
- **Retained provider-specific semantics and why**: Microsoft-specific identity/permission terms remain only when they identify external provider truth.
|
|
- **Bounded extraction or follow-up path**: No multi-provider framework. Follow-up only for DB/model rename or broader provider-boundary cleanup beyond route cutover.
|
|
|
|
## Constitution Check
|
|
|
|
*GATE: Must pass before runtime implementation and re-check before close-out.*
|
|
|
|
- Inventory-first: no new inventory or snapshot truth.
|
|
- Read/write separation: no new write workflow. Existing destructive actions touched by route/resource work keep confirmation, authorization, and audit behavior.
|
|
- Single Graph contract path: no new Graph calls.
|
|
- Deterministic capabilities: capability-first RBAC remains authoritative; no role-string checks.
|
|
- Proportionality / no premature abstraction: use existing helper if possible; any new link helper is bounded to current route generation.
|
|
- No new persisted truth: no migrations, tables, compatibility shims, or dual-read paths.
|
|
- Workspace isolation: all environment and operations links carry explicit workspace context or validate current workspace context.
|
|
- Tenant isolation: tenant-owned records exposed through canonical environment routes still enforce managed-environment entitlement.
|
|
- RBAC-UX: non-member/out-of-scope remains 404; established member missing capability remains 403; UI hiding is not security.
|
|
- Provider boundary: tenant-first platform route language is retired; provider-specific tenant terms remain only provider-owned.
|
|
- Test governance: guard tests are allowed and focused; no full-suite repair or new lane framework.
|
|
- Filament-native UI: Filament remains v5 on Livewire v4, no v3/v4 API usage, no ad-hoc UI redesign.
|
|
- Deployment/ops: no asset registration is planned. If assets are unexpectedly registered, deploy notes include `cd apps/platform && php artisan filament:assets`.
|
|
|
|
## Filament v5 Output Contract
|
|
|
|
- **Livewire compliance**: Filament v5 targets Livewire v4.0+; current app has Livewire 4.1.4.
|
|
- **Provider registration location**: Laravel 12 provider registration must remain in `apps/platform/bootstrap/providers.php`. `TenantPanelProvider` must not be registered there.
|
|
- **Globally searchable resources**: If `TenantResource` is retired or moved out of active discovery, global search must be disabled for it or it must no longer register. Any managed-environment resource that remains globally searchable must have Edit or View pages.
|
|
- **Destructive actions**: This spec does not add destructive actions. Any touched existing destructive action must still execute through `->action(...)`, use `->requiresConfirmation()`, and enforce server-side authorization.
|
|
- **Asset strategy**: No new Filament assets are planned. If implementation unexpectedly registers assets, deployment must include `cd apps/platform && php artisan filament:assets`.
|
|
- **Testing plan**: Pages/actions/helpers changed by the cutover are covered with Pest/Filament tests; guard tests cover route resurrection, helper resurrection, intended URL rejection, legacy URL generation, and managed-environment canonical links.
|
|
|
|
## Test Governance Check
|
|
|
|
- **Test purpose / classification by changed surface**: Feature guard tests for route/link/intended URL contracts; Unit tests for pure helper logic; Feature/Filament tests for pages/resources; Browser only for visible navigation smoke.
|
|
- **Affected validation lanes**: Feature/Guards, Feature/Workspaces, Feature/ProviderConnections, Feature/RequiredPermissions, Feature/Filament, Spec 288 guard pack, Spec 293 cutover lane, optional Browser lane.
|
|
- **Why this lane mix is the narrowest sufficient proof**: The risk is route/link resurrection, not complete product behavior. Focused guards plus existing domain test directories prove the changed contracts.
|
|
- **Narrowest proving commands**:
|
|
|
|
```bash
|
|
cd apps/platform
|
|
./vendor/bin/sail artisan test --compact tests/Feature/Guards/NoLegacyTenantPanelRuntimeTest.php
|
|
./vendor/bin/sail artisan test --compact tests/Feature/Guards/NoActiveTenantResourceRoutesTest.php
|
|
./vendor/bin/sail artisan test --compact tests/Feature/Guards/ManagedEnvironmentCanonicalRouteContractTest.php
|
|
./vendor/bin/sail artisan test --compact tests/Feature/Workspaces/WorkspaceIntendedUrlLegacyRejectionTest.php
|
|
```
|
|
|
|
- **Fixture / helper / factory / seed / context cost risks**: The replacement for `setTenantPanelContext()` must not make provider setup, browser fixtures, or broad workspace setup implicit.
|
|
- **Expensive defaults or shared helper growth introduced?**: none planned.
|
|
- **Heavy-family additions, promotions, or visibility changes**: none planned.
|
|
- **Surface-class relief / special coverage rule**: Standard-native Filament coverage unless route/navigation changes are visible in browser flows.
|
|
- **Closing validation and reviewer handoff**: run focused guards, affected domain directories, Spec 288 pack, Spec 293 pack, and Pint dirty.
|
|
- **Budget / baseline / trend follow-up**: document any material guard runtime increase in the implementation close-out.
|
|
- **Review-stop questions**: Does `/admin/tenants...` still return a product page? Does a helper still emit legacy URLs? Does intended URL handling preserve legacy paths? Did a test helper alias keep the old name? Did RBAC weaken?
|
|
- **Escalation path**: document-in-feature for allowed technical references; follow-up-spec for structural rename/localization issues.
|
|
- **Active feature PR close-out entry**: Guardrail / Route Cutover.
|
|
- **Why no dedicated follow-up spec is needed**: The route cutover is bounded. DB/model rename and broader copy/localization are explicit non-goals and can become follow-ups only if product needs them.
|
|
|
|
## Project Structure
|
|
|
|
### Documentation (this feature)
|
|
|
|
```text
|
|
specs/297-managed-environment-canonical-route-cutover/
|
|
├── spec.md
|
|
├── plan.md
|
|
├── research.md
|
|
├── data-model.md
|
|
├── quickstart.md
|
|
├── legacy-surface-audit.md
|
|
├── tasks.md
|
|
├── contracts/
|
|
│ └── managed-environment-canonical-route-contract.md
|
|
└── checklists/
|
|
└── requirements.md
|
|
```
|
|
|
|
### Source Code (repository root)
|
|
|
|
Expected touched surfaces during implementation:
|
|
|
|
```text
|
|
apps/platform/app/
|
|
├── Providers/Filament/
|
|
├── Filament/
|
|
│ ├── Pages/
|
|
│ └── Resources/
|
|
├── Support/
|
|
│ ├── Workspaces/
|
|
│ ├── OperationRunLinks.php
|
|
│ └── ManagedEnvironmentLinks.php (only if needed)
|
|
└── Http/
|
|
|
|
apps/platform/bootstrap/providers.php
|
|
apps/platform/routes/web.php
|
|
apps/platform/tests/
|
|
├── Pest.php
|
|
├── Feature/
|
|
├── Unit/
|
|
└── Browser/
|
|
```
|
|
|
|
**Structure Decision**: Use existing Laravel/Filament app structure and existing route/helper/test conventions. Do not create a new base application folder or dependency.
|
|
|
|
## Complexity Tracking
|
|
|
|
| Violation | Why Needed | Simpler Alternative Rejected Because |
|
|
|---|---|---|
|
|
| Cross-cutting route/link/test-helper cleanup | Legacy route truth exists in multiple owners and cannot be retired safely in one local page | Local cleanup would leave intended URLs, tests, or link builders able to resurrect old paths |
|
|
| Bounded canonical link helper if needed | Runtime link generation must have one owner to make guard tests meaningful | Scattered route-name literals would recreate the drift this spec removes |
|
|
| New guard tests | Regression risk is route/link resurrection after a cutover | Manual review and ad hoc source scans are not durable enough |
|
|
|
|
## Phase 0: Safety Gate
|
|
|
|
1. Run:
|
|
|
|
```bash
|
|
git status --short --branch
|
|
git diff --stat
|
|
git log -1 --oneline
|
|
```
|
|
|
|
2. Confirm the implementation branch is `297-managed-environment-canonical-route-cutover` or a session branch created from it.
|
|
3. Stop if unrelated uncommitted changes exist.
|
|
4. Read:
|
|
|
|
```text
|
|
.specify/memory/constitution.md
|
|
specs/287-cutover-prerequisite-completion/
|
|
specs/288-quality-gates-no-legacy-enforcement/
|
|
specs/293-post-cutover-suite-stabilization/
|
|
specs/296-full-suite-green-signal-restoration/
|
|
```
|
|
|
|
## Phase 1: Baseline Audit
|
|
|
|
Refresh `legacy-surface-audit.md` before code edits:
|
|
|
|
```bash
|
|
git status --short --branch
|
|
git diff --stat
|
|
|
|
cd apps/platform
|
|
./vendor/bin/sail artisan route:list | rg "admin/t|admin/tenants|provider-connections|required-permissions|workspaces/.*/environments|operations"
|
|
rg "TenantPanelProvider|panel:\s*'tenant'|panel:\s*\"tenant\"|/admin/t/|/admin/tenants|TenantResource::getUrl|TenantDashboard::getUrl|TenantRequiredPermissions::getUrl|setTenantPanelContext|admin\.operations" . --glob '!vendor' --glob '!node_modules'
|
|
```
|
|
|
|
Classify each finding as runtime, test, copy, historical, provider-specific, or allowed technical reference.
|
|
|
|
## Phase 2: Remove Dormant TenantPanelProvider
|
|
|
|
- Delete `apps/platform/app/Providers/Filament/TenantPanelProvider.php` if no true runtime dependency exists.
|
|
- Ensure `apps/platform/bootstrap/providers.php` does not reference it.
|
|
- Replace tests that inspect the file with provider-registration and route-list guards.
|
|
- Add/extend `NoLegacyTenantPanelRuntimeTest`.
|
|
|
|
## Phase 3: Establish Canonical Managed Environment Link Contract
|
|
|
|
- Locate repo-real managed-environment route helpers first.
|
|
- Create or extend `ManagedEnvironmentLinks` only if needed.
|
|
- Cover index/detail/required-permissions/diagnostics/access-scopes/operations.
|
|
- Replace direct legacy link generation in runtime surfaces.
|
|
- Add contract tests that assert no generated URL contains `/admin/tenants` or `/admin/t/`.
|
|
|
|
## Phase 4: Retire `/admin/tenants...`
|
|
|
|
- Remove active TenantResource route registration or move it out of active discovery.
|
|
- If a temporary redirect is unavoidable, require unique workspace/environment resolution and document the exception. Default is 404.
|
|
- Update global search for any retired resource.
|
|
- Add/extend `NoActiveTenantResourceRoutesTest`.
|
|
|
|
## Phase 5: Intended URL Legacy Rejection
|
|
|
|
- Update `WorkspaceRedirectResolver`, `WorkspaceIntendedUrl`, or repo-real intended URL owners.
|
|
- Reject `/admin/t...` and `/admin/tenants...` as final destinations.
|
|
- Normalize legacy `/admin/operations` to workspace operations when workspace is known.
|
|
- Fall back to workspace home or environment index when unsafe.
|
|
- Keep external URLs blocked.
|
|
|
|
## Phase 6: Required Permissions And Provider Connections
|
|
|
|
- Replace old required-permissions and provider-connection tenant URLs.
|
|
- Ensure tenantless provider-connection resource remains canonical.
|
|
- Ensure required-permissions uses the workspace/environment route.
|
|
- Add/extend legacy route tests proving old URLs do not return 200.
|
|
|
|
## Phase 7: Test Helper Rename
|
|
|
|
- Rename `setTenantPanelContext()` to the chosen canonical helper, for example `setAdminEnvironmentContext()`.
|
|
- Update every test usage.
|
|
- Do not keep an alias under the old name.
|
|
- Add guard coverage that fails on old helper resurrection.
|
|
|
|
## Phase 8: Copy Cleanup In Touched Active Surfaces
|
|
|
|
- Replace tenant-first product copy only in files touched by this cutover.
|
|
- Keep Microsoft/provider-specific tenant ID copy where correct.
|
|
- List remaining old references in `legacy-surface-audit.md`.
|
|
|
|
## Phase 9: Regression Proof Pack
|
|
|
|
Run focused proof:
|
|
|
|
```bash
|
|
cd apps/platform
|
|
./vendor/bin/sail artisan test --compact \
|
|
tests/Feature/Guards/NoLegacyTenantPanelRuntimeTest.php \
|
|
tests/Feature/Guards/NoActiveTenantResourceRoutesTest.php \
|
|
tests/Feature/Guards/ManagedEnvironmentCanonicalRouteContractTest.php \
|
|
tests/Feature/Workspaces/WorkspaceIntendedUrlLegacyRejectionTest.php \
|
|
tests/Feature/ProviderConnections/LegacyRedirectTest.php \
|
|
tests/Feature/ManagedEnvironment/LegacyTenantCoreGuardTest.php \
|
|
tests/Feature/Spec080WorkspaceManagedTenantAdminMigrationTest.php \
|
|
tests/Feature/Filament/ManagedEnvironmentAccessScopeManagementTest.php \
|
|
tests/Feature/Rbac/ProviderConnectionWorkspaceFirstPolicyTest.php
|
|
```
|
|
|
|
Run the Spec 288 guard pack and Spec 293 cutover lane listed in the spec. Run browser smoke only if visible navigation flows were touched.
|
|
|
|
## Phase 10: Broad Validation
|
|
|
|
Run at least:
|
|
|
|
```bash
|
|
cd apps/platform
|
|
./vendor/bin/sail artisan test --compact tests/Feature/Guards
|
|
./vendor/bin/sail artisan test --compact tests/Feature/Workspaces
|
|
./vendor/bin/sail artisan test --compact tests/Feature/ProviderConnections
|
|
./vendor/bin/sail artisan test --compact tests/Feature/RequiredPermissions
|
|
./vendor/bin/sail artisan test --compact tests/Feature/Filament
|
|
./vendor/bin/sail bin pint --dirty --format agent
|
|
git diff --check
|
|
```
|
|
|
|
Raw full suite is optional unless requested; if run, record the exact result.
|