# Tasks: Unified Operations Runs Suitewide **Feature**: `054-unify-runs-suitewide` **Spec**: `specs/054-unify-runs-suitewide/spec.md` ## Phase 1: Foundation (DB & Service) - [ ] **Migration**: Create `operation_runs` table with partial unique index on `(tenant_id, run_identity_hash)` where status in `queued, running`. - [ ] **Model**: Create `OperationRun` model with casts (JSONB for summaries/context), relationship to `Tenant` and `User`. - [ ] **Service**: Implement `OperationRunService::ensureRun()` (idempotent creation) and `updateRun()` methods. - [ ] **Test**: Feature test for `ensureRun` verifying idempotency (same hash = same run) and concurrency safety (simulated). - [ ] **Test**: Feature test for `updateRun` verifying status transitions and history logging (if any). - [ ] **Job Middleware**: Create `TrackOperationRun` middleware to automatically handle job success/failure updates for jobs using this system. - [ ] **Retention**: Create a daily scheduled job to prune `operation_runs` older than 90 days. ## Phase 2: Monitoring UI (Read-Only) - [ ] **Page**: Create Filament Page `Monitoring/Operations` (List) strictly scoped to current tenant. - [ ] **Table**: Implement `OperationRun` table with columns: Status (Badge), Operation Type, Initiator, Started At, Duration, Outcome. - [ ] **Filters**: Add table filters for `Type`, `Outcome`, `Date Range`, `Initiator`. - [ ] **Detail View**: Create "View Run" modal or separate page showing: - Summary counts (Success/Fail/Total) - Failure list (Sanitized codes/messages) - Context JSON (Debug info) - Timeline (Created/Started/Finished) - [ ] **Test**: Livewire test verifying `Readonly` users can see table but no actions. - [ ] **Test**: Verify cross-tenant access is blocked. ## Phase 3: Producer Migration (Parallel Write) ### Inventory Sync (`inventory.sync`) - [ ] **Refactor**: Update `RunInventorySyncJob` dispatch logic to call `OperationRunService::ensureRun()` first. - [ ] **Refactor**: Update Job to use `TrackOperationRun` middleware (or manual updates) to sync status to `operation_runs`. - [ ] **Verify**: Ensure legacy `inventory_sync_runs` is still written to (if legacy UI depends on it) OR confirm legacy UI is replaced. *Decision: Parallel write as per spec.* ### Policy Sync (`policy.sync`) - [ ] **Refactor**: Update Policy Sync start logic to use `OperationRunService`. - [ ] **Refactor**: Instrument Policy Sync job to update `operation_runs`. ### Directory Groups Sync (`directory_groups.sync`) - [ ] **Refactor**: Update Group Sync start logic to use `OperationRunService`. - [ ] **Refactor**: Instrument Group Sync job to update `operation_runs`. ### Drift Generation (`drift.generate`) - [ ] **Refactor**: Update Drift Generation start logic to use `OperationRunService`. - [ ] **Refactor**: Instrument Drift job to update `operation_runs`. ### Backup Set (`backup_set.add_policies`) - [ ] **Refactor**: Update "Add Policies" action to use `OperationRunService`. ## Phase 4: Restore Adapter - [ ] **Listener**: Create `SyncRestoreRunToOperation` listener observing `RestoreRun` events (`created`, `updated`). - [ ] **Logic**: Map `RestoreRun` status/outcomes to `OperationRun` schema. - `RestoreRun` created -> `OperationRun` created (queued/running). - `RestoreRun` updated -> `OperationRun` updated. - [ ] **Context**: Store `{"restore_run_id": }` in `OperationRun.context`. - [ ] **Test**: Verify creating a `RestoreRun` automatically spawns a shadow `OperationRun`. ## Phase 5: Notifications & Polish - [ ] **Notifications**: Implement Database Notifications for "Run Started" (with link) and "Run Completed" (with outcome). - [ ] **Frontend**: Ensure "View Run" link in Toast notifications correctly opens the Monitoring Detail view. - [ ] **Final Verify**: Run through the `requirements.md` checklist manually.