34 KiB
Feature Specification: Workspace-first Managed Environment Core Cutover
Feature Branch: 279-workspace-managed-environment-core
Created: 2026-05-06
Status: Ready with approved feature-local exception
Input: User description: "Use the next unspecced reserved cutover slot from the roadmap/spec-candidate pack and prepare the Workspace-first Managed Environment Core Cutover package as the next bounded implementation-ready spec."
Spec Candidate Check
- Problem: TenantPilot still treats
Tenantas the active managed-target core across models, route binding, Filament tenancy, memberships, query helpers, and operator context. That blocks the planned workspace-first / provider-neutral evolution because the platform core still assumes the managed target is a Microsoft-shaped tenant instead of a generic managed environment inside a workspace. - Today's failure: Current repo seams such as
TenantPanelProvider,Tenant,ProviderConnection::tenant(), tenant-owned query helpers,Filament::getTenant()usage, and manytenant_idforeign keys force every new workspace-first or provider-neutral change to either deepenTenantcoupling or add compatibility shims the constitution explicitly rejects. - User-visible improvement: Operators and future features get one consistent managed-target identity inside a workspace. Context selection, authorization boundaries, route binding, and current environment-scoped surfaces stop depending on
Tenantas platform-core truth. - Smallest enterprise-capable version: Replace
Tenantas the active managed-target core withManagedEnvironment, retarget current core foreign-key anchors and context helpers tomanaged_environment_id, keep the existing panel bootable by temporarily rebinding the current/admin/t/{environment}path family toManagedEnvironment, and defer the public workspace-first route/IA rewrite, provider-profile extraction, artifact retargeting refinements, and RBAC scope redesign to follow-up specs280-287. - Explicit non-goals: No dual-read or dual-write compatibility layer, no legacy
Tenantalias model, no production-data backfill strategy, no full workspace-first public route-family rewrite, no provider-profile extraction, no artifact-language rewrite, no package engine, no guided-operations layer, and no speculative multi-provider framework. - Permanent complexity imported: One new managed-target root entity, one breaking schema cutover from
tenant_idtomanaged_environment_id, one renamed environment-membership seam, existing context-helper replacement, and focused unit/feature/browser plus guard-test coverage. - Why now:
279is the first unspecced reserved slot in the roadmap-backed cutover pack, and every later cutover spec (280-287) depends on this core replacement. Waiting adds moreTenant- and Microsoft-specific coupling to the platform core. - Why not local: The problem spans schema, Eloquent relations, route binding, Filament tenancy, current-context resolution, authorization helpers, commands, and tests. A local rename or adapter would immediately drift.
- Approval class: Core Enterprise
- Red flags triggered: New persisted truth, new state family, many touched seams, and a foundation-sounding cutover. Defense: this is current-release architecture truth, not speculative extensibility; it explicitly forbids compatibility shims and defers broader route, copy, provider, and artifact follow-through to the next reserved specs.
- Score: Nutzen: 2 | Dringlichkeit: 2 | Scope: 1 | Komplexitaet: 1 | Produktnaehe: 1 | Wiederverwendung: 2 | Gesamt: 9/12
- Decision: approve
Spec Scope Fields
- Scope: workspace
- Primary Routes:
- existing workspace chooser route under
/admin - existing tenant chooser surface, retargeted to managed-environment selection
- current environment-scoped panel routes under
/admin/t/{environment}as a temporary bounded exception until Spec280replaces the public path family - current admin resource/detail routes that bind the managed target model directly or derive environment context from it
- existing workspace chooser route under
- Data Ownership:
Workspaceremains the primary SaaS and organization contextManagedEnvironmentbecomes the new managed-target root record inside a workspace- current core-owned managed-target anchors and context-owned relations retarget from
tenant_idtomanaged_environment_id; provider-connection extraction and broader governance-artifact retargeting remain follow-up work for Specs281and282
- RBAC:
- workspace membership remains the first isolation boundary
- current tenant-membership semantics are retargeted to managed-environment membership semantics without widening role scope in this spec
- wrong-workspace and non-member access remain
404 - in-scope actors missing a capability remain
403
Canonical-view handling for current admin surfaces:
- Default filter behavior when tenant-context is active: current canonical admin views continue to prefilter to the active managed environment whenever they currently prefilter to the active tenant; broader workspace-first canonical-view semantics remain Spec
280follow-up work - Explicit entitlement checks preventing cross-tenant leakage: any route, query helper, or global-search path that currently resolves tenant scope must resolve the active managed environment plus current workspace membership before revealing environment-bound records
Cross-Cutting / Shared Pattern Reuse
- Cross-cutting feature?: yes
- Interaction class(es): context selection, route links, global-search scoping, current-target chips, resource query helpers, and environment-bound deep links
- Systems touched:
TenantPanelProvider,WorkspaceContext,ChooseTenant,ResolvesPanelTenantContext,InteractsWithTenantOwnedRecords,ScopesGlobalSearchToTenant,TenantOwnedModelFamilies,OperationRunLinks, current tenant widgets, and tenant-scoped resources/pages - Existing pattern(s) to extend: workspace-first context storage, current Filament panel-provider seams, current deny-as-not-found membership enforcement, and existing environment-bound route builders
- Shared contract / presenter / builder / renderer to reuse: existing
WorkspaceContext, panel-provider registration, current resource query scoping helpers,OperationRunLinks, and the existing workspace capability resolver - Why the existing shared path is sufficient or insufficient: those seams are sufficient as cutover points, but insufficient because they still encode
Tenantas the platform-core managed target - Exception type:
Cross-panel Canonical Route Exception - Allowed deviation and why: one bounded deviation is allowed: the current
/admin/t/{environment}shell may remain temporarily while bindingManagedEnvironmentinstead ofTenant, even though the source-pack end state moves Filament tenancy toWorkspacein Spec280. This temporary bridge exists only to keep the runtime operable whileTenantis removed from the core. No second compatibility route family is allowed. - Reason block: only one canonical surface makes sense during the cutover. Keeping the existing shell avoids a second public route family, keeps shell transition explicit, preserves truthful scope signals, and leaves final canonical Workspace tenancy to Spec
280. - Dedicated proof:
apps/platform/tests/Feature/ManagedEnvironment/ManagedEnvironmentPanelContextTest.php,apps/platform/tests/Browser/Spec279ManagedEnvironmentCoreCutoverSmokeTest.php, andspecs/279-workspace-managed-environment-core/checklists/constitution-scope-001-exception.md - Consistency impact: route keys, chooser labels, context bars, global-search scope resolution, tenant-owned query helpers, and deep-link builders must all agree on
ManagedEnvironmentas the active managed target - Review focus: reviewers must verify that the cutover replaces current shared seams in place, that the temporary
/admin/tpath is the only documented exception, and that no alias model or second context stack appears
OperationRun UX Impact
- Touches OperationRun start/completion/link UX?: yes, link semantics only
- Shared OperationRun UX contract/layer reused:
OperationRunLinksand the existing OperationRun URL-resolution helpers - Delegated start/completion UX behaviors: tenant/workspace-safe environment link resolution only; no new queued toasts, start events, completion notifications, or dedupe messaging are added in this slice
- Local surface-owned behavior that remains: none; existing surfaces continue to use the central OperationRun link helpers after their context model is retargeted
- Queued DB-notification policy:
N/A - Terminal notification path:
N/A - Exception required?: yes - the temporary
/admin/t/{environment}path retention described above. This is a bounded route exception only and does not permit a second compatibility family.
Provider Boundary / Platform Core Check
- Shared provider/platform boundary touched?: yes
- Boundary classification: mixed
- Seams affected: managed-target identity, provider-connection foreign-key anchors, current context model, operator vocabulary, route binding, and current target selection
- Neutral platform terms preserved or introduced:
workspace,managed environment,provider connection,target scope,operation,finding,review, andgovernance artifact - Provider-specific semantics retained and why: Microsoft-specific identifiers such as
entra_tenant_id, Graph consent details, and portal metadata may remain in provider-owned tables or provider metadata until Spec281extracts and normalizes them. They must not live onManagedEnvironment. - Why this does not deepen provider coupling accidentally: the core cutover explicitly forbids Microsoft-specific identity, Graph, or Intune fields on
ManagedEnvironmentand replacesTenantas the shared core noun - Follow-up path: Spec
281for provider-profile extraction, Spec284for provider-neutral artifact-source taxonomy, and Spec286for copy/localization cleanup
UI / Surface Guardrail Impact
| Surface / Change | Operator-facing surface change? | Native vs Custom | Shared-Family Relevance | State Layers Touched | Exception Needed? | Low-Impact / N/A Note |
|---|---|---|---|---|---|---|
| Managed-environment chooser replacing current tenant chooser | yes | Native Filament page | context selection, navigation entry point | page, URL/query | no | Keeps the existing chooser family and retargets it to managed environments |
Current environment-scoped panel routes under /admin/t/{environment} |
yes | Native Filament panel shell | route links, context bar, global search, resource scope | shell, page, detail, URL/query | yes | Temporary path retention only until Spec 280 owns the public route-family rewrite |
Admin directory/resource surfaces that currently list Tenant records |
yes | Native Filament resources/pages | detail links, current-target summaries | page, detail | no | Core noun and route binding change here; broader IA and copy polish remain deferred |
Decision-First Surface Role
| Surface | Decision Role | Human-in-the-loop Moment | Immediately Visible for First Decision | On-Demand Detail / Evidence | Why This Is Primary or Why Not | Workflow Alignment | Attention-load Reduction |
|---|---|---|---|---|---|---|---|
| Managed-environment chooser | Primary Decision Surface | Operator selects the current managed target inside the active workspace | environment name, display name, lifecycle posture, and current workspace | provider-specific diagnostics stay secondary and remain follow-up work | Primary because current environment selection is the first explicit decision before any environment-scoped workflow begins | Keeps the existing current-target selection workflow intact | Removes ambiguity between workspace scope and managed-target scope |
| Current environment-scoped panel shell | Secondary Context Surface | Operator verifies they are acting in the correct managed environment while using existing pages | active workspace plus active managed-environment identity | deeper provider or governance detail remains on the current pages | Not primary because it carries context while work happens elsewhere | Aligns with existing panel-shell behavior instead of inventing a new workbench | Reduces wrong-target actions during the cutover |
Audience-Aware Disclosure
| Surface | Audience Modes In Scope | Decision-First Default-Visible Content | Operator Diagnostics | Support / Raw Evidence | One Dominant Next Action | Hidden / Gated By Default | Duplicate-Truth Prevention |
|---|---|---|---|---|---|---|---|
| Managed-environment chooser | operator-MSP, support-platform | environment identity, display name, lifecycle posture, and workspace context | provider-health detail and migration notes remain secondary | raw provider metadata stays hidden | Enter environment |
provider-specific raw metadata | chooser cards show selection truth once and defer diagnostics |
| Current environment-scoped panel shell | operator-MSP, support-platform | active workspace and active managed-environment context | deeper per-page diagnostics remain where they already live | raw payloads remain page-local and secondary | existing page action | any migration/debug hints stay lower-priority | shell surfaces should not repeat full page-level summaries |
UI/UX Surface Classification
| Surface | Action Surface Class | Surface Type | Likely Next Operator Action | Primary Inspect/Open Model | Row Click | Secondary Actions Placement | Destructive Actions Placement | Canonical Collection Route | Canonical Detail Route | Scope Signals | Canonical Noun | Critical Truth Visible by Default | Exception Type / Justification |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Managed-environment chooser | Selector / Context / Entry | Context-selection page | Enter the intended managed environment | card/list selection | optional current pattern | workspace switch remains secondary | none | /admin/choose-environment (logical) |
environment entry path | active workspace plus environment identity | Managed environment | selected target identity and lifecycle posture | none |
| Current environment-scoped panel shell | Shell / Context / Navigation | Filament panel shell | Continue into the current environment page | current shell context | forbidden | page-local links stay secondary | none | /admin/t/{environment} (temporary) |
existing page routes under the shell | active workspace plus active managed environment | Managed environment | current environment identity | temporary route retention until Spec 280 |
Operator Surface Contract
| Surface | Primary Persona | Decision / Operator Action Supported | Surface Type | Primary Operator Question | Default-visible Information | Diagnostics-only Information | Status Dimensions Used | Mutation Scope | Primary Actions | Dangerous Actions |
|---|---|---|---|---|---|---|---|---|---|---|
| Managed-environment chooser | TenantPilot operator | Decide which managed environment inside the current workspace should become active | Context-selection page | Which managed environment am I about to act in? | environment identity, workspace context, lifecycle posture | provider-specific diagnostics and migration detail | lifecycle, access posture | none | Enter environment | none |
| Current environment-scoped panel shell | TenantPilot operator | Confirm that all current environment-bound pages resolve the right managed target | Panel shell | Am I in the correct workspace and managed environment? | active workspace and active managed-environment identity | page-local diagnostics only | access posture, lifecycle | none | existing page action | none |
Proportionality Review
- New source of truth?: yes
- New persisted entity/table/artifact?: yes
- New abstraction?: no new generic abstraction; existing tenant-context seams are replaced or neutralized in place
- New enum/state/reason family?: yes, bounded managed-environment kind and lifecycle posture fields
- New cross-domain UI framework/taxonomy?: no
- Current operator problem: the product cannot become workspace-first or provider-neutral while the core managed target, current context, and route binding still assume
Tenant - Existing structure is insufficient because: the current
Tenantmodel mixes managed-target identity, provider-specific metadata, current-context behavior, and Filament tenant binding across the app - Narrowest correct implementation: a single breaking core cutover to
ManagedEnvironmentwith one documented temporary route-path exception and no compatibility aliases - Ownership cost: broad schema and relation retargeting, command and test updates, temporary exception tracking for
/admin/t/{environment}, and explicit follow-up ownership for Specs280-287 - Alternative intentionally rejected: dual-read/dual-write aliases, a
Tenantwrapper aroundManagedEnvironment, or one giant combined route/IA/provider/artifact rewrite. Those options either violate the constitution or make the first cutover slice too broad to review safely. - Release truth: current-release truth with explicit follow-up slices for the remaining cutover pack
Compatibility posture
This feature assumes a pre-production environment.
Backward compatibility, legacy aliases, dual-read/dual-write shims, historical fixtures, and compatibility-specific tests are out of scope unless explicitly required by this spec.
Canonical replacement is preferred over preservation.
Testing / Lane / Runtime Impact
- Test purpose / classification: Unit, Feature, Browser
- Validation lane(s): fast-feedback, confidence, browser
- Why this classification and these lanes are sufficient: the cutover changes core model truth, route/model binding, and Filament context selection. Unit tests prove model and context rules, feature tests prove scope and routing semantics, and one browser smoke proves the workspace-to-environment selection flow stays operable after the cutover.
- New or expanded test families: one managed-environment unit family, one managed-environment feature family, and one narrow browser smoke
- Fixture / helper cost impact: moderate; existing tenant fixtures and helper families must be replaced with managed-environment equivalents rather than layered adapters
- Heavy-family visibility / justification: none
- Special surface test profile: standard-native-filament, global-context-shell, exception-coded-surface
- Standard-native relief or required special coverage: standard Filament feature coverage is sufficient for chooser and panel-context semantics; one browser smoke is required because the cutover changes end-to-end context selection and panel bootstrapping
- Reviewer handoff: reviewers must verify that
ManagedEnvironmentreplacesTenantin core-owned paths, the temporary/admin/texception is the only path deviation, the legacy-core guard provestenant_idremoval inside the declared core-owned cutover inventory while keeping Specs281and282exclusions explicit,ManagedEnvironmentcarries no Microsoft-specific identity fields, any touched globally searchable resource still satisfies Filament’s edit/view eligibility rule or remains out of global search, no new asset registration or deployment-step change appears, and provider registration remains inapps/platform/bootstrap/providers.php - Budget / baseline / trend impact: moderate feature-local increase only
- Escalation needed:
document-in-featurefor the temporary/admin/tpath exception;follow-up-specalready assigned for the remaining cutover pack - Active feature PR close-out entry: Guardrail
- Planned validation commands:
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/Unit/ManagedEnvironment/ManagedEnvironmentModelTest.php tests/Unit/ManagedEnvironment/ManagedEnvironmentContextResolverTest.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/Feature/ManagedEnvironment/ManagedEnvironmentRouteBindingTest.php tests/Feature/ManagedEnvironment/ManagedEnvironmentAuthorizationTest.php tests/Feature/ManagedEnvironment/ManagedEnvironmentPanelContextTest.php tests/Feature/ManagedEnvironment/LegacyTenantCoreGuardTest.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/Spec279ManagedEnvironmentCoreCutoverSmokeTest.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 'App\Models\Tenant' "$REPO_ROOT/apps/platform/app" "$REPO_ROOT/apps/platform/tests" "$REPO_ROOT/apps/platform/database"export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && REPO_ROOT="$(git rev-parse --show-toplevel)" && rg -n -- '->tenant\(Tenant::class' "$REPO_ROOT/apps/platform/app" "$REPO_ROOT/apps/platform/tests" "$REPO_ROOT/apps/platform/database"
Scope Boundaries (required for this slice)
In Scope
- introduce
ManagedEnvironmentas the active managed-target root inside a workspace - introduce the breaking schema/model cutover away from
Tenantandtenant_idin core-owned paths - retarget current context selection, route binding, query helpers, memberships, and the current tenant-panel shell bridge to
ManagedEnvironmentwhile keeping the finalWorkspaceFilament-tenancy switch deferred to Spec280 - keep the current environment-scoped panel operable through the documented temporary
/admin/t/{environment}exception until Spec280 - update factories, seeders, policies, guards, route binding, and tests so core-owned paths no longer rely on
App\Models\Tenant - ensure
ManagedEnvironmentcarries no Microsoft-specific identity, Graph, or Intune fields
Non-Goals
- final workspace-first public route family and navigation IA rewrite
- provider-profile extraction and provider-scope normalization
- governance artifact naming and route retargeting polish
- RBAC scope redesign or new capability families
- copy/localization neutralization beyond the minimum core cutover terms
- quality-gate automation beyond the feature-local guard tests needed for this slice
- package execution, guided operations, virtual consultant, or any new provider implementation
Assumptions
- the repo remains pre-production, so destructive in-place replacement is acceptable and compatibility shims are not
- the temporary
/admin/t/{environment}path retention is the only allowed path exception for this slice - broader workspace-first IA, provider extraction, artifact retargeting, and RBAC scoping remain explicitly deferred to Specs
280-287 - current workspace membership and capability semantics stay materially unchanged in this slice; only the managed-target noun and foreign-key anchors move
Risks
- the implementation could accidentally combine the core cutover with the public route/IA rewrite, which would make review and rollback reasoning too broad
- lingering
Tenantreferences in commands, tests, or helper traits could hide cutover drift and produce mixed context behavior - provider-specific identity could accidentally land on
ManagedEnvironmentif currentTenantfields are copied forward without discipline - the temporary
/admin/texception could become permanent if Spec280is not treated as mandatory follow-up
Candidate Selection Gate Summary
- Selected candidate:
279 - Workspace-first Managed Environment Core Cutover - Source locations:
docs/product/spec-candidates.mdunder theWorkspace-first / ManagedEnvironment Core Cutover candidate packdocs/product/roadmap.mdunder the planned cutover pack ordering
- Why selected now:
279is the first unspecced reserved slot in the cutover pack and is the prerequisite for the remaining reserved follow-ups - Why close alternatives were deferred:
280depends on the core entity and context replacement from279281depends on the new managed-target root before provider-profile extraction makes sense282depends onmanaged_environment_idbecoming the core anchor first283-287are later normalization and guardrail layers, not the initial breaking cutover
- Smallest viable implementation slice: core entity replacement, foreign-key retargeting, current-context replacement, and one bounded path exception only
- Documented deviation from raw candidate wording: this package defers the public workspace-first route-family rewrite and final
WorkspaceFilament-tenancy end state to Spec280. To keep the implementation bounded and the runtime operable,279allows the current/admin/t/{environment}shell to remain temporarily while rebinding it toManagedEnvironment.
Completed-Spec Guardrail Result
specs/276-support-access-governance/already exists and remains a separate prepared packagespecs/277-stored-reports-surface/already exists and remains a separate prepared packagespecs/278-cross-domain-indicator-audit/already exists and carries completed docs-only close-out historyspecs/247-plans-entitlements-billing-readiness/,specs/251-commercial-entitlements-billing-state/,specs/252-platform-localization-v1/,specs/262-lifecycle-governance-taxonomy/, andspecs/264-cross-tenant-promotion-execution/remain context only and are not rewritten by this package
Deferred Adjacent Candidates
280 - Filament Workspace Tenancy & Environment Routing Cutover281 - Provider Connection, Provider Scope & Microsoft Profile Extraction282 - Governance Artifact Retargeting to ManagedEnvironment283 - Provider Capability Registry v1284 - Provider-neutral Artifact Source Taxonomy v1285 - Workspace-first RBAC & Environment Access Scoping286 - UI Copy, IA & Localization Neutralization287 - Cutover Quality Gates & No-Legacy Enforcement
User Scenarios & Testing
User Story 1 - Resolve managed environments as the active target inside a workspace (Priority: P1)
As a platform operator, I want the active managed target to be a ManagedEnvironment inside my current workspace so the platform core stops depending on Tenant as its primary identity model.
Why this priority: every later cutover slice depends on the managed-target root being replaced first.
Independent Test: Seed a workspace plus one managed environment, resolve the record through route binding and current-context helpers, and confirm the core paths no longer require App\Models\Tenant.
Acceptance Scenarios:
- Given a workspace has a managed environment, When the current environment is resolved by route key, Then the app returns the
ManagedEnvironmentrecord and current workspace context instead of aTenantmodel. - Given a wrong-workspace or non-member actor, When they try to resolve the same managed environment, Then the app responds with
404and leaks no environment-bound data.
User Story 2 - Keep current environment-scoped surfaces operable through the cutover (Priority: P1)
As an operator using the current admin panel, I want the existing environment-scoped shell to keep working while the core noun changes so the cutover is reviewable without bundling the full route/IA rewrite.
Why this priority: the cutover is not implementation-ready unless the current panel still boots on the new core entity.
Independent Test: Select a workspace, enter a managed environment from the retargeted chooser, and open the current environment dashboard through the temporary /admin/t/{environment} shell.
Acceptance Scenarios:
- Given an operator selected a workspace, When they choose a managed environment, Then the current panel shell loads with that managed environment as the active bound model.
- Given the same environment-scoped shell, When a page or deep link resolves the active target, Then route builders, query helpers, and current-target chips use
ManagedEnvironmentconsistently.
User Story 3 - Remove active tenant-core drift from schema, policies, and tests (Priority: P2)
As a maintainer, I want core-owned schema, policies, factories, and guard tests to use ManagedEnvironment and managed_environment_id so later specs do not inherit mixed core nouns.
Why this priority: lingering tenant-core drift would make the follow-up cutover pack unstable and ambiguous.
Independent Test: Run the managed-environment unit/feature suite and the legacy-core guard checks, then confirm no active App\Models\Tenant or ->tenant(Tenant::class) binding remains in core-owned paths.
Acceptance Scenarios:
- Given the cutover implementation is complete, When factories, policies, and tests create the managed target, Then they use
ManagedEnvironmentand managed-environment memberships rather thanTenant. - Given the final core-owned paths are searched or guard-tested, When forbidden legacy core patterns are checked, Then no active
Tenantcore model or Filament tenant binding remains.
Edge Cases
- The current public
/admin/t/{environment}path may remain temporarily, but it must bindManagedEnvironmentand must not coexist with a second compatibility route family. - Microsoft-specific external terms such as
Microsoft Entra Tenant IDmay remain only in provider-owned metadata or provider profiles, not onManagedEnvironment. - Archived or inactive managed environments must not become selectable current context by default.
- Old tenant-specific factories, seeders, and fixtures must be removed or replaced in the same cutover PR rather than kept for convenience.
Requirements (mandatory)
Constitution alignment (required): This feature changes core data ownership, route binding, context selection, and existing operator-facing shell behavior. It adds no Microsoft Graph calls and no new OperationRun family. Any security-relevant mutation that is not represented by OperationRun still uses existing audit behavior where applicable.
Constitution alignment (PROP-001 / ABSTR-001 / PERSIST-001 / STATE-001 / BLOAT-001): The feature introduces a new persisted root entity because the current product truth needs a provider-neutral managed-target core now. A narrower alias or adapter would preserve the wrong truth and would violate the repo’s pre-production lean doctrine.
Constitution alignment (XCUT-001): Current context-selection, route-building, query-scoping, and shell-context seams must be replaced in place. No second local environment-context language is allowed.
Constitution alignment (PROV-001): ManagedEnvironment must remain provider-neutral. Provider-specific identity stays in provider-owned seams and follow-up Spec 281.
Constitution alignment (SCOPE-001 exception/update prerequisite): The current constitution still requires tenant-owned tables to use workspace_id plus tenant_id as NOT NULL. This package intentionally replaces active core-owned managed-target keys with managed_environment_id. Implementation is gated by the explicit exception record in specs/279-workspace-managed-environment-core/checklists/constitution-scope-001-exception.md until the constitution itself is amended.
Functional Requirements
- FR-001: The package MUST introduce
ManagedEnvironmentas the active managed-target root record inside a workspace. - FR-002: The package MUST remove active core dependence on
App\Models\Tenantand retarget core-owned foreign keys fromtenant_idtomanaged_environment_id. - FR-003:
ManagedEnvironmentMUST NOT contain Microsoft-specific identity, Graph, or Intune fields. - FR-004: Current workspace-plus-target context resolution MUST bind
ManagedEnvironmentinstead ofTenant. - FR-005: Current environment membership and capability checks MUST continue to enforce
404for non-members and403for in-scope capability denials. - FR-006: The current environment-scoped panel shell may retain the
/admin/t/{environment}path temporarily, but it MUST bindManagedEnvironmentand MUST remain the only documented path exception in this slice. - FR-007: Current tenant-scoped query helpers, global-search scoping, route builders, and current-target UI seams MUST resolve
ManagedEnvironmentconsistently. - FR-008: Tests, factories, policies, and seeders in core-owned paths MUST use
ManagedEnvironmentnaming and IDs after the cutover. - FR-009: The package MUST not introduce dual columns, alias models, dual-write logic, or compatibility routes.
- FR-010: The package MUST explicitly defer the remaining workspace-first route-family rewrite, provider extraction, artifact retargeting, RBAC scope redesign, copy neutralization, and long-lived cutover quality gates to Specs
280-287.
Authorization and Safety Requirements
- AR-001: Workspace membership remains the first access boundary and must still deny non-members as
404. - AR-002: Managed-environment membership remains the second access boundary and must still deny wrong-environment access as
404. - AR-003: No new destructive action semantics are introduced. Any touched existing destructive actions must preserve
->requiresConfirmation()and current authorization checks.
Non-Functional Requirements
- NFR-001: Filament remains v5 on Livewire v4.
- NFR-002: Provider registration stays in
apps/platform/bootstrap/providers.php; no new panel provider registration location is introduced. - NFR-003: Any existing globally searchable resource touched by the cutover must continue to satisfy Filament’s edit/view-page requirement or remain out of global search.
- NFR-004: No new asset registration or
filament:assetsdeployment change is introduced in this slice. - NFR-005: The cutover must remain reviewable as one bounded implementation loop and must not silently absorb the broader Spec
280-287work.