TenantAtlas/specs/280-workspace-tenancy-environment-routing/plan.md
ahmido 670c46dedd Spec 280: prepare workspace tenancy and environment routing cutover (#336)
## Summary
- add the implementation-ready spec-prep artifacts for Spec 280: Filament Workspace Tenancy & Environment Routing Cutover
- define the bounded scope, rollout constraints, route contract, and validation plan for the workspace-first routing cutover
- update the generated Copilot agent context for the active feature branch

## Testing
- not run; this branch adds spec-prep artifacts only and does not change application code

## Notes
- no application runtime, database, or frontend code changes are included in this PR
- target base branch requested: `platform-dev`

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #336
2026-05-07 10:20:43 +00:00

295 lines
29 KiB
Markdown

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