TenantAtlas/specs/292-workspace-tenant-closure/tasks.md
Ahmed Darrazi adf9237152
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 1m32s
feat: implement workspace and tenant closure lifecycle
2026-05-07 15:08:20 +02:00

16 KiB

description
Task list for Workspace & Tenant Closure Lifecycle v1

Tasks: Workspace & Tenant Closure Lifecycle v1

Input: Design documents from specs/292-workspace-tenant-closure/
Prerequisites: specs/292-workspace-tenant-closure/spec.md, specs/292-workspace-tenant-closure/plan.md

Tests: REQUIRED (Pest). Keep proof bounded to focused Feature coverage for system directory, admin workspace and tenant surfaces, chooser recovery, and canonical historical viewers. Operations: Reuse the existing OperationRun start UX and canonical run viewers. No new run type, no queue family, and no local blocked-run substitute are allowed. RBAC: Wrong-plane or non-member access remains 404; in-scope actors missing capability remain 403. Closure/removal posture is never an authorization shortcut. Shared Pattern Reuse: Reuse WorkspaceContext, TenantOperabilityService, WorkspaceCommercialLifecycleResolver, BadgeCatalog / BadgeRenderer, current audit infrastructure, and current Filament action-surface patterns. Filament / Panel Guardrails: Filament remains v5 on Livewire v4. Provider registration remains unchanged in apps/platform/bootstrap/providers.php. No new panel, no new globally searchable resource, and no new asset strategy are allowed. Organization: Tasks are grouped by user story so workspace closure, tenant removal, and posture clarity remain independently implementable and testable.

Test Governance Checklist

  • Lane assignment stays fast-feedback and confidence and remains the narrowest sufficient proof.
  • New or changed tests stay in focused Feature families only unless a bounded implementation seam proves a unit test is necessary.
  • Shared helpers, factories, seeds, fixtures, and context defaults stay cheap by default.
  • Planned validation commands cover closure, removal, chooser recovery, and historical viewer legitimacy without widening into browser or heavy-governance lanes.
  • The declared surface test profiles remain standard-native-filament, global-context-shell, and shared-detail-family only.
  • Any drift toward purge, export, billing workflow, or a second mutation plane resolves as reject-or-split, not hidden scope.

Phase 1: Setup (Shared Context)

Purpose: Confirm the current lifecycle, chooser, and history seams before any runtime change begins.

  • T001 Review specs/292-workspace-tenant-closure/spec.md, specs/292-workspace-tenant-closure/plan.md, specs/262-lifecycle-governance-taxonomy/spec.md, specs/143-tenant-lifecycle-operability-context-semantics/spec.md, and specs/274-billing-subscription-truth/spec.md together so the slice stays grounded in current lifecycle and commercial truth.
  • T002 [P] Confirm the current system and admin surface seams in apps/platform/app/Filament/System/Pages/Directory/ViewWorkspace.php, apps/platform/app/Filament/System/Pages/Directory/ViewTenant.php, apps/platform/app/Filament/System/Pages/Ops/ViewRun.php, apps/platform/app/Filament/Resources/Workspaces/Pages/ViewWorkspace.php, and apps/platform/app/Filament/Resources/TenantResource.php.
  • T003 [P] Confirm the chooser and context seams in apps/platform/app/Support/Workspaces/WorkspaceContext.php, apps/platform/app/Http/Middleware/EnsureWorkspaceSelected.php, apps/platform/app/Support/Middleware/EnsureFilamentTenantSelected.php, apps/platform/app/Filament/Pages/ChooseWorkspace.php, and apps/platform/app/Filament/Pages/ChooseTenant.php.
  • T004 [P] Confirm the current lifecycle and audit seams in apps/platform/app/Services/Tenants/TenantOperabilityService.php, apps/platform/app/Services/Entitlements/WorkspaceCommercialLifecycleResolver.php, apps/platform/app/Services/Audit/WorkspaceAuditLogger.php, and the current tenant audit logging path.

Phase 2: Foundational (Blocking Prerequisites)

Purpose: Add the bounded lifecycle truth and write-side seam before surface behavior changes.

Critical: No user-story work should begin until this phase is complete.

  • T005 [P] Add failing feature coverage in apps/platform/tests/Feature/System/Directory/ViewWorkspaceClosureTest.php and apps/platform/tests/Feature/System/Ops/ClosedWorkspaceHistoricalAccessTest.php to lock close/reopen behavior, historical readability, and pre-enqueue blocking.
  • T006 [P] Add failing feature coverage in apps/platform/tests/Feature/Filament/Resources/Workspaces/WorkspaceClosureStatusTest.php and apps/platform/tests/Feature/Filament/Pages/WorkspaceContextClosureRecoveryTest.php to lock admin read-only posture, chooser recovery, and cleared-context behavior.
  • T007 [P] Add failing feature coverage in apps/platform/tests/Feature/Filament/Resources/TenantResource/TenantWorkspaceRemovalTest.php to lock remove/restore behavior, chooser exclusion, and tenant-context denial rules.
  • T008 Create apps/platform/database/migrations/*_add_workspace_closure_fields.php and apps/platform/database/migrations/*_add_managed_environment_workspace_removal_fields.php so existing records can store explicit closure and removal truth.
  • T009 Update apps/platform/app/Models/Workspace.php and apps/platform/app/Models/ManagedEnvironment.php with casts, bounded helper methods, and relationship accessors for the new lifecycle truth.
  • T010 Implement apps/platform/app/Services/Workspaces/WorkspaceLifecycleService.php as the one bounded orchestration seam for close/reopen and remove/restore plus audit-safe state transitions, and keep membership rows preserved rather than recreated or deleted.
  • T011 Extend apps/platform/app/Services/Audit/WorkspaceAuditLogger.php and the current tenant audit logging path with stable action IDs and metadata for close/reopen and remove/restore.
  • T012 Update the relevant policy and capability seams so close/reopen and remove/restore enforce server-side authorization with the required 404 versus 403 behavior.

Checkpoint: Workspace and tenant lifecycle truth exists, audit is wired, and write-side behavior is centralized before UI or chooser changes land.


Phase 3: User Story 1 - Close a workspace without losing history (Priority: P1)

Goal: Authorized platform users can close and reopen workspaces explicitly while preserving readable history.

Independent Test: Close a workspace from the system detail page, confirm chooser and action gating update, verify historical viewers remain readable, and reopen the workspace.

Tests for User Story 1

  • T013 [P] [US1] Extend apps/platform/tests/Feature/System/Directory/ViewWorkspaceClosureTest.php to prove confirmation, impact summary, reason capture, clear guard-failure reasons on unsafe close attempts, canonical success or error notification copy, audit metadata, membership preservation, reopen behavior, and blocked mutation or start behavior.
  • T014 [P] [US1] Extend apps/platform/tests/Feature/Filament/Resources/Workspaces/WorkspaceClosureStatusTest.php to prove admin read-only posture, distinct closed versus suspended copy, and the absence of a second workspace-closure mutation plane.

Implementation for User Story 1

  • T015 [US1] Update apps/platform/app/Filament/System/Pages/Directory/ViewWorkspace.php and apps/platform/app/Filament/System/Pages/Ops/ViewRun.php so the system surfaces render closure posture, impact summary, and keep closed-workspace history readable with canonical success or error notification copy and clear guard-failure messaging on unsafe attempts.
  • T016 [US1] Update apps/platform/app/Support/Workspaces/WorkspaceContext.php, apps/platform/app/Http/Middleware/EnsureWorkspaceSelected.php, apps/platform/app/Filament/Pages/ChooseWorkspace.php, and apps/platform/app/Filament/Widgets/Tenant/TenantReviewPackCard.php so closed workspaces clear invalid remembered context, route through explicit recovery messaging, and block the in-scope tenant start surface before enqueue.
  • T017 [US1] Update apps/platform/app/Filament/Resources/Workspaces/Pages/ViewWorkspace.php and apps/platform/app/Filament/Pages/Settings/WorkspaceSettings.php so the admin plane shows read-only closure posture, defers in-scope blocked-state checks to apps/platform/app/Services/Workspaces/WorkspaceLifecycleService.php, and does not expose closure mutation controls.

Checkpoint: Workspace closure becomes an explicit, auditable, read-only posture with preserved historical access.


Phase 4: User Story 2 - Remove a tenant from a workspace without deleting tenant history (Priority: P1)

Goal: Workspace owners can remove and restore tenants from the active workspace set without losing historical legitimacy.

Independent Test: Remove a tenant from the tenant-management surface, confirm chooser and tenant-context routes treat it as non-operable, verify historical viewers still render, and restore the tenant.

Tests for User Story 2

  • T018 [P] [US2] Extend apps/platform/tests/Feature/Filament/Resources/TenantResource/TenantWorkspaceRemovalTest.php to prove confirmation, impact summary, reason capture, clear guard-failure reasons on unsafe remove attempts, canonical success or error notification copy, audit metadata, membership preservation, restore behavior, chooser exclusion, tenant-context denial, and representative removed-tenant blocked-start no-OperationRun behavior on apps/platform/app/Filament/Widgets/Tenant/TenantReviewPackCard.php.
  • T019 [P] [US2] Extend apps/platform/tests/Feature/System/Ops/ClosedWorkspaceHistoricalAccessTest.php to prove historical viewers remain readable when the referenced tenant is removed from the workspace.

Implementation for User Story 2

  • T020 [US2] Update apps/platform/app/Filament/Resources/TenantResource.php and the resource's view-page action surface so remove/restore actions, impact summaries, canonical success or error notification copy, posture badges, and grouped destructive actions follow the spec contract.
  • T021 [US2] Update apps/platform/app/Services/Tenants/TenantOperabilityService.php, apps/platform/app/Support/Middleware/EnsureFilamentTenantSelected.php, apps/platform/app/Support/Middleware/DenyNonMemberTenantAccess.php, apps/platform/app/Filament/Pages/ChooseTenant.php, tenant-memory handling in apps/platform/app/Support/Workspaces/WorkspaceContext.php, and apps/platform/app/Filament/Widgets/Tenant/TenantReviewPackCard.php so removed tenants are no longer valid active context and cannot enqueue new runs.
  • T022 [US2] Update apps/platform/app/Filament/System/Pages/Directory/ViewTenant.php and apps/platform/app/Filament/System/Pages/Ops/ViewRun.php so removed tenants remain historically visible with explicit posture and no false not-found behavior.

Checkpoint: Tenant removal becomes explicit, reversible, and historically safe without remaining an active workspace context.


Phase 5: User Story 3 - Distinguish suspended read-only, closed, and removed clearly (Priority: P2)

Goal: Operators can tell which lifecycle posture is blocking them and what next action remains legitimate.

Independent Test: Render admin, system, chooser, and historical surfaces for suspended-read-only, closed, and removed states and verify distinct copy and badges.

Tests for User Story 3

  • T023 [P] [US3] Extend apps/platform/tests/Feature/System/Directory/ViewWorkspaceClosureTest.php, apps/platform/tests/Feature/Filament/Resources/Workspaces/WorkspaceClosureStatusTest.php, and apps/platform/tests/Feature/Filament/Resources/TenantResource/TenantWorkspaceRemovalTest.php to prove distinct posture labels, centralized badge mapping, disclosure ordering, blocked-action explanations, and one dominant next action.

Implementation for User Story 3

  • T024 [US3] Update posture rendering on apps/platform/app/Filament/System/Pages/Directory/ViewWorkspace.php, apps/platform/app/Filament/Resources/Workspaces/Pages/ViewWorkspace.php, and apps/platform/app/Filament/Pages/Settings/WorkspaceSettings.php so Suspended read-only remains distinct from Closed and uses shared badge semantics rather than local mappings.
  • T025 [US3] Update posture rendering on apps/platform/app/Filament/Resources/TenantResource.php, apps/platform/app/Filament/System/Pages/Directory/ViewTenant.php, and chooser recovery messaging so Removed from workspace remains distinct from archive and provider-missing semantics, and keep decision content first with diagnostics secondary.

Checkpoint: Lifecycle posture becomes explicit and non-ambiguous across the affected operator and history surfaces.


Phase 6: Polish & Cross-Cutting Validation

Purpose: Validate the bounded slice and stop without widening scope.

  • T026 [P] Run export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/System/Directory/ViewWorkspaceClosureTest.php tests/Feature/System/Ops/ClosedWorkspaceHistoricalAccessTest.php.
  • T027 [P] Run export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Filament/Resources/Workspaces/WorkspaceClosureStatusTest.php tests/Feature/Filament/Resources/TenantResource/TenantWorkspaceRemovalTest.php tests/Feature/Filament/Pages/WorkspaceContextClosureRecoveryTest.php.
  • T028 [P] Run export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent.
  • T029 [P] Review touched code to confirm Filament stays on Livewire v4, provider registration remains unchanged in apps/platform/bootstrap/providers.php, no globally searchable resource or wider discovery path is added, no asset strategy changes appear, and no second closure-mutation plane slipped in.
  • T030 [P] Record the final guardrail and test-governance outcome in the implementation close-out without reopening purge, export, billing, or portal scope.

Dependencies & Execution Order

Phase Dependencies

  • Phase 1 (Setup): no dependencies; start immediately.
  • Phase 2 (Foundational): depends on Phase 1 and blocks all user stories.
  • Phase 3 (US1): depends on Phase 2 and establishes explicit workspace closure truth plus chooser recovery.
  • Phase 4 (US2): depends on Phase 2 and should land after or alongside US1 so tenant removal composes with the new workspace posture rules.
  • Phase 5 (US3): depends on Phases 3 and 4 because it clarifies the final shared posture language.
  • Phase 6 (Polish): depends on all desired user stories being complete.

User Story Dependencies

  • US1 (P1): independently testable after Phase 2 and delivers the central workspace-closure capability.
  • US2 (P1): independently testable after Phase 2 and delivers the central tenant-removal capability.
  • US3 (P2): depends on the completed runtime posture rules from US1 and US2.

Within Each User Story

  • Write the listed Pest coverage first and make it fail for the intended gap.
  • Keep implementation inside the existing model, service, middleware, Filament, and audit seams named above.
  • Re-run the narrowest relevant validation command after each story checkpoint before moving on.

Implementation Strategy

Suggested MVP Scope

  • MVP = US1 + US2 together. The feature is only trustworthy when workspace closure and tenant removal both exist and historical readability remains intact.

Incremental Delivery

  1. Complete Phase 1 and Phase 2.
  2. Deliver US1 so explicit workspace closure and chooser recovery exist.
  3. Deliver US2 so tenants can be removed or restored without losing history.
  4. Deliver US3 so posture language across the affected surfaces becomes unambiguous.
  5. Finish with the focused validation and drift-review tasks in Phase 6.

Team Strategy

  1. Settle persistence and bounded service shape first.
  2. Parallelize failing tests within each story before runtime edits.
  3. Serialize merges around WorkspaceContext, TenantOperabilityService, ViewWorkspace, and TenantResource so posture language stays coherent.

Deferred Follow-Ups / Non-Goals

  • export-before-delete workflow
  • retention and purge governance
  • customer self-serve workspace offboarding or billing-driven closure
  • provider-level lifecycle expansion beyond the current separate specs
  • lifecycle dashboard or workbench surfaces