TenantAtlas/specs/297-managed-environment-canonical-route-cutover/spec.md
ahmido 3ec582a182 feat: retire legacy tenant route surfaces (#352)
## 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
2026-05-12 23:35:03 +00:00

37 KiB

Feature Specification: Managed Environment Canonical Route Cutover & Legacy Tenant Surface Retirement

Feature Branch: 297-managed-environment-canonical-route-cutover
Created: 2026-05-12
Status: Ready
Input: User-provided Spec 297 prompt: retire active /admin/tenants... and remaining legacy tenant surfaces, remove dormant TenantPanel runtime readiness, and make Workspace -> Managed Environments the only active product route truth.

Spec Candidate Check (mandatory - SPEC-GATE-001)

  • Problem: The workspace-first managed-environment cutover is not complete while active /admin/tenants... product routes, TenantPanelProvider, tenant-panel test helpers, legacy intended URLs, and old TenantResource/TenantDashboard link generation still exist as runtime or test truth.
  • Today's failure: Operators, tests, and contributors can still follow or assert /admin/tenants..., TenantResource::getUrl(...), TenantDashboard::getUrl(...), TenantRequiredPermissions::getUrl(...), setTenantPanelContext(), or dormant tenant-panel provider code even though Specs 279-296 moved the product direction to workspace-first and managed-environment-first routing.
  • User-visible improvement: Admin operators and maintainers get one product truth: Workspace -> Managed Environments -> Environment Detail / Readiness / Permissions / Diagnostics / Operations. Legacy tenant routes stop competing with canonical routes and cannot return through intended URL handling or stale test fixtures.
  • Smallest enterprise-capable version: Remove the dormant tenant panel provider if unused, retire active /admin/tenants... product routes, centralize canonical managed-environment link generation, reject or safely normalize legacy intended URLs, rename the tenant-panel test helper without an alias, and add guard tests proving legacy surfaces stay retired.
  • Explicit non-goals: No database rename from Tenant to ManagedEnvironment, no new product workflow, no compatibility layer for old URLs, no broad localization sweep, no Package Execution, no Guided Operations, no Microsoft provider refactor, no large RBAC refactor, and no new persisted data model.
  • Permanent complexity imported: One small canonical link helper or extension of an existing helper, targeted guard tests, and one spec-local legacy surface audit. No new table, enum, status family, provider framework, or cross-domain UI framework is introduced.
  • Why now: Specs 287, 288, and 293 completed prerequisites and guard/stabilization work but repo truth still shows active legacy route and helper surfaces. Delaying this cutover lets the retired tenant product language keep spreading into future specs and tests.
  • Why not local: The drift is cross-cutting across routes, Filament resource registration, link builders, intended URL resolution, tests, helpers, and operator copy. A local page fix would leave multiple active sources of truth.
  • Approval class: Cleanup
  • Red flags triggered: Cross-cutting route/test-helper cleanup and active route retirement. Defense: the scope is bounded to retiring known legacy surfaces and replacing them with existing canonical workspace/environment routes; it adds guard tests, not a new product framework.
  • Score: Nutzen: 2 | Dringlichkeit: 2 | Scope: 2 | Komplexitaet: 1 | Produktnaehe: 2 | Wiederverwendung: 2 | Gesamt: 11/12
  • Decision: approve

Spec Scope Fields (mandatory)

  • Scope: canonical-view
  • Primary Routes:
    • Retired: /admin/t, /admin/t/...
    • Retired active product surface: /admin/tenants, /admin/tenants/{environment}, /admin/tenants/{environment}/edit, /admin/tenants/{environment}/memberships, /admin/tenants/{environment}/required-permissions, /admin/tenants/{environment}/provider-connections...
    • Canonical: /admin/workspaces/{workspace}/environments
    • Canonical: /admin/workspaces/{workspace}/environments/{environment}
    • Canonical: /admin/workspaces/{workspace}/environments/{environment}/required-permissions
    • Canonical: /admin/workspaces/{workspace}/environments/{environment}/diagnostics if repo-real or equivalent diagnostics/readiness route exists
    • Canonical: /admin/workspaces/{workspace}/environments/{environment}/access-scopes if repo-real or equivalent membership/access-scope route exists
    • Canonical operations: /admin/workspaces/{workspace}/operations and /admin/workspaces/{workspace}/operations/{run}
  • Data Ownership:
    • No new persisted entity, table, enum, state, or status family.
    • Existing ManagedEnvironment / internal Tenant model reality may remain technical implementation truth where repo-real.
    • Workspace membership remains the role/capability authority.
    • Managed environment membership remains narrowing/access-scope only and must not regain role authority.
  • RBAC:
    • Workspace membership is required before revealing workspace or environment surfaces.
    • Managed-environment access scope may narrow access but cannot grant role authority.
    • Non-member or out-of-scope actors receive 404 (deny-as-not-found).
    • Established members missing capability receive 403.
    • UI visibility is never authorization; policies/gates remain the server-side truth.

For canonical-view specs:

  • Default filter behavior when tenant-context is active: Any legacy or stale environment hint must be resolved into explicit workspace + managed-environment context before links or pages are shown. If safe resolution is not possible, fall back to workspace home or environment index.
  • Explicit entitlement checks preventing cross-tenant leakage: Any canonical environment route, operation link, relation/action link, or intended URL normalization must verify workspace entitlement and managed-environment entitlement before revealing tenant-owned records.

Cross-Cutting / Shared Pattern Reuse (mandatory)

  • Cross-cutting feature?: yes
  • Interaction class(es): route/link generation, navigation entry points, intended URL handling, Filament resource URLs, action links, test helper context, guard tests, provider/required-permissions launch points, workspace operations links
  • Systems touched:
    • apps/platform/app/Providers/Filament/TenantPanelProvider.php
    • apps/platform/bootstrap/providers.php
    • apps/platform/app/Filament/Resources/TenantResource.php
    • apps/platform/app/Filament/Pages/TenantDashboard.php
    • apps/platform/app/Filament/Pages/TenantRequiredPermissions.php
    • apps/platform/app/Support/Workspaces/WorkspaceRedirectResolver.php
    • apps/platform/app/Support/Workspaces/WorkspaceOverviewBuilder.php
    • apps/platform/app/Support/OperationRunLinks.php
    • existing workspace/environment route helpers or new bounded ManagedEnvironmentLinks
    • apps/platform/tests/Pest.php
    • targeted Feature, Browser, Unit, and Guard tests that still assert old route truth
  • Existing pattern(s) to extend: current workspace-first admin routes, OperationRunLinks, WorkspaceContext, existing admin panel context helpers, existing Spec 288/293 guard style, and any repo-real managed-environment route helper.
  • Shared contract / presenter / builder / renderer to reuse: reuse existing route helpers where they already generate canonical workspace/environment URLs. Introduce ManagedEnvironmentLinks only if no repo-real helper owns index/detail/permissions/diagnostics/access-scope URLs.
  • Why the existing shared path is sufficient or insufficient: The canonical route family already exists for workspace/environment pages and operations. What is insufficient is that old link builders, tests, and intended URL handling still accept or emit retired route families.
  • Allowed deviation and why: Technical class/model names containing Tenant may remain where a database/model rename is out of scope. Provider-specific Microsoft tenant ID copy may remain when it refers to Microsoft Entra tenant identity, not TenantPilot route/product identity.
  • Consistency impact: Runtime links, Filament resource pages, notifications/toast actions, test helpers, browser tests, and intended URL handling must all converge on the same workspace-first managed-environment routes.
  • Review focus: Reviewers must verify that no compatibility surface is preserved for /admin/tenants..., no /admin/t... route returns as active product truth, TenantPanelProvider cannot be re-enabled by registration, and no old helper alias remains.

OperationRun UX Impact (mandatory)

  • Touches OperationRun start/completion/link UX?: yes, only for canonical operations links and route generation.
  • Shared OperationRun UX contract/layer reused: OperationRunLinks and canonical admin.operations.index / admin.operations.view routes with explicit workspace context.
  • Delegated start/completion UX behaviors: Existing Open operation / View operation behavior remains owned by the shared OperationRun UX path.
  • Local surface-owned behavior that remains: Environment and provider surfaces may still own local launch inputs and local copy, but not workspace-safe operation URL construction.
  • Queued DB-notification policy: N/A - unchanged.
  • Terminal notification path: existing central lifecycle mechanism, unchanged.
  • Exception required?: none.

Provider Boundary / Platform Core Check (mandatory)

  • Shared provider/platform boundary touched?: yes
  • Boundary classification: mixed
  • Seams affected: provider-connection route ownership, required-permissions route ownership, managed-environment route naming, operations URL generation, provider diagnostics/readiness links, and provider-owned Microsoft tenant ID copy.
  • Neutral platform terms preserved or introduced: workspace, managed environment, environment, provider connection, required permissions, diagnostics, access scope, operation.
  • Provider-specific semantics retained and why: Microsoft Entra tenant ID and Graph permission terminology may remain where the provider itself is the subject.
  • Why this does not deepen provider coupling accidentally: The spec removes tenant-first route/product truth from platform core while allowing provider-owned Microsoft terminology only where it describes external identity or permission data.
  • Follow-up path: document-in-feature for contained technical Tenant names that remain because DB/model rename is out of scope; follow-up-spec only if implementation discovers a structural provider/platform boundary gap outside route cutover.

UI / Surface Guardrail Impact (mandatory)

Surface / Change Operator-facing surface change? Native vs Custom Shared-Family Relevance State Layers Touched Exception Needed? Low-Impact / N/A Note
Retire /admin/tenants... as active product surface yes Native Filament routes/resources, no custom UI planned navigation, resource links, breadcrumbs, action links route, page, URL, test context no remove or neutralize old surface; do not redesign it
Canonical managed-environment links yes Native Filament routes and shared route helper navigation, action links, notifications, operations links URL/helper only no centralize link generation without new UI framework
Intended URL rejection/normalization no direct new UI N/A redirect workflow, workspace chooser session/intended URL no behavior-only route safety
Test helper rename no N/A test support only test panel/workspace/environment context no helper name must reflect no TenantPanel exists

Decision-First Surface Role (mandatory when operator-facing surfaces are changed)

Surface Decision Role Human-in-the-loop Moment Immediately Visible for First Decision On-Demand Detail / Evidence Why This Is Primary or Why Not Workflow Alignment Attention-load Reduction
Managed environment index/detail Primary Decision Surface Operator chooses or inspects the managed environment inside a workspace workspace, environment identity, readiness/health links, primary next action domain-specific diagnostics and raw provider detail remain on existing surfaces Primary because it is the canonical starting point for environment work Workspace -> Managed Environments -> Environment Detail removes need to choose between /admin/tenants and workspace routes
Required permissions / diagnostics / access scopes Secondary Context Surface Operator checks readiness, provider health, or access narrowing before acting current workspace/environment context and status/action affordance provider-owned diagnostics and evidence remain secondary Secondary because it supports environment readiness and operation decisions stays under canonical environment route family reduces route and copy ambiguity
Workspace operations Secondary Context Surface Operator follows a run from environment context to operation detail workspace-scoped run list/detail run diagnostics and logs remain in operation detail Secondary because execution truth belongs to Operations uses existing OperationRun route contract avoids tenant-scoped operation back links

Audience-Aware Disclosure (mandatory when operator-facing surfaces are changed)

Surface Audience Modes In Scope Decision-First Default-Visible Content Operator Diagnostics Support / Raw Evidence One Dominant Next Action Hidden / Gated By Default Duplicate-Truth Prevention
Managed environment index/detail operator-MSP, support-platform workspace/environment scope, environment name, readiness/action links provider readiness and access-scope context raw provider identifiers only where already allowed Open environment or current primary environment action raw provider payloads and support diagnostics one canonical environment detail URL
Required permissions / diagnostics / access scopes operator-MSP, support-platform current environment, required permission state, access-scope state provider health, missing permissions, narrowing details Microsoft tenant ID / Graph identifiers only as provider detail page-owned primary readiness or access action raw/provider-owned data no legacy tenant-detail fallback
Workspace operations operator-MSP, support-platform run status and workspace context run detail and failure reason raw logs only where existing gates allow View operation support/raw detail operations links always workspace-scoped

UI/UX Surface Classification (mandatory when operator-facing surfaces are changed)

Surface Action Surface Class Surface Type Likely Next Operator Action Primary Inspect/Open Model Row Click Secondary Actions Placement Destructive Actions Placement Canonical Collection Route Canonical Detail Route Scope Signals Canonical Noun Critical Truth Visible by Default Exception Type / Justification
Managed environments List / Detail Workspace-scoped environment registry Open environment full-row or identifier open to canonical detail required when table exists More/detail header More/detail header with confirmation /admin/workspaces/{workspace}/environments /admin/workspaces/{workspace}/environments/{environment} workspace + environment Managed environment current workspace/environment and readiness links none
Required permissions Detail / Readiness Environment-scoped readiness page Review missing permissions direct page route n/a existing page actions unchanged; destructive-like actions require confirmation inherited environment route /admin/workspaces/{workspace}/environments/{environment}/required-permissions workspace + environment Required permissions permission readiness and safe next action none
Provider connections List / Detail / Integrations Tenantless admin resource with neutral scope context Open provider connection existing provider resource detail required where table exists More/detail header More/detail header with confirmation /admin/provider-connections /admin/provider-connections/{record} workspace/environment context through record/query/domain Provider connection provider connection and target scope no tenant-scoped route family

Operator Surface Contract (mandatory when operator-facing surfaces are changed)

Surface Primary Persona Decision / Operator Action Supported Surface Type Primary Operator Question Default-visible Information Diagnostics-only Information Status Dimensions Used Mutation Scope Primary Actions Dangerous Actions
Managed environments Workspace operator Pick the correct environment and continue safely list/detail Which managed environment am I working in? workspace/environment scope, environment identity, current route truth provider identifiers and low-level diagnostics readiness, lifecycle, access scope TenantPilot only unless page-specific action says otherwise Open environment existing environment mutations only
Required permissions Workspace operator Decide whether provider permissions are ready readiness detail What permission gap blocks this environment? missing permission state, provider context, primary remediation path raw provider scopes and Graph detail readiness and verification Microsoft tenant only when explicitly remediating provider permission Review required permissions none added
Provider connections Workspace operator Inspect or manage provider connection integration resource Which provider connection applies to this scope? provider connection, neutral target scope provider-owned profile detail lifecycle, authorization, target scope TenantPilot record / Microsoft provider depending on existing action Open provider connection existing destructive actions only
Operations Workspace operator Follow execution truth operations list/detail What happened or is running in this workspace? run status, workspace scope, environment filter when present low-level run diagnostics lifecycle, outcome, progress execution record only View operation none added

Proportionality Review (mandatory when structural complexity is introduced)

  • New source of truth?: no
  • New persisted entity/table/artifact?: no application persistence; one spec-local legacy-surface-audit.md artifact is used as implementation evidence.
  • New abstraction?: yes, only if no existing canonical link helper exists. The allowed abstraction is a bounded ManagedEnvironmentLinks helper for route generation.
  • New enum/state/reason family?: no
  • New cross-domain UI framework/taxonomy?: no
  • Current operator problem: legacy tenant routes and helpers still act as product truth and can resurrect retired surfaces.
  • Existing structure is insufficient because: direct calls to TenantResource/TenantDashboard/TenantRequiredPermissions and old intended URL handling are scattered; route truth is not centralized enough for guard tests to enforce cleanly.
  • Narrowest correct implementation: extend an existing helper if present; otherwise add one small link helper that only maps current workspace/environment objects to existing named routes.
  • Ownership cost: low; one helper plus guard tests must be maintained when route names change.
  • Alternative intentionally rejected: preserving redirects or aliases for /admin/tenants... or /admin/t...; that would keep the legacy surface active.
  • Release truth: current-release cutover cleanup in a pre-production environment.

Compatibility posture

This feature assumes the repo's pre-production lean doctrine.

Backward compatibility, legacy aliases, route shims, old helper aliases, dual routing, and compatibility-specific tests are out of scope unless a safe canonical URL can be uniquely resolved and the spec/plan is updated with an explicit exception. The default behavior for unsafe legacy paths is 404 or canonical workspace fallback, not silent redirect compatibility.

Testing / Lane / Runtime Impact (mandatory for runtime behavior changes)

  • Test purpose / classification: Feature guard tests for route/link/intended URL contracts; Feature/Filament tests for resource/page link changes; Unit tests for helper/link resolver behavior; Browser only if visible navigation flows are touched.
  • Validation lane(s): targeted Feature guards, Workspaces, ProviderConnections, RequiredPermissions, Filament, Spec 288 guard pack, Spec 293 cutover lane, and optional Browser smoke if navigation is visibly changed.
  • Why this classification and these lanes are sufficient: The change is route/link/test-helper cutover, not a new business workflow. Guard tests prove retired paths stay dead; focused resource/page tests prove canonical replacements work.
  • New or expanded test families: new/expanded guard tests under tests/Feature/Guards and tests/Feature/Workspaces; no new permanent test lane.
  • Fixture / helper cost impact: setTenantPanelContext() is replaced by an explicit admin/workspace/environment helper. The new helper must not make expensive provider, browser, or full workspace defaults implicit.
  • Heavy-family visibility / justification: none by default. Heavy/browser tests only run when existing visible flows are touched.
  • Special surface test profile: standard-native-filament, global-context-shell, route-contract, and browser-smoke only when UI navigation is touched.
  • Standard-native relief or required special coverage: ordinary Pest/Filament coverage is sufficient unless a browser-facing route/navigation flow changes.
  • Reviewer handoff: Reviewers must confirm Filament v5 on Livewire v4, provider registration remains in apps/platform/bootstrap/providers.php, globally searchable resources have Edit/View pages or global search disabled, destructive actions still use ->action(...), ->requiresConfirmation(), and authorization, asset strategy is unchanged unless documented, and tests cover mutated pages/actions via Livewire/Filament where applicable.
  • Budget / baseline / trend impact: targeted guards grow; no full-suite budget change is planned. Any material lane runtime drift must be documented in the active PR/spec close-out.
  • Escalation needed: document-in-feature for contained old technical names; follow-up-spec for structural DB/model rename or broader localization.
  • Active feature PR close-out entry: Guardrail / Route Cutover / Smoke Coverage as applicable.
  • Planned validation commands:
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

Required Regression Proof Pack

The implementation close-out must record exact results for the focused Spec 297 proof:

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

The existing Spec 288 guard pack must also remain green:

cd apps/platform
./vendor/bin/sail artisan test --compact \
  tests/Feature/Guards/Spec288NoLegacyRouteAndHelperGuardTest.php \
  tests/Feature/Guards/Spec288ProviderCoreAndRoleAuthorityGuardTest.php \
  tests/Feature/Guards/AdminWorkspaceRoutesGuardTest.php \
  tests/Feature/Guards/ProviderBoundaryPlatformCoreGuardTest.php \
  tests/Feature/Guards/BrowserLaneIsolationTest.php \
  tests/Feature/Guards/CiLaneFailureClassificationContractTest.php \
  tests/Feature/Guards/CiHeavyBrowserWorkflowContractTest.php

If visible navigation flows are touched, run browser smoke:

cd apps/platform
./vendor/bin/sail artisan test --compact \
  tests/Browser/Spec281ProviderConnectionScopeSmokeTest.php \
  tests/Browser/Spec285WorkspaceRbacEnvironmentAccessSmokeTest.php

User Scenarios & Testing (mandatory)

User Story 1 - Legacy Tenant Routes Stay Dead (Priority: P1)

As a workspace operator, I must not be routed into retired tenant-panel or tenant-resource product surfaces.

Why this priority: Retired routes are the direct source of product-truth drift.

Independent Test: Request /admin/t/example, /admin/t/example/operations, /admin/t/example/provider-connections, /admin/tenants, /admin/tenants/{environment}, and legacy provider/required-permissions paths and verify they are not active product pages.

Acceptance Scenarios:

  1. Given an authenticated workspace member, When they request /admin/t/example, Then the response is 404.
  2. Given an authenticated workspace member, When they request /admin/tenants/{environment}/provider-connections, Then the response is 404 unless a documented safe canonical resolution exists.
  3. Given route:list output, When it is scanned, Then no active /admin/t... route exists and /admin/tenants... is not an active product surface.

User Story 2 - Canonical Managed Environment Links Are The Only Runtime Links (Priority: P1)

As an operator following links from dashboards, notifications, provider connections, evidence, reviews, or operations, I need every environment link to resolve through workspace-first managed-environment routes.

Why this priority: Old link generation silently revives legacy surfaces even after routes are hidden.

Independent Test: Render or call runtime link builders for environment detail, required permissions, diagnostics, access scopes, provider connections, and operations and verify generated URLs contain /admin/workspaces/{workspace}/environments... or tenantless provider/operations canonical routes, never /admin/tenants... or /admin/t....

Acceptance Scenarios:

  1. Given a workspace and managed environment, When ManagedEnvironmentLinks::viewUrl($environment) or the repo-real equivalent is called, Then the URL points to canonical environment detail.
  2. Given an environment with required permissions, When the page action/back link is rendered, Then the link points to canonical environment required-permissions route.
  3. Given an operation for an environment, When a related link is generated, Then the operation URL is workspace-scoped.

User Story 3 - Intended URLs Cannot Resurrect Legacy Surfaces (Priority: P1)

As a user returning after workspace selection or login, I must never land on retired tenant routes through stored intended URLs.

Why this priority: Intended URL persistence can bypass navigation cleanup and silently re-enable old route truth.

Independent Test: Store legacy intended URLs and verify the resolver rejects them, normalizes /admin/operations to workspace operations when possible, and falls back to workspace home or environment index when safe resolution is impossible.

Acceptance Scenarios:

  1. Given /admin/t/example/provider-connections as an intended URL, When the workspace redirect resolver runs, Then it does not return or persist that URL.
  2. Given /admin/operations as an intended URL and a known workspace, When the resolver runs, Then it returns /admin/workspaces/{workspace}/operations.
  3. Given /admin/tenants/example/required-permissions without safe workspace/environment resolution, When the resolver runs, Then it falls back to workspace home or environment index.

User Story 4 - Test Harness Uses Admin Workspace/Environment Context (Priority: P2)

As a maintainer, I need tests to express the current admin panel and managed-environment context rather than reviving TenantPanel vocabulary.

Why this priority: Old helper names keep the retired panel as a mental and test-runtime model.

Independent Test: rg "setTenantPanelContext|panel:\\s*'tenant'|panel:\\s*\"tenant\"" apps/platform/tests returns no active helper or non-guard use; all migrated tests use a new admin/workspace/environment context helper.

Acceptance Scenarios:

  1. Given tests/Pest.php, When it is scanned, Then setTenantPanelContext is absent.
  2. Given a test that needs environment context, When it sets context, Then it uses setAdminEnvironmentContext() or the chosen canonical helper.
  3. Given guard tests, When an old helper name is reintroduced, Then the guard fails.

User Story 5 - Narrowing-Only Environment Access Remains Intact (Priority: P2)

As a security reviewer, I need managed-environment memberships to remain access-scope/narrowing-only and never regain role authority.

Why this priority: Route cutover must not backslide into tenant-scope role authority while replacing test fixtures.

Independent Test: RBAC tests prove workspace membership is the only role-bearing truth and managed-environment scope cannot grant role/capability authority.

Acceptance Scenarios:

  1. Given a user with managed-environment scope but no workspace capability, When they access a protected action, Then capability denial remains 403 after membership is established or 404 when not entitled.
  2. Given a managed-environment membership row with legacy/placeholder role data, When authorization runs, Then the role value is ignored as authority.

Functional Requirements

  • FR-297-001: apps/platform/app/Providers/Filament/TenantPanelProvider.php MUST be deleted if it is not runtime-registered and not required by runtime code. If deletion proves impossible, legacy-surface-audit.md MUST document the true dependency and the implementation MUST still prove it cannot be registered or route /admin/t....
  • FR-297-002: apps/platform/bootstrap/providers.php MUST NOT register TenantPanelProvider.
  • FR-297-003: /admin/t, /admin/t/..., and nested legacy tenant-panel paths MUST return 404 or be absent from route:list. Default behavior is 404, not redirect.
  • FR-297-004: /admin/tenants... MUST no longer be active product truth. TenantResource list/view/edit/memberships routes MUST be removed, moved out of auto-discovery, or otherwise made non-product routes with explicit guard proof.
  • FR-297-005: Canonical managed-environment URLs MUST exist for environment index, detail, required permissions/readiness, diagnostics/provider health, access scopes/membership narrowing, and workspace operations, reusing repo-real routes where present.
  • FR-297-006: Runtime code MUST NOT generate active product links through TenantResource::getUrl(...), TenantDashboard::getUrl(...), or TenantRequiredPermissions::getUrl(...) unless the target class has been changed to emit canonical workspace/environment routes and guard tests prove no /admin/tenants... or /admin/t... URL.
  • FR-297-007: The implementation MUST introduce or extend one canonical link owner for managed-environment URLs, such as ManagedEnvironmentLinks, instead of scattering route-name literals across runtime surfaces.
  • FR-297-008: WorkspaceRedirectResolver, WorkspaceIntendedUrl, or their repo-real equivalents MUST reject /admin/t..., /admin/tenants..., /admin/tenants/*/required-permissions, /admin/tenants/*/provider-connections, and external URLs as final intended destinations.
  • FR-297-009: Legacy /admin/operations intended URLs MUST normalize to workspace-scoped operations when a workspace is known, or fall back safely when not.
  • FR-297-010: Legacy required-permissions URLs under /admin/tenants/{environment}/required-permissions MUST not return 200 as active product pages.
  • FR-297-011: Legacy provider-connection URLs under /admin/tenants/{environment}/provider-connections... MUST not return 200 as active product pages.
  • FR-297-012: setTenantPanelContext() MUST be removed or renamed with no alias under the old name. The replacement helper MUST express admin + workspace + managed-environment context.
  • FR-297-013: Runtime and test copy touched by this cutover MUST use managed-environment/environment product language instead of tenant-first labels, except for Microsoft/provider-specific tenant ID terminology, technical model names, migrations, historical specs, or audit history.
  • FR-297-014: Guard tests MUST fail if TenantPanelProvider is registered, /admin/t... becomes routable, /admin/tenants... is revived as product truth, old helper names return, or runtime URL generation emits legacy tenant paths.
  • FR-297-015: Workspace-first RBAC MUST remain intact: workspace membership carries role/capability authority, managed-environment membership narrows access only, and non-member scope remains deny-as-not-found.

Non-Functional Requirements

  • NFR-297-001: No new persisted storage, migration, compatibility shim, or dual-read/dual-write path.
  • NFR-297-002: Route/link guards must be deterministic and actionable, with failure messages that name the forbidden path/helper and owning file.
  • NFR-297-003: New helpers must be small, explicit, and easy to delete or rename if the route contract changes.
  • NFR-297-004: Test updates must not broaden heavy/browser lanes unless the touched surface requires it.
  • NFR-297-005: Any remaining technical Tenant references must be documented as allowed or listed as follow-up.

Acceptance Criteria

  • AC-297-001: No runtime provider file or provider registration can re-enable the tenant panel.
  • AC-297-002: /admin/t... is not routable as product truth and is guarded.
  • AC-297-003: /admin/tenants... is retired as active product truth; no navigation, intended URL, runtime link, or test helper depends on it.
  • AC-297-004: One canonical managed-environment link contract covers index, detail, readiness/permissions, diagnostics, access scopes, and workspace operations where repo-real routes exist.
  • AC-297-005: Intended URL handling cannot return retired tenant routes.
  • AC-297-006: Runtime links no longer generate old TenantResource/TenantPanel URLs.
  • AC-297-007: setTenantPanelContext() is gone with no alias.
  • AC-297-008: Provider and required-permissions tenant-scoped legacy routes do not return 200.
  • AC-297-009: Managed-environment access scopes remain narrowing-only.
  • AC-297-010: Spec 288 and Spec 293 guard/stabilization proof remains green after the cutover.
  • AC-297-011: Pint dirty passes.

Success Criteria

  • SC-297-001: Route-list and guard tests prove no active /admin/t... route and no active product /admin/tenants... route family.
  • SC-297-002: Source scans in runtime code find no unallowed /admin/tenants, /admin/t/, TenantResource::getUrl, TenantDashboard::getUrl, TenantRequiredPermissions::getUrl, or setTenantPanelContext references.
  • SC-297-003: Focused route/link/intended URL tests pass without compatibility redirects.
  • SC-297-004: Final implementation summary can state: Managed Environment canonical cutover complete; legacy tenant surfaces retired.

Risks

  • R-297-001: Some old tests may still assert historical /admin/tenants... behavior from Spec 080/143/147. Mitigation: classify as historical tests only if moved/retired or update them to current product truth.
  • R-297-002: TenantResource may still be globally searchable. Mitigation: retire it from discovery or disable global search unless canonical Edit/View routes exist.
  • R-297-003: Link helper creation could become over-generalized. Mitigation: helper may only map existing workspace/environment routes and must not become a routing framework.
  • R-297-004: Intended URL normalization can create unsafe cross-workspace redirects. Mitigation: require workspace/environment entitlement checks and fallback when resolution is ambiguous.

Assumptions

  • The product is still pre-production under LEAN-001, so compatibility routes and legacy aliases are not required.
  • Internal Tenant class/table names may remain technical implementation detail until a separate DB/model rename spec exists.
  • Existing canonical workspace/environment routes are the preferred target and must be reused rather than duplicated.
  • Filament remains v5 on Livewire v4. Provider registration remains in apps/platform/bootstrap/providers.php.
  • No new asset registration is planned. If implementation unexpectedly registers Filament assets, deploy notes must include cd apps/platform && php artisan filament:assets.

Final Output Required For Implementation

At implementation close-out, report:

  1. Commands run and result.
  2. Deleted legacy code and why deletion was safe.
  3. Retired route families, new behavior, and guard.
  4. Canonical replacements for old usage.
  5. Remaining legacy references, why allowed, and follow-up if any.
  6. Test/lane results.
  7. Final decision, exactly one of:
    • Managed Environment canonical cutover complete; legacy tenant surfaces retired.
    • Blocked by true runtime dependency on legacy tenant surface.
    • Incomplete; active legacy tenant routes remain.