295 lines
29 KiB
Markdown
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.
|