## Summary - replace the legacy Tenant and TenantMembership core models with ManagedEnvironment and ManagedEnvironmentMembership - propagate the managed environment naming and key changes across Filament resources, pages, controllers, jobs, models, and supporting runtime paths - add feature 279 spec artifacts and focused managed-environment test coverage for model behavior, route binding, panel context, authorization, and legacy guardrails ## Validation - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/ManagedEnvironment/LegacyTenantCoreGuardTest.php tests/Feature/ManagedEnvironment/ManagedEnvironmentAuthorizationTest.php tests/Feature/ManagedEnvironment/ManagedEnvironmentPanelContextTest.php tests/Feature/ManagedEnvironment/ManagedEnvironmentRouteBindingTest.php tests/Unit/ManagedEnvironment/ManagedEnvironmentContextResolverTest.php tests/Unit/ManagedEnvironment/ManagedEnvironmentModelTest.php` - `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent` ## Notes - branch pushed from commit `1123b122` - browser smoke test file was added but not run in this pass Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #335
6.1 KiB
Data Model: Workspace-first Managed Environment Core Cutover
Date: 2026-05-06
Branch: 279-workspace-managed-environment-core
Overview
This slice introduces one new managed-target root record and replaces the current tenant-core anchor. Workspace remains the primary SaaS context. ManagedEnvironment becomes the environment-scoped root record under a workspace. Current environment-scoped records retarget from tenant_id to managed_environment_id in core-owned paths only, with no compatibility columns.
New Persisted Truth
1. Managed Environment
Persistence: new managed_environments table
Ownership: managed-target root scoped to one workspace
Lifecycle: current-release core entity
| Field | Type | Nullable | Notes |
|---|---|---|---|
id |
bigint | no | Internal primary key |
workspace_id |
bigint | no | Required parent workspace |
slug |
string | no | Neutral route key inside the workspace |
name |
string | no | Internal canonical name |
display_name |
string | yes | Operator-facing label when it differs from name |
kind |
string | no | Bounded current-release category for the managed target |
lifecycle_status |
string | no | Selectability and lifecycle posture for current context |
metadata |
jsonb | yes | Provider-neutral environment metadata only |
created_at |
timestamp | yes | Standard timestamp |
updated_at |
timestamp | yes | Standard timestamp |
Rules:
ManagedEnvironmentmust not store Microsoft-specific identity, Graph, or Intune fields.metadatamay store only neutral presentation or lifecycle hints such as internal labels, neutral tags, or operator notes; it must not store provider tenant IDs, domains, Graph scopes, consent identifiers, or raw provider profiles.- The route key should be neutral and operator-safe.
- Archived or inactive environments are not selectable current context by default.
2. Managed Environment Membership
Persistence: renamed or replaced environment-membership table
Ownership: environment-scoped access truth
| Field | Type | Nullable | Notes |
|---|---|---|---|
id |
bigint | no | Internal primary key |
user_id |
bigint | no | Member actor |
managed_environment_id |
bigint | no | Environment scope |
role |
string | no | Existing role semantics preserved in this slice |
source |
string | yes | Existing source semantics preserved where still needed |
source_ref |
string | yes | Existing external source reference if still used |
created_by_user_id |
bigint | yes | Existing audit-facing author field if still used |
created_at |
timestamp | yes | Standard timestamp |
updated_at |
timestamp | yes | Standard timestamp |
Rules:
- This slice preserves current membership semantics; it only changes the scoped target noun and foreign key.
- Workspace membership remains the first access boundary.
Retargeted Existing Truth
3. Workspace Relation
Workspace changes from hasMany(Tenant::class) to hasMany(ManagedEnvironment::class).
4. Environment-scoped Foreign-Key Contract
Current environment-scoped records move from tenant_id to managed_environment_id in core-owned paths only.
This package intentionally treats the precise table list as implementation inventory driven by current repo truth through TenantOwnedModelFamilies plus schema grep. The retargeting set is limited to current core-owned model families that use tenant_id as the active managed-target key in:
- current root-selection, membership, and current-context families
- current panel/query/helper seams that need the new managed-target key to resolve scope honestly
- current commands, fixtures, and tests that resolve active target scope directly through
tenant_id
Rules:
- no dual columns
- no
tenant_idplusmanaged_environment_idoverlap - no alias relationships that keep both nouns active
Derived Runtime Contracts
5. Current Context Contract
Persistence: existing context/session helpers, retargeted
Owner: workspace + managed-environment selection flow
| Field | Type | Required | Notes |
|---|---|---|---|
current_workspace_id |
int | yes | Existing primary SaaS context |
current_managed_environment_id |
int | yes | Replaces current tenant-scoped active target |
current_managed_environment_slug |
string | yes | Route-safe current target key |
Rules:
- The app must not keep an active current-tenant contract in parallel.
- Existing chooser and panel-shell flows resolve through workspace plus managed environment together.
6. Temporary Environment Shell Route Contract
Persistence: none, route-model binding only
Owner: current environment-scoped panel shell
| Field | Type | Required | Notes |
|---|---|---|---|
path_family |
string | yes | Temporarily /admin/t/{environment} |
bound_model |
string | yes | ManagedEnvironment |
exception_owner |
string | yes | Spec 279, closed by Spec 280 |
Rules:
- this is the only allowed public-path exception in this slice
- the path family must not coexist with a second compatibility route family
- the route parameter meaning changes from tenant to managed environment immediately
Boundaries Explicitly Preserved
Workspaceremains the primary SaaS context.- Provider-specific identity remains outside
ManagedEnvironment. - Provider-connection extraction and broader governance-artifact retargeting remain follow-up work for Specs
281and282. - Broader workspace-first route-family and breadcrumb rewrite remain Spec
280. - Provider-profile extraction remains Spec
281. - Artifact retargeting polish remains Spec
282. - RBAC redesign remains Spec
285. - Copy/localization neutralization remains Spec
286.
Cutover Invariants
- No active
App\Models\Tenantremains in core-owned paths after implementation. - No
->tenant(Tenant::class)Filament tenant binding remains. - No
tenant_idcompatibility columns remain in the cutover set. - No Microsoft-specific identity fields land on
ManagedEnvironment. - The only temporary exception is the public
/admin/t/{environment}path family until Spec280.