# Implementation Plan: Filament Workspace Tenancy & Environment Routing Cutover **Branch**: `280-workspace-tenancy-environment-routing` | **Date**: 2026-05-07 | **Spec**: [spec.md](./spec.md) **Input**: Feature specification from `specs/280-workspace-tenancy-environment-routing/spec.md` ## Summary Prepare the second reserved workspace-first cutover slice that removes the temporary `/admin/t` operator shell, makes `Workspace` the only Filament tenant, and moves environment work under the canonical workspace-first route family rooted at `/admin/workspaces/{workspace}/environments/{environment}`. The narrow implementation path reuses the existing `AdminPanelProvider`, `WorkspaceOverview`, `ManagedTenantsLanding` and `ChooseTenant` chooser flow, `TenantDashboard`, `Monitoring\Operations`, `WorkspaceOverviewBuilder`, `TenantDashboardSummaryBuilder`, `OperationRunLinks`, and related navigation/context helpers while explicitly deferring Specs `281` through `287`. This plan stays intentionally bounded. Filament remains v5 on Livewire v4, provider registration remains in `apps/platform/bootstrap/providers.php`, no new persistence or provider extraction is introduced, no compatibility route or second panel survives, no artifact retargeting or RBAC redesign is absorbed, and no broad quality-gate or copy-neutralization work moves into this slice. ## Inherited Baseline / Explicit Delta ### Inherited baseline - Spec `279` already replaced the core managed-target noun with `ManagedEnvironment` and kept the `/admin/t/{environment}` shell as a temporary bridge. - `apps/platform/app/Providers/Filament/AdminPanelProvider.php` currently owns the default `admin` panel, `/admin`, `ChooseWorkspace`, `ChooseTenant`, `WorkspaceOverview`, `TenantRequiredPermissions`, and the canonical workspace-scoped operations surface. - `apps/platform/app/Providers/Filament/TenantPanelProvider.php` still owns `id('tenant')`, `path('admin/t')`, and `tenant(ManagedEnvironment::class, slugAttribute: 'slug')`, so the operator runtime still has a second panel and second route language. - `apps/platform/bootstrap/providers.php` still registers both `AdminPanelProvider` and `TenantPanelProvider`. - `apps/platform/app/Support/Workspaces/WorkspaceRedirectResolver.php` still branches to `ChooseTenant` or `TenantDashboard::getUrl(panel: 'tenant', tenant: $tenant)`. - `apps/platform/app/Filament/Pages/ChooseTenant.php`, `apps/platform/app/Filament/Pages/Workspaces/ManagedTenantsLanding.php`, `apps/platform/app/Http/Middleware/EnsureWorkspaceSelected.php`, `apps/platform/app/Support/Middleware/EnsureFilamentTenantSelected.php`, `apps/platform/app/Support/Tenants/TenantPageCategory.php`, and `apps/platform/app/Filament/Concerns/ResolvesPanelTenantContext.php` still encode `/admin/t`, `/admin/tenants/{environment}`, or explicit tenant-panel assumptions. - `apps/platform/app/Support/OperationRunLinks.php`, `apps/platform/app/Support/Navigation/RelatedNavigationResolver.php`, and `apps/platform/app/Filament/Pages/Monitoring/Operations.php` still emit or expect tenant-panel destinations and workspace-canonical operations routes under `/admin/operations`. - Route ownership in `apps/platform/routes/web.php` still exposes `/admin`, `/admin/operations`, `/admin/operations/{run}`, `/admin/w/{workspace}/managed-tenants`, `/admin/tenants/{tenant}/required-permissions`, and the Filament-generated `/admin/t/{tenant}/...` family at the same time. ### Explicit delta in this plan - Collapse the operator-facing `tenant` panel into the existing `admin` panel and make `Workspace` the only Filament tenant. - Replace the public `/admin/t/{environment}` and `/admin/tenants/{environment}/required-permissions` route families with one canonical workspace-first environment family. - Remove the legacy chooser route `/admin/w/{workspace}/managed-tenants` and the legacy operations routes `/admin/operations` plus `/admin/operations/{run}` with no redirects, aliases, or hidden fallback readers. - Re-home the existing workspace dashboard, environment chooser, environment dashboard, and operations hub under `/admin/workspaces/{workspace}/...` without creating replacement dashboards or new panel abstractions. - Update middleware, route categorization, current-context resolution, breadcrumbs, context-bar signals, and page/deep-link builders as one route-contract change rather than page-by-page exceptions. - Keep all provider extraction, governance-artifact retargeting, provider-neutral capability work, RBAC redesign, copy-neutralization, and broad no-legacy/quality-gate follow-through deferred to Specs `281` through `287`. ## Technical Context **Language/Version**: PHP 8.4.15, Laravel 12.52 **Primary Dependencies**: Filament 5.2.1, Livewire 4.1.4, Pest 4.3.1, existing workspace and environment authorization/context helpers, existing Filament panel providers and page/resource action-surface contracts **Storage**: PostgreSQL, no new persistence or schema change in this slice **Testing**: Pest feature tests, one Pest browser smoke, and focused grep/guard checks for legacy route language **Validation Lanes**: fast-feedback, confidence, browser **Target Platform**: Laravel monolith in `apps/platform` **Project Type**: web application **Performance Goals**: preserve current dashboard and operations responsiveness while changing only route ownership, panel tenancy, and context resolution; no new queue, polling, or asset load path **Constraints**: no compatibility redirects or aliases, no second Filament tenant at the environment level, no new persistence, no provider extraction, no artifact retargeting, no RBAC redesign, no broad copy neutralization, no quality-gate pack work, provider registration stays in `apps/platform/bootstrap/providers.php`, and Filament remains v5 on Livewire v4 **Scale/Scope**: one operator-panel tenancy flip, one canonical workspace-first environment route family, one workspace-first operations route family, and one bounded set of chooser/middleware/link/breadcrumb/current-context updates ## Likely Affected Repo Surfaces - `apps/platform/app/Providers/Filament/AdminPanelProvider.php` - `apps/platform/app/Providers/Filament/TenantPanelProvider.php` - `apps/platform/bootstrap/providers.php` - `apps/platform/app/Filament/Pages/ChooseWorkspace.php` - `apps/platform/app/Filament/Pages/ChooseTenant.php` - `apps/platform/app/Filament/Pages/Workspaces/ManagedTenantsLanding.php` - `apps/platform/app/Filament/Pages/WorkspaceOverview.php` - `apps/platform/app/Filament/Pages/TenantDashboard.php` - `apps/platform/app/Filament/Pages/TenantRequiredPermissions.php` - `apps/platform/app/Filament/Pages/Monitoring/Operations.php` - `apps/platform/app/Filament/Concerns/ResolvesPanelTenantContext.php` - `apps/platform/app/Http/Middleware/EnsureWorkspaceSelected.php` - `apps/platform/app/Support/Middleware/EnsureFilamentTenantSelected.php` - `apps/platform/app/Support/Tenants/TenantPageCategory.php` - `apps/platform/app/Support/Workspaces/WorkspaceRedirectResolver.php` - `apps/platform/app/Support/OperationRunLinks.php` - `apps/platform/app/Support/Navigation/RelatedNavigationResolver.php` - `apps/platform/app/Filament/Resources/TenantResource.php` - `apps/platform/app/Filament/Resources/Workspaces/WorkspaceResource.php` - `apps/platform/routes/web.php` - feature, browser, and guard coverage under `apps/platform/tests/Feature`, `apps/platform/tests/Browser`, and existing grep/guard patterns ## Filament v5 / Panel Notes - **Livewire v4.0+ compliance**: this slice keeps Filament v5 on Livewire v4 and changes only panel tenancy, route ownership, and current-context handling. - **Provider registration location**: any provider registration change stays in `apps/platform/bootstrap/providers.php`; nothing moves to `bootstrap/app.php`. - **Global search rule**: touched searchable resources must keep a valid view or edit destination or be disabled from global search in the same implementation slice. Current repo truth shows `WorkspaceResource` and `TenantResource` as the search-eligible surfaces that need explicit review. - **Destructive actions**: no new destructive actions are introduced. Any touched existing destructive actions must preserve `->requiresConfirmation()` plus current server-side authorization. - **Asset strategy**: no new asset registration or deployment step is planned. Existing admin theme/asset handling remains unchanged. ## Workspace-first Routing Fit - Reuse the existing `admin` panel instead of creating a third panel or a nested-environment Filament tenancy model. - Treat `WorkspaceOverview` as the canonical workspace dashboard under `/admin/workspaces/{workspace}` rather than leaving `/admin` as a second environment-like dashboard route. - Treat the current chooser stack as two reuse candidates: `ChooseWorkspace` remains the workspace chooser, while `ManagedTenantsLanding` plus `ChooseTenant` form the environment-selection seams to retarget to `/admin/workspaces/{workspace}/environments`. - Treat `TenantDashboard` as the surviving managed-environment dashboard surface, but move its route ownership and breadcrumb/context shell under the workspace-first family. - Treat `Monitoring\Operations` as the only operations hub, but move its public collection and detail routes under the workspace-first family and preserve explicit `managed_environment_id` filter context when entered from environment pages. - Update `EnsureWorkspaceSelected`, `EnsureFilamentTenantSelected`, `TenantPageCategory`, and `ResolvesPanelTenantContext` together so the same route family defines tenant-bound versus workspace-scoped behavior. - Remove `/admin/t` and `/admin/tenants/{environment}/required-permissions` outright in line with LEAN-001 instead of adding redirects or dual readers. - Remove `/admin/w/{workspace}/managed-tenants` and `/admin/operations` plus `/admin/operations/{run}` outright in line with LEAN-001 instead of leaving a second chooser or operations route language behind. ## UI / Surface Guardrail Plan - **Guardrail scope**: changed surfaces - **Native vs custom classification summary**: native Filament - **Shared-family relevance**: workspace dashboard, environment chooser, managed-environment dashboard, operations hub, related navigation builders, breadcrumbs, context bars - **State layers in scope**: shell, page, detail, URL-query - **Audience modes in scope**: operator-MSP, support-platform - **Decision/diagnostic/raw hierarchy plan**: decision-first on workspace dashboard and environment chooser, diagnostics-second on environment dashboard and operations detail, raw/support evidence remains on downstream pages only - **Raw/support gating plan**: unchanged capability-gated downstream evidence; this slice changes route truth and scope signals, not evidence disclosure - **One-primary-action / duplicate-truth control**: workspace dashboard stays the workspace decision surface, environment chooser stays the one dominant selection step, and environment dashboard keeps one primary follow-up action while breadcrumbs/context bars carry scope once instead of duplicating summaries - **Handling modes by drift class or surface**: review-mandatory - **Repository-signal treatment**: review-mandatory until grep/guard proof shows `/admin/t` and `panel: 'tenant'` are gone from touched operator surfaces - **Special surface test profiles**: standard-native-filament, global-context-shell, monitoring-state-page - **Required tests or manual smoke**: functional-core, state-contract, manual-smoke - **Exception path and spread control**: none; this slice removes the prior shell exception rather than introducing a new one - **Active feature PR close-out entry**: Guardrail ## Shared Pattern & System Fit - **Cross-cutting feature marker**: yes - **Systems touched**: Filament panel providers, chooser pages, workspace dashboard, environment dashboard, operations page, context-bar/navigation builders, middleware/current-context helpers, route classifiers, global-search destinations - **Shared abstractions reused**: `WorkspaceOverviewBuilder`, `TenantDashboardSummaryBuilder`, `WorkspaceContext`, `WorkspaceRedirectResolver`, `OperationRunLinks`, `RelatedNavigationResolver`, existing Filament page/resource action-surface declarations - **New abstraction introduced? why?**: none planned; this slice should replace temporary routing/panel ownership in place - **Why the existing abstraction was sufficient or insufficient**: existing builders and dashboards already own the correct operator truth, but the surrounding panel and route shell still speak a temporary environment-panel language that must be removed - **Bounded deviation / spread control**: none; implementation must converge on the shared builders and one route language rather than growing another local escape hatch ## OperationRun UX Impact - **Touches OperationRun start/completion/link UX?**: yes, shared link semantics only - **Central contract reused**: `OperationRunLinks`, `RelatedNavigationResolver`, `Monitoring\Operations`, `CanonicalNavigationContext` - **Delegated UX behaviors**: workspace-safe URL resolution for the operations collection/detail routes, explicit environment prefiltering via `managed_environment_id`, and environment-to-operations back-link context - **Surface-owned behavior kept local**: environment dashboards and environment-scoped pages supply only the filter context and back-navigation label for the existing operations surface - **Queued DB-notification policy**: `N/A` - **Terminal notification path**: `N/A` - **Exception path**: none ## Provider Boundary & Portability Fit - **Shared provider/platform boundary touched?**: yes - **Provider-owned seams**: provider-specific copy or metadata left on untouched classes such as `TenantResource`, provider connection details, Microsoft-specific profile/permission semantics deferred to later specs - **Platform-core seams**: panel tenancy, workspace-first route nouns, chooser wording, breadcrumb/context hierarchy, current-context resolution, workspace/environment-safe deep-link builders - **Neutral platform terms / contracts preserved**: `workspace`, `managed environment`, `environment`, `operations`, `findings`, `backup sets`, `evidence`, `required permissions` - **Retained provider-specific semantics and why**: untouched provider-owned class names or copy may still use `tenant` until Specs `281` and `286`; this slice only makes the public routing and context contract truthful now - **Bounded extraction or follow-up path**: Specs `281`, `282`, `285`, `286`, and `287` ## Constitution Check *GATE: Must pass before implementation begins and again after the design artifacts are complete.* - Inventory-first / snapshot truth: PASS. This slice changes routing, tenancy, and navigation only; inventory and snapshot semantics remain untouched. - Read/write separation: PASS. No new write workflow or remote-call behavior is introduced. - Graph contract path: PASS. No Graph call, endpoint, or contract-registry work is introduced. - Deterministic capabilities: PASS. Current capability derivation remains; the slice only changes route and panel ownership around existing checks. - RBAC-UX plane separation: PASS. `/admin` and `/system` remain separate. - Workspace isolation: PASS. Workspace membership remains the first route boundary and must stay deny-as-not-found for non-members. - Managed-environment isolation: PASS. Wrong-workspace or inaccessible environment resolution remains `404`, including explicit hostile filter hints. - Destructive action discipline: PASS by non-expansion. Touched destructive actions keep existing `->requiresConfirmation()` and server-side authorization. - Global search safety: PASS with implementation condition. `WorkspaceResource` and `TenantResource` must keep valid view/edit destinations or be disabled from global search. - OperationRun / Ops-UX: PASS. The slice reuses the shared operations hub and changes only route/link semantics. - Data minimization: PASS. No new data or provider-specific persistence is introduced. - Test governance: PASS. Proof stays bounded to focused feature coverage, one browser smoke, and grep/guard checks. - Proportionality / no premature abstraction: PASS. The slice removes a temporary second panel and route family instead of adding framework machinery. - Persisted truth / behavioral state: PASS. No new persistence, state family, DTO layer, taxonomy, or abstraction is introduced. - UI semantics / shared pattern first / Filament-native UI: PASS. Existing native Filament surfaces and shared builders remain the first path. - Provider boundary: PASS. The plan removes provider-shaped routing from platform-core navigation instead of deepening it. **Gate evaluation**: PASS. **Post-design re-check**: PASS while `research.md`, `data-model.md`, `quickstart.md`, `contracts/workspace-tenancy-environment-routing.logical.openapi.yaml`, and `checklists/requirements.md` remain aligned and continue to defer Specs `281` through `287` explicitly. ## Test Governance Check - **Test purpose / classification by changed surface**: Feature, Browser - **Affected validation lanes**: fast-feedback, confidence, browser - **Why this lane mix is the narrowest sufficient proof**: the cutover changes public routes, panel tenancy, chooser flow, breadcrumbs, navigation helpers, and deny-as-not-found semantics. Feature tests prove route ownership and authorization boundaries, while one browser smoke proves the surviving admin-panel flow from workspace selection to environment dashboard to workspace operations. - **Narrowest proving command(s)**: - `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && REPO_ROOT="$(git rev-parse --show-toplevel)" && (cd "$REPO_ROOT/apps/platform" && ./vendor/bin/sail artisan test --compact tests/Feature/Workspace/WorkspaceFilamentTenancyCutoverTest.php tests/Feature/ManagedEnvironment/WorkspaceFirstEnvironmentRoutingTest.php tests/Feature/Monitoring/WorkspaceOperationsEnvironmentContextTest.php tests/Feature/Navigation/WorkspaceEnvironmentBreadcrumbsTest.php tests/Feature/Guards/LegacyAdminTenantRouteRemovalGuardTest.php)` - `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && REPO_ROOT="$(git rev-parse --show-toplevel)" && (cd "$REPO_ROOT/apps/platform" && ./vendor/bin/sail artisan test --compact tests/Browser/Spec280WorkspaceTenancyEnvironmentRoutingSmokeTest.php)` - `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && REPO_ROOT="$(git rev-parse --show-toplevel)" && (cd "$REPO_ROOT/apps/platform" && ./vendor/bin/sail bin pint --dirty --format agent)` - `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && REPO_ROOT="$(git rev-parse --show-toplevel)" && rg -n --fixed-strings '/admin/t/' "$REPO_ROOT/apps/platform/app" "$REPO_ROOT/apps/platform/tests" "$REPO_ROOT/apps/platform/routes" "$REPO_ROOT/apps/platform/bootstrap"` - `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && REPO_ROOT="$(git rev-parse --show-toplevel)" && rg -n --fixed-strings '/admin/tenants/' "$REPO_ROOT/apps/platform/app" "$REPO_ROOT/apps/platform/tests" "$REPO_ROOT/apps/platform/routes" "$REPO_ROOT/apps/platform/bootstrap"` - `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && REPO_ROOT="$(git rev-parse --show-toplevel)" && rg -n --fixed-strings '/admin/w/' "$REPO_ROOT/apps/platform/app" "$REPO_ROOT/apps/platform/tests" "$REPO_ROOT/apps/platform/routes" "$REPO_ROOT/apps/platform/bootstrap"` - `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && REPO_ROOT="$(git rev-parse --show-toplevel)" && rg -n --fixed-strings '/admin/operations' "$REPO_ROOT/apps/platform/app" "$REPO_ROOT/apps/platform/tests" "$REPO_ROOT/apps/platform/routes" "$REPO_ROOT/apps/platform/bootstrap"` - `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && REPO_ROOT="$(git rev-parse --show-toplevel)" && rg -n --fixed-strings "panel: 'tenant'" "$REPO_ROOT/apps/platform/app" "$REPO_ROOT/apps/platform/tests" "$REPO_ROOT/apps/platform/routes" "$REPO_ROOT/apps/platform/bootstrap"` - `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && REPO_ROOT="$(git rev-parse --show-toplevel)" && rg -n --fixed-strings 'TenantPanelProvider::class' "$REPO_ROOT/apps/platform/bootstrap/providers.php"` - **Fixture / helper / factory / seed / context cost risks**: moderate because proof needs workspace membership, managed-environment membership, and remembered-context behaviors without widening helper defaults - **Expensive defaults or shared helper growth introduced?**: no; reuse current workspace/environment helpers and keep any new fixture setup opt-in - **Heavy-family additions, promotions, or visibility changes**: none - **Surface-class relief / special coverage rule**: standard-native-filament relief for most pages; one browser smoke is still required because the entry flow crosses chooser, dashboard, and operations surfaces - **Closing validation and reviewer handoff**: rerun the exact commands above, verify that `TenantPanelProvider` no longer owns public operator routing, confirm `/admin/t`, `/admin/tenants/{environment}/required-permissions`, `/admin/w/{workspace}/managed-tenants`, and `/admin/operations` plus `/admin/operations/{run}` are gone with no redirect/alias fallback, confirm `ChooseTenant`, `ManagedTenantsLanding`, and `WorkspaceRedirectResolver` open workspace-first destinations, confirm `OperationRunLinks` and `RelatedNavigationResolver` emit workspace-first operations URLs with explicit environment context, confirm `TenantPageCategory`, `EnsureWorkspaceSelected`, `EnsureFilamentTenantSelected`, and `ResolvesPanelTenantContext` no longer treat the removed route families as active language, confirm `WorkspaceResource` and `TenantResource` still satisfy the global-search destination rule or are disabled, confirm destructive actions touched by the move still require confirmation, and confirm no new asset or deploy step appears - **Budget / baseline / trend follow-up**: contained feature-local increase only - **Review-stop questions**: did a compatibility route or dual-panel fallback appear, did legacy `panel: 'tenant'` links survive, did `/admin/t`, `/admin/tenants/{environment}`, `/admin/w/{workspace}/managed-tenants`, or `/admin/operations` remain reachable, did wrong-workspace or hostile filter access stop being `404`, did the operations hub lose explicit environment context, did the slice absorb deferred Spec `281`-`287` work - **Escalation path**: `reject-or-split` if the implementation introduces compatibility routes, provider extraction, RBAC redesign, or broad copy/quality-gate work - **Active feature PR close-out entry**: Guardrail - **Why no dedicated follow-up spec is needed**: the remaining adjacent work is already reserved as Specs `281` through `287`; routine routing/tenancy proof stays inside this feature ## Review Checklist Status - **Review checklist artifact**: `checklists/requirements.md` - **Review outcome class**: `implementation-ready` - **Workflow outcome**: `keep` - **Test-governance outcome**: `keep` - **Escalation rule**: if implementation keeps `/admin/t`, keeps `panel: 'tenant'` links, adds compatibility redirects, or absorbs deferred provider/artifact/RBAC/copy/quality-gate work, flip the workflow outcome to `split` or `reject-or-split` ## Rollout Considerations - Land the panel-tenancy flip, route-family rewrite, and current-context helper update as one bounded implementation slice so workspace/environment truth changes atomically. - Remove the temporary `tenant` panel from operator routing instead of leaving a dormant compatibility shell behind. - Retarget chooser flow and shared link builders before polishing individual environment pages so route truth changes at the shared seams first. - Keep direct route guards and grep checks in the same change set so `/admin/t`, `/admin/tenants/{environment}`, `/admin/w/{workspace}/managed-tenants`, `/admin/operations`, and `panel: 'tenant'` do not re-enter the codebase quietly. ## Risk Controls - Reject any implementation that leaves `/admin/t/{environment}`, `/admin/tenants/{environment}/required-permissions`, `/admin/w/{workspace}/managed-tenants`, or `/admin/operations` plus `/admin/operations/{run}` reachable through redirects, aliases, or hidden fallback readers. - Reject any implementation that introduces nested or dual Filament tenancy rather than making `Workspace` the only Filament tenant. - Reject any implementation that rebuilds dashboard signal systems instead of reusing `WorkspaceOverviewBuilder` and `TenantDashboardSummaryBuilder`. - Reject any implementation that retargets operations links page by page instead of through `OperationRunLinks` and related navigation helpers. - Reject any implementation that widens scope into provider extraction, artifact retargeting, RBAC redesign, copy neutralization, or no-legacy quality-gate work reserved for Specs `281` through `287`. ## Research & Design Outputs - `research.md` records the surviving panel choice, workspace-only Filament tenancy, chooser-flow reuse plan, shared operations-link strategy, middleware/current-context convergence plan, global-search treatment, and proof strategy. - `data-model.md` captures the route-context and page-view-model contracts for workspace dashboard, environment chooser, managed-environment dashboard, workspace operations, and searchable destinations. - `quickstart.md` gives reviewers the bounded cutover flow and exact validation commands. - `contracts/workspace-tenancy-environment-routing.logical.openapi.yaml` captures the conceptual GET-route and removed-route contract for the workspace-first runtime. - `checklists/requirements.md` records package readiness, boundedness, and outcome state. ## Project Structure ### Documentation (this feature) ```text specs/280-workspace-tenancy-environment-routing/ ├── checklists/ │ └── requirements.md ├── contracts/ │ └── workspace-tenancy-environment-routing.logical.openapi.yaml ├── data-model.md ├── plan.md ├── quickstart.md ├── research.md ├── spec.md └── tasks.md ``` ### Source Code (expected implementation surfaces) ```text apps/platform/ ├── app/ │ ├── Filament/ │ │ ├── Concerns/ │ │ │ └── ResolvesPanelTenantContext.php │ │ ├── Pages/ │ │ │ ├── ChooseTenant.php │ │ │ ├── ChooseWorkspace.php │ │ │ ├── TenantDashboard.php │ │ │ ├── TenantRequiredPermissions.php │ │ │ ├── WorkspaceOverview.php │ │ │ ├── Monitoring/ │ │ │ │ └── Operations.php │ │ │ └── Workspaces/ │ │ │ └── ManagedTenantsLanding.php │ │ └── Resources/ │ │ ├── TenantResource.php │ │ └── Workspaces/ │ │ └── WorkspaceResource.php │ ├── Providers/Filament/ │ │ ├── AdminPanelProvider.php │ │ └── TenantPanelProvider.php │ ├── Http/Middleware/ │ │ └── EnsureWorkspaceSelected.php │ └── Support/ │ ├── Middleware/ │ │ └── EnsureFilamentTenantSelected.php │ ├── Navigation/ │ │ └── RelatedNavigationResolver.php │ ├── Tenants/ │ │ └── TenantPageCategory.php │ ├── Workspaces/ │ │ └── WorkspaceRedirectResolver.php │ └── OperationRunLinks.php ├── bootstrap/ │ └── providers.php ├── routes/ │ └── web.php └── tests/ ├── Browser/ └── Feature/ ``` **Structure decision**: keep the documentation package self-contained under `specs/280-workspace-tenancy-environment-routing/`; later implementation should modify the existing `apps/platform` panel, route, middleware, and navigation seams directly instead of introducing a parallel routing subsystem. ## Complexity Tracking No constitution violation or bloat exception is introduced by the plan. The slice removes a temporary panel and route family and adds no new persistence, abstraction, state family, or taxonomy. ## Proportionality Review - **Current operator problem**: the operator runtime still communicates two public truths by splitting workspace work under `/admin` and environment work under `/admin/t`. - **Existing structure is insufficient because**: the temporary second panel is encoded in providers, chooser redirects, middleware, route categorization, breadcrumbs, and shared deep-link builders, so a local redirect fix would preserve the same structural drift. - **Narrowest correct implementation**: reuse the existing `admin` panel, dashboard builders, chooser surfaces, and operations hub while replacing only the panel-tenancy and route-contract shell around them. - **Ownership cost created**: focused route, middleware, link-builder, and browser/feature proof work across several shared seams. - **Alternative intentionally rejected**: keeping `/admin/t` with redirects or dual-panel ownership, because it preserves the temporary shell and contradicts the pre-production no-legacy doctrine. - **Release truth**: current-release truth; this is a bounded cutover slice, not future-framework preparation.