## 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
192 lines
9.4 KiB
Markdown
192 lines
9.4 KiB
Markdown
# Data Model: Filament Workspace Tenancy & Environment Routing Cutover
|
||
|
||
**Date**: 2026-05-07
|
||
**Branch**: `280-workspace-tenancy-environment-routing`
|
||
|
||
## Overview
|
||
|
||
This slice introduces no new persistence. It replaces a temporary routing and panel-tenancy shell with a workspace-first runtime contract built on existing `Workspace` and `ManagedEnvironment` truth. The data model for this package is therefore a set of derived route, view-model, and navigation contracts that implementation must keep aligned across pages, middleware, and shared link builders.
|
||
|
||
## Persisted Truth Unchanged
|
||
|
||
- `Workspace` remains the workspace-owned root context.
|
||
- `ManagedEnvironment` remains the environment-scoped managed target inside one workspace.
|
||
- No table ownership, foreign-key ownership, artifact ownership, or role/capability family changes are introduced in this slice.
|
||
- Provider registration remains in `apps/platform/bootstrap/providers.php`; no new provider or asset persistence is introduced.
|
||
|
||
## Derived Runtime Contracts
|
||
|
||
### 1. Workspace Admin Context
|
||
|
||
**Persistence**: derived from route parameters plus `WorkspaceContext` session state
|
||
**Owner**: workspace-first admin shell
|
||
|
||
| Field | Type | Required | Notes |
|
||
|---|---|---|---|
|
||
| `workspace_id` | int | yes | Canonical workspace scope for the current request |
|
||
| `workspace_slug` | string | yes | Route-safe workspace identifier |
|
||
| `workspace_name` | string | yes | Operator-visible workspace label |
|
||
| `entry_mode` | string | yes | `chooser` or `dashboard` |
|
||
| `remembered_environment_id` | int | no | Derived only when the remembered environment belongs to the same workspace |
|
||
|
||
**Rules**:
|
||
|
||
- `/admin` resolves through this contract to either workspace selection or the canonical workspace dashboard.
|
||
- Non-member workspace access remains `404`.
|
||
- Switching workspaces invalidates any remembered environment that belongs to another workspace before any environment page renders.
|
||
|
||
### 2. Workspace Dashboard View
|
||
|
||
**Persistence**: none, derived from `WorkspaceOverviewBuilder`
|
||
**Owner**: `WorkspaceOverview`
|
||
|
||
| Field | Type | Required | Notes |
|
||
|---|---|---|---|
|
||
| `workspace` | object | yes | Workspace summary for the active workspace |
|
||
| `overview_payload` | array | yes | Existing builder output for signal cards, summaries, and quick actions |
|
||
| `environment_chooser_url` | string | yes | Canonical workspace-scoped environment chooser route |
|
||
| `operations_url` | string | yes | Canonical workspace operations route |
|
||
|
||
**Rules**:
|
||
|
||
- The workspace dashboard is the primary decision surface after workspace selection.
|
||
- It must not silently behave like a second environment dashboard.
|
||
- It reuses current builder output rather than introducing a new summary system.
|
||
|
||
### 3. Environment Chooser View
|
||
|
||
**Persistence**: none, derived from `ManagedTenantsLanding` data plus existing `ChooseTenant` selection logic
|
||
**Owner**: workspace-scoped environment chooser surface
|
||
|
||
| Field | Type | Required | Notes |
|
||
|---|---|---|---|
|
||
| `workspace` | object | yes | Active workspace summary |
|
||
| `environments` | list<object> | yes | Selectable managed environments within the workspace |
|
||
| `open_environment_url` | string | yes | Workspace-first environment dashboard URL per row/card |
|
||
| `switch_workspace_url` | string | no | Secondary escape hatch back to workspace choice |
|
||
|
||
**Environment item fields**:
|
||
|
||
| Field | Type | Required | Notes |
|
||
|---|---|---|---|
|
||
| `id` | int | yes | ManagedEnvironment key |
|
||
| `slug` | string | yes | Route-safe environment identifier |
|
||
| `name` | string | yes | Operator-visible environment label |
|
||
| `lifecycle_status` | string | yes | Existing operability/lifecycle status |
|
||
| `posture_hint` | string | no | Existing discoverability/operability summary only |
|
||
|
||
**Rules**:
|
||
|
||
- Only environments belonging to the active workspace and accessible to the actor appear.
|
||
- Archived or otherwise non-selectable environments do not appear and do not resolve.
|
||
- `ChooseTenant` may survive as an implementation seam, but not as a second public chooser contract.
|
||
|
||
### 4. Managed Environment Page Context
|
||
|
||
**Persistence**: derived from workspace-first route parameters plus `WorkspaceContext`
|
||
**Owner**: all environment-scoped pages touched by this slice
|
||
|
||
| Field | Type | Required | Notes |
|
||
|---|---|---|---|
|
||
| `workspace_id` | int | yes | Outer scope boundary |
|
||
| `workspace_slug` | string | yes | Outer scope route key |
|
||
| `managed_environment_id` | int | yes | Nested environment scope |
|
||
| `managed_environment_slug` | string | yes | Nested environment route key |
|
||
| `managed_environment_name` | string | yes | Operator-visible environment label |
|
||
| `breadcrumb_segments` | list<object> | yes | `Workspace -> Managed Environment -> page` |
|
||
| `page_category` | string | yes | Derived route classification after legacy families are removed |
|
||
|
||
**Rules**:
|
||
|
||
- The `{environment}` parameter must belong to the `{workspace}` parameter or the request is `404`.
|
||
- Breadcrumb and context-bar ordering must always be `Workspace -> Managed Environment -> page`.
|
||
- No touched page may keep `/admin/t` or `/admin/tenants/{environment}` as a valid public route.
|
||
|
||
### 5. Managed Environment Dashboard View
|
||
|
||
**Persistence**: none, derived from `TenantDashboardSummaryBuilder` and current dashboard widgets
|
||
**Owner**: `TenantDashboard`
|
||
|
||
| Field | Type | Required | Notes |
|
||
|---|---|---|---|
|
||
| `workspace` | object | yes | Outer workspace summary for breadcrumb/context |
|
||
| `managed_environment` | object | yes | Active environment summary |
|
||
| `dashboard_summary` | array | yes | Existing summary-builder payload |
|
||
| `primary_follow_up_url` | string | no | Existing recommended-action destination |
|
||
| `operations_url` | string | yes | Canonical workspace operations route with explicit environment filter |
|
||
|
||
**Rules**:
|
||
|
||
- The surface remains the canonical environment dashboard.
|
||
- Existing widget and header-action ownership stays intact.
|
||
- Operations navigation from this surface always enters the workspace operations family with explicit environment context.
|
||
|
||
### 6. Workspace Operations Scope
|
||
|
||
**Persistence**: derived route/query/session state already modeled by `Monitoring\Operations`
|
||
**Owner**: canonical workspace operations hub and detail viewer
|
||
|
||
| Field | Type | Required | Notes |
|
||
|---|---|---|---|
|
||
| `workspace_id` | int | yes | Required workspace scope |
|
||
| `managed_environment_id` | int | no | Optional environment prefilter |
|
||
| `tenant_scope` | string | no | Existing workspace-wide versus narrowed state flag |
|
||
| `active_tab` | string | no | Existing operations tab state |
|
||
| `problem_class` | string | no | Existing scoped deep-link filter |
|
||
| `nav_context` | object | no | Back-link label and URL for environment return flow |
|
||
|
||
**Rules**:
|
||
|
||
- The collection route is `/admin/workspaces/{workspace}/operations`.
|
||
- The detail route is `/admin/workspaces/{workspace}/operations/{run}`.
|
||
- Explicit environment filters outside the current workspace or actor entitlement are `404`.
|
||
- Stale remembered environment filters may be discarded, but explicit hostile filters may not widen scope silently.
|
||
|
||
### 7. Searchable Destination Contract
|
||
|
||
**Persistence**: none, derived from Filament resource configuration
|
||
**Owner**: touched globally searchable resources
|
||
|
||
| Field | Type | Required | Notes |
|
||
|---|---|---|---|
|
||
| `resource_key` | string | yes | `workspace` or `managed_environment` |
|
||
| `record_title_attribute` | string | yes | Existing Filament record title attribute |
|
||
| `destination_kind` | string | yes | `view` or `edit` |
|
||
| `destination_route` | string | yes | Valid route after the workspace-first cutover |
|
||
| `global_search_enabled` | bool | yes | Search remains enabled only if destination stays valid |
|
||
|
||
**Rules**:
|
||
|
||
- `WorkspaceResource` remains searchable only if its view/edit destination stays valid.
|
||
- `TenantResource` remains searchable only if its view/edit destination stays valid after the environment route move.
|
||
- Touched surfaces that cannot satisfy Filament’s view/edit rule must be disabled from global search in the same slice.
|
||
|
||
## Route Invariants
|
||
|
||
- Public operator route families after the cutover are rooted at `/admin/workspaces/{workspace}`.
|
||
- `/admin/t/{environment}` is removed, not redirected.
|
||
- `/admin/tenants/{environment}/required-permissions` is removed, not redirected.
|
||
- `/admin/w/{workspace}/managed-tenants` is removed, not redirected.
|
||
- `/admin/operations` and `/admin/operations/{run}` are removed, not redirected.
|
||
- Shared builders and helpers must stop emitting `panel: 'tenant'` for touched operator destinations.
|
||
- `Workspace` is the only Filament tenant for operator routing; `ManagedEnvironment` is nested route context only.
|
||
|
||
## State Transitions
|
||
|
||
1. `NoWorkspaceSelected` -> `ChooseWorkspace`
|
||
2. `WorkspaceSelected` -> `WorkspaceDashboard`
|
||
3. `WorkspaceDashboard` -> `EnvironmentChooser`
|
||
4. `EnvironmentChooser` -> `ManagedEnvironmentDashboard`
|
||
5. `ManagedEnvironmentDashboard` -> `EnvironmentScopedPage` or `WorkspaceOperationsScope`
|
||
6. `WorkspaceSwitch` -> clear cross-workspace environment context before rendering the new workspace dashboard or chooser
|
||
7. `LegacyEnvironmentRouteRequested` -> `NotFound`
|
||
8. `LegacyWorkspaceChooserRequested` -> `NotFound`
|
||
9. `LegacyOperationsRouteRequested` -> `NotFound`
|
||
|
||
## Deferred Boundaries
|
||
|
||
- No new provider connection/profile entity or abstraction is introduced here.
|
||
- No artifact ownership retargeting is introduced here.
|
||
- No RBAC role or capability family change is introduced here.
|
||
- No UI copy neutralization or localization rewrite is introduced here.
|
||
- No quality-gate pack or no-legacy automation beyond the local grep/guard proof is introduced here. |