--- description: "Task list for feature implementation" --- # Tasks: Unified Operations Runs Suitewide (054) **Input**: Design documents from `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/054-unify-runs-suitewide/` **Prerequisites**: `specs/054-unify-runs-suitewide/plan.md`, `specs/054-unify-runs-suitewide/spec.md`, `specs/054-unify-runs-suitewide/data-model.md`, `specs/054-unify-runs-suitewide/research.md`, `specs/054-unify-runs-suitewide/quickstart.md`, `specs/054-unify-runs-suitewide/contracts/` **Tests**: Required (Pest) for runtime behavior changes. **Operations**: Long-running/queued/remote/scheduled actions MUST create/reuse a canonical `OperationRun` and link to Monitoring → Operations. Monitoring pages MUST be DB-only at render time (no remote calls). ## Format: `[ID] [P?] [Story?] Description` - **[P]**: Can run in parallel (different files, no blocking dependencies) - **[Story]**: User story label (e.g., `[US1]`, `[US2]`, `[US3]`) — REQUIRED for story phases only - Each task includes at least one concrete file path ## Path Conventions (Laravel Monolith) - Source: `app/`, `routes/`, `resources/`, `config/`, `database/` - Tests: `tests/Feature/`, `tests/Unit/` --- ## Phase 1: Setup (Spec + Contract Alignment) **Purpose**: Resolve ambiguity before implementation starts - [x] T001 Validate Phase 1 run type set is consistent (adoption set + FR-003 + identity rules) in `specs/054-unify-runs-suitewide/spec.md` - [x] T002 Validate Monitoring Operations routes match Filament surface + OpenAPI contract in `specs/054-unify-runs-suitewide/contracts/routes.md` and `specs/054-unify-runs-suitewide/contracts/admin-pages.openapi.yaml` - [x] T003 Validate `OperationRunService` contract + quickstart usage examples align with intended API in `specs/054-unify-runs-suitewide/contracts/service_interface.md` and `specs/054-unify-runs-suitewide/quickstart.md` - [x] T004 Confirm FR-019 (Audit-only) is out-of-scope for 054 unless an audit-only action is touched; if touched, add AuditLog implementation + tests per `specs/054-unify-runs-suitewide/spec.md` in `specs/054-unify-runs-suitewide/tasks.md` --- ## Phase 2: Foundational (Canonical Run Primitive) **Purpose**: Core infrastructure that MUST be complete before ANY user story can be implemented - [x] T005 Create `operation_runs` migration (columns + indexes + partial unique index) in `database/migrations/*_create_operation_runs_table.php` - [x] T006 Create `OperationRun` Eloquent model (casts + relationships + helpers) in `app/Models/OperationRun.php` - [x] T007 [P] Add `OperationRunStatus` enum in `app/Support/OperationRunStatus.php` - [x] T008 [P] Add `OperationRunOutcome` enum (stored tokens vs UI labels; `cancelled` reserved) in `app/Support/OperationRunOutcome.php` - [x] T009 [P] Add `OperationRunType` enum (Phase 1 run types) in `app/Support/OperationRunType.php` - [x] T010 [P] Add `OperationRunFactory` for tests in `database/factories/OperationRunFactory.php` - [x] T011 Implement idempotent create/reuse + lifecycle updates + failure sanitization in `app/Services/OperationRunService.php` (depends on T005–T010) - [x] T012 Centralize “View run” + deep links in `app/Support/OperationRunLinks.php` (depends on T011) - [x] T013 [P] Implement tenant-scoped authorization policy in `app/Policies/OperationRunPolicy.php` - [x] T014 Register `OperationRun` policy with Gate in `app/Providers/AppServiceProvider.php` - [x] T015 Implement job middleware lifecycle tracking in `app/Jobs/Middleware/TrackOperationRun.php` (depends on T011) - [x] T016 Implement 90-day retention pruning job in `app/Jobs/PruneOldOperationRunsJob.php` - [x] T017 Schedule pruning job daily with non-overlapping lock (`withoutOverlapping` or equivalent cache lock) in `routes/console.php` - [x] T018 Add scheduled pruning non-overlap regression test (if feasible) in `tests/Feature/Scheduling/PruneOldOperationRunsScheduleTest.php` - [x] T019 Add `OperationRunService` tests (hash stability, idempotency, unique-index race, sanitization) in `tests/Feature/OperationRunServiceTest.php` - [x] T020 Add `TrackOperationRun` middleware lifecycle tests in `tests/Feature/TrackOperationRunMiddlewareTest.php` --- ## Phase 3: User Story 1 - See Every Supported Operation in Monitoring (Priority: P1) **Goal**: Monitoring → Operations shows all canonical runs (tenant-scoped) with list + detail, filters, and safe failures. **Independent Test**: Trigger at least one run of each Phase 1 run producer, then verify list/detail in Monitoring render DB-only and are tenant-scoped per `specs/054-unify-runs-suitewide/spec.md`. ### Tests for User Story 1 - [x] T021 [US1] Add Monitoring list/detail authorization + tenant isolation tests in `tests/Feature/MonitoringOperationsTest.php` - [x] T022 [P] [US1] Add Monitoring DB-only render test (mock Graph client; assert never called) in `tests/Feature/MonitoringOperationsTest.php` - [x] T023 [P] [US1] Add restore adapter visibility tests (created/visible from `previewed` onward; `previewed` maps to `queued/pending`) in `tests/Feature/RestoreAdapterTest.php` ### Implementation for User Story 1 - [x] T024 [US1] Create Filament Monitoring resource (list + view-only) in `app/Filament/Resources/OperationRunResource.php` - [x] T025 [US1] Implement list columns + default sort + default last-30-days window in `app/Filament/Resources/OperationRunResource.php` - [x] T026 [US1] Implement list filters (type, state bucket, time range, initiator) in `app/Filament/Resources/OperationRunResource.php` - [x] T027 [US1] Implement run detail view (meta, summary_counts, failures, context, links) in `app/Filament/Resources/OperationRunResource/Pages/ViewOperationRun.php` - [x] T028 [US1] Implement related links for each Phase 1 run type in `app/Support/OperationRunLinks.php` - [x] T029 [US1] Implement RestoreRun → OperationRun adapter create/update (from `previewed` onward; `previewed` maps to `status=queued`, `outcome=pending`) in `app/Listeners/SyncRestoreRunToOperationRun.php` - [x] T030 [US1] Wire RestoreRun lifecycle events to adapter in `app/Observers/RestoreRunObserver.php` - [x] T031 [US1] Register RestoreRun observer in `app/Providers/AppServiceProvider.php` --- ## Phase 4: User Story 2 - Start Operations Without Blocking (Priority: P2) **Goal**: Start surfaces are enqueue-only, return immediate confirmation + “View run”, and jobs update canonical run lifecycle. **Independent Test**: Start each Phase 1 operation from its owning UI and confirm the request returns quickly, includes “View run”, and the run progresses queued → running → terminal outcome. ### Tests for User Story 2 - [x] T032 [P] [US2] Add Inventory “Sync now” start-surface tests in `tests/Feature/Inventory/InventorySyncStartSurfaceTest.php` - [x] T033 [P] [US2] Add Policies “Sync now” start-surface tests in `tests/Feature/PolicySyncStartSurfaceTest.php` - [x] T034 [P] [US2] Add Directory Groups “Sync groups” start-surface tests in `tests/Feature/DirectoryGroups/StartSyncFromGroupsPageTest.php` - [x] T035 [P] [US2] Add Drift “Generate drift” start-surface tests in `tests/Feature/Drift/DriftGenerationDispatchTest.php` - [x] T036 [P] [US2] Add Backup Set “Add policies” start-surface tests in `tests/Feature/BackupSets/AddPoliciesStartSurfaceTest.php` - [x] T037 [P] [US2] Add Backup Schedule “Run now/Retry” start-surface tests in `tests/Feature/BackupScheduling/RunNowRetryActionsTest.php` - [x] T067 [P] [US2] Add Backup Set “Remove policies” (row + bulk) start-surface tests in `tests/Feature/BackupSets/RemovePoliciesStartSurfaceTest.php` and `tests/Feature/Filament/BackupItemsBulkRemoveTest.php` - [x] T038 [P] [US2] Add “queued + terminal” notification tests (initiator only; safe content) in `tests/Feature/Notifications/OperationRunNotificationTest.php` ### Implementation for User Story 2 - [x] T039 [P] [US2] Refactor Inventory “Sync now” to ensure run + dispatch + “View run” in `app/Filament/Pages/InventoryLanding.php` - [x] T040 [P] [US2] Refactor Policies “Sync now” to ensure run + dispatch + “View run” in `app/Filament/Resources/PolicyResource/Pages/ListPolicies.php` - [x] T041 [P] [US2] Refactor Directory Groups “Sync groups” to ensure run + dispatch + “View run” in `app/Filament/Resources/EntraGroupResource/Pages/ListEntraGroups.php` - [x] T042 [P] [US2] Refactor Drift “Generate drift” (manual + auto-on-open) to ensure run + dispatch + “View run” in `app/Filament/Pages/DriftLanding.php` - [x] T043 [P] [US2] Refactor Backup Set “Add policies” Livewire action to ensure run + dispatch + “View run” in `app/Livewire/BackupSetPolicyPickerTable.php` - [x] T044 [P] [US2] Refactor Backup Schedule “Run now/Retry” actions to ensure run + dispatch + “View run” in `app/Filament/Resources/BackupScheduleResource.php` - [x] T068 [P] [US2] Refactor Backup Set “Remove policies” actions (row + bulk) to ensure run + dispatch + “View run” in `app/Filament/Resources/BackupSetResource/RelationManagers/BackupItemsRelationManager.php` and `app/Jobs/RemovePoliciesFromBackupSetJob.php` - [x] T045 [P] [US2] Instrument inventory sync job run lifecycle + summary/failures in `app/Jobs/RunInventorySyncJob.php` - [x] T046 [P] [US2] Instrument policy sync job run lifecycle + summary/failures in `app/Jobs/SyncPoliciesJob.php` - [x] T047 [P] [US2] Instrument groups sync job run lifecycle + summary/failures in `app/Jobs/EntraGroupSyncJob.php` - [x] T048 [P] [US2] Instrument drift generation job run lifecycle + summary/failures in `app/Jobs/GenerateDriftFindingsJob.php` - [x] T049 [P] [US2] Instrument backup set “add policies” job run lifecycle + summary/failures in `app/Jobs/AddPoliciesToBackupSetJob.php` - [x] T050 [P] [US2] Instrument backup schedule job run lifecycle + summary/failures in `app/Jobs/RunBackupScheduleJob.php` - [x] T051 [US2] Implement queued notification (after successful dispatch) in `app/Notifications/OperationRunQueued.php` - [x] T052 [US2] Implement terminal outcome notification (succeeded/partial/failed) in `app/Notifications/OperationRunCompleted.php` - [x] T053 [US2] Emit notifications from canonical lifecycle updates (initiator only) in `app/Services/OperationRunService.php` - [x] T054 [US2] Handle queue dispatch failures (fail fast; no misleading queued runs) in `app/Services/OperationRunService.php` --- ## Phase 5: User Story 3 - Duplicate Starts Reuse the Same Active Run (Priority: P3) **Goal**: Duplicate starts reuse the same active run (dedupe), enforced at DB level and validated by tests. **Independent Test**: Start the same operation twice with identical effective inputs while the first is queued/running and verify the system reuses the active run. ### Tests for User Story 3 - [x] T055 [US3] Add service-level dedupe + race-collision tests in `tests/Feature/OperationRunServiceTest.php` - [x] T056 [US3] Add end-to-end “reuse active run” test for at least one producer in `tests/Feature/PolicySyncStartSurfaceTest.php` ### Implementation for User Story 3 - [x] T057 [US3] Normalize identity inputs before hashing (stable JSON; ignore initiator) in `app/Services/OperationRunService.php` - [x] T058 [P] [US3] Ensure `inventory.sync` identity inputs follow FR-010 in `app/Filament/Pages/InventoryLanding.php` - [x] T059 [P] [US3] Ensure `policy.sync` identity inputs follow FR-010 in `app/Filament/Resources/PolicyResource/Pages/ListPolicies.php` - [x] T060 [P] [US3] Ensure `directory_groups.sync` identity inputs follow FR-010 in `app/Filament/Resources/EntraGroupResource/Pages/ListEntraGroups.php` - [x] T061 [P] [US3] Ensure `drift.generate` identity inputs follow FR-010 in `app/Filament/Pages/DriftLanding.php` - [x] T062 [P] [US3] Ensure `backup_set.add_policies` identity inputs follow FR-010 in `app/Livewire/BackupSetPolicyPickerTable.php` - [x] T063 [P] [US3] Ensure `backup_schedule.run_now`/`backup_schedule.retry` identity inputs follow FR-010 in `app/Filament/Resources/BackupScheduleResource.php` --- ## Phase 6: Polish & Cross-Cutting Concerns - [x] T064 [P] Run formatter on changed files via `./vendor/bin/pint --dirty` - [x] T065 Run targeted tests for this feature via `./vendor/bin/sail artisan test tests/Feature/MonitoringOperationsTest.php` - [x] T066 Run quickstart scenarios and update docs if needed in `specs/054-unify-runs-suitewide/quickstart.md` --- ## Dependencies & Execution Order ### Phase Dependencies - Setup (Phase 1) → blocks Foundational - Foundational (Phase 2) → blocks US1/US2/US3 - US1/US2/US3 can proceed after Phase 2 (parallel if staffed, or sequential P1 → P2 → P3) - Polish (Phase 6) depends on the desired user stories being complete ### User Story Dependencies (Graph) ```text Foundational ├─ US1 (Monitoring UI) ├─ US2 (Start surfaces + lifecycle + notifications) └─ US3 (Dedupe + identity + race handling) ``` --- ## Parallel Execution Examples After Phase 2, these can run in parallel (different files/modules): ### US1 (Monitoring UI) - `T023` (restore adapter tests) + `T024` (resource scaffold) + `T029` (restore adapter listener) ### US2 (Start surfaces + lifecycle + notifications) - Tests: `T032`–`T038` - Producers/start surfaces: `T039`–`T044` - Workers/job instrumentation: `T045`–`T050` - Notification classes: `T051` + `T052` ### US3 (Dedupe + identity + race handling) - Identity review per producer: `T058`–`T063` --- ## Implementation Strategy ### MVP First (US1 Only) 1. Complete Phase 1–2 (canonical run primitive) 2. Complete US1 (Monitoring list/detail + tenant isolation) 3. Validate Monitoring renders DB-only and is tenant-scoped ### Incremental Delivery 1. Add US2 producers/workers + notifications 2. Add US3 dedupe + race validation 3. Polish (formatting, targeted tests, quickstart validation)