TenantAtlas/specs/280-workspace-tenancy-environment-routing/plan.md
Ahmed Darrazi 40a33cdc15
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 1m35s
spec: prepare workspace tenancy environment routing cutover
2026-05-07 12:12:39 +02:00

29 KiB

Implementation Plan: Filament Workspace Tenancy & Environment Routing Cutover

Branch: 280-workspace-tenancy-environment-routing | Date: 2026-05-07 | Spec: 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)

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)

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.