TenantAtlas/specs/280-workspace-tenancy-environment-routing/research.md
ahmido 670c46dedd Spec 280: prepare workspace tenancy and environment routing cutover (#336)
## 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
2026-05-07 10:20:43 +00:00

9.3 KiB

Research: Filament Workspace Tenancy & Environment Routing Cutover

Date: 2026-05-07
Branch: 280-workspace-tenancy-environment-routing

Decision 1: Collapse public operator routing into the existing admin panel

  • Decision: AdminPanelProvider remains the only operator-facing Filament panel, and Workspace becomes the only Filament tenant for operator admin routing. TenantPanelProvider stops owning public operator routes.
  • Rationale: verified repo seams show AdminPanelProvider already owns /admin, ChooseWorkspace, ChooseTenant, WorkspaceOverview, and the current workspace-scoped operations hub, while TenantPanelProvider exists only to keep the temporary /admin/t shell alive. Filament v5 panel configuration on Laravel 12 still expects provider registration in apps/platform/bootstrap/providers.php, so the narrowest truthful cutover is to remove the second operator panel rather than preserve it as a redirect shell.
  • Alternatives considered:
    • Keep TenantPanelProvider as a redirect-only shell: rejected because it preserves the same split public truth and adds compatibility behavior the spec forbids.
    • Introduce nested environment Filament tenancy: rejected because ManagedEnvironment should remain nested route context, not a second panel tenancy.

Decision 2: Make the workspace-scoped environment chooser the canonical public environment entry surface

  • Decision: the canonical environment chooser route lives at /admin/workspaces/{workspace}/environments, reusing the current workspace-bound ManagedTenantsLanding surface. ChooseTenant remains an implementation seam to absorb or delegate selection logic, but it should not survive as a second canonical public chooser route, and /admin/w/{workspace}/managed-tenants is retired with no redirect or alias.
  • Rationale: ManagedTenantsLanding already binds a Workspace route parameter and lists accessible ManagedEnvironment records for that workspace. ChooseTenant currently mixes workspace recovery, selection, and redirection into the temporary tenant panel. Keeping the workspace-scoped landing as the public chooser keeps the route language aligned with the new workspace-first contract.
  • Alternatives considered:
    • Keep both ChooseTenant and ManagedTenantsLanding public: rejected because it preserves two chooser URLs for the same operator decision.
    • Continue auto-branching from workspace selection directly into one environment dashboard: rejected because the spec treats the workspace dashboard and environment chooser as explicit decision surfaces, not hidden branching behavior.

Decision 3: Keep /admin tied to workspace selection or the workspace dashboard

  • Decision: direct /admin requests resolve only to workspace selection or the canonical workspace dashboard. Environment entry becomes explicit through the workspace dashboard and environment chooser instead of using /admin as a hidden second environment dashboard route.
  • Rationale: the spec requires /admin to remain the operator entrypoint only, not a second canonical environment route. This keeps the workspace dashboard as the primary decision surface and removes the need to infer operator scope from a remembered environment.
  • Alternatives considered:
    • Keep /admin auto-redirecting into one environment when possible: rejected because it weakens the workspace-first shell and makes route truth dependent on remembered tenant context.
    • Leave /admin ambiguous between workspace and environment dashboards: rejected because it preserves the current split truth.

Decision 4: Reuse the existing workspace and environment dashboards under new route ownership

  • Decision: WorkspaceOverview plus WorkspaceOverviewBuilder remain the workspace dashboard, and TenantDashboard plus TenantDashboardSummaryBuilder remain the managed-environment dashboard. The slice changes route ownership, breadcrumbs, context-bar signals, and deep links only.
  • Rationale: current repo truth already has the signal builders and widget families needed for this slice. The missing piece is not new dashboard content, but the temporary panel and route shell around it.
  • Alternatives considered:
    • Build new dashboard pages for workspace-first routing: rejected because it would duplicate existing signal ownership and absorb UI work the spec explicitly defers.
    • Refactor builder ownership now: rejected because provider extraction and copy neutralization are deferred to later specs.

Decision 5: Move operations into a workspace-first route family through shared navigation builders

  • Decision: /admin/workspaces/{workspace}/operations and /admin/workspaces/{workspace}/operations/{run} become the canonical operations routes, and OperationRunLinks, RelatedNavigationResolver, and Monitoring\Operations remain the only shared seams for retargeting collection/detail URLs, environment filters, and back-navigation context. The legacy /admin/operations family is retired with no redirect or alias.
  • Rationale: Monitoring\Operations already models managed_environment_id, tenant_scope, problemClass, activeTab, and navigation context as workspace-scoped state. The current defect is the public route family and back-link language, not the monitoring page itself.
  • Alternatives considered:
    • Keep /admin/operations as the canonical route: rejected because the spec explicitly requires the workspace-first operations family.
    • Add environment-local operations pages: rejected because the operations hub is already the canonical shared monitoring surface.

Decision 6: Update middleware, route categorization, and panel-context resolution together

  • Decision: EnsureWorkspaceSelected, EnsureFilamentTenantSelected, TenantPageCategory, ResolvesPanelTenantContext, and WorkspaceRedirectResolver must move to the workspace-first environment family in the same implementation slice.
  • Rationale: those seams currently special-case /admin/t, /admin/tenants/{environment}, workspace-canonical /admin/operations, and current panel ID. Partial updates would leave stale remembered environment context, wrong 404/403 handling, or mixed breadcrumb language.
  • Alternatives considered:
    • Route redirects only: rejected because redirects would preserve the old route language and leave classifier logic stale.
    • Query-parameter-only environment context: rejected because the spec requires canonical workspace-first environment routes, not implicit query-driven context.

Decision 7: Keep global search truthful only where destinations remain valid

  • Decision: the touched search-eligible surfaces are WorkspaceResource and TenantResource. Each remains globally searchable only if it still has a valid view or edit destination under the workspace-first route contract; otherwise search is disabled in the same slice.
  • Rationale: Filament v5 global search requires a resource to have a view or edit page in order to produce valid results. Current repo truth shows most other touched resources are already isGloballySearchable = false, so the search review surface is small and explicit.
  • Alternatives considered:
    • Leave current global search behavior unchanged and fix later: rejected because it can leave broken results or inaccurate hints immediately after the route cutover.

Decision 8: Prove the cutover with focused feature coverage, one browser smoke, and grep/guard checks

  • Decision: use focused feature tests for routing and authorization, one browser smoke for the workspace-to-environment-to-operations path, and explicit grep/guard checks for /admin/t and panel: 'tenant' regressions.
  • Rationale: Filament documentation emphasizes testing authorization and Livewire page behavior end to end, and the riskiest regression here is the live entry flow across chooser, dashboard, and operations surfaces. One narrow browser smoke is enough; broader browser or governance suites would be disproportionate.
  • Alternatives considered:
    • Feature tests only: rejected because they would not prove the live chooser-to-dashboard flow on the surviving panel.
    • Broad browser suite: rejected because it would create a new heavy cost center for a routing cutover slice.

Final Research Outcome

  • The final operator runtime should have one public panel and one public route language rooted in workspace scope.
  • The workspace-scoped environment chooser should become the public environment entry surface, with ChooseTenant absorbed into the same flow rather than preserved as a second public chooser URL.
  • The legacy chooser route /admin/w/{workspace}/managed-tenants and the legacy operations family /admin/operations must not survive as redirects, aliases, or hidden fallback readers.
  • The workspace dashboard and managed-environment dashboard should be reused as-is under new route ownership.
  • Operations routing should move through the shared builders and preserve explicit environment scope via managed_environment_id and back-link context.
  • Middleware, page categorization, and panel-context resolution must change together so deny-as-not-found and remembered-context semantics stay correct.
  • Global search must remain truthful for WorkspaceResource and TenantResource or be disabled in the same slice.
  • The narrowest honest proof is feature coverage, one browser smoke, and grep/guard checks.