--- description: "Executable task list for Spec 091 implementation" --- # Tasks: BackupSchedule Retention & Lifecycle (Archive/Restore/Force Delete) **Input**: Design documents from `/specs/091-backupschedule-retention-lifecycle/` **Prerequisites**: `plan.md` (required), `spec.md` (user stories), `research.md`, `data-model.md`, `contracts/`, `quickstart.md` **Tests**: REQUIRED (Pest) for runtime behavior changes. --- ## Phase 1: Setup (Shared Infrastructure) **Purpose**: Confirm baseline assumptions and align with repo conventions before changing runtime behavior. - [X] T001 Confirm SoftDeletes + lifecycle conventions in app/Filament/Resources/BackupSetResource.php - [X] T002 Confirm RBAC-UX helper usage patterns in app/Support/Rbac/UiEnforcement.php - [X] T003 Confirm BackupSchedule scheduling flow touchpoints in app/Services/BackupScheduling/BackupScheduleDispatcher.php and app/Jobs/RunBackupScheduleJob.php --- ## Phase 2: Foundational (Blocking Prerequisites) **Purpose**: Introduce the archived lifecycle state at the data/model layer. **⚠️ CRITICAL**: No user story work should begin until this phase is complete. - [X] T004 Add SoftDeletes to app/Models/BackupSchedule.php - [X] T005 Create migration to add deleted_at to backup_schedules in database/migrations/ (new migration file) - [X] T006 [P] Update BackupSchedule model query expectations/tests to account for soft-deleted records in tests/Feature/BackupScheduling/BackupScheduleCrudTest.php **Checkpoint**: `BackupSchedule` supports archived state (`deleted_at`). --- ## Phase 3: User Story 1 — Archive a schedule safely (Priority: P1) 🎯 MVP **Goal**: Tenant admins can archive schedules (soft delete) with confirmation; archived schedules are excluded from the default list and MUST never execute. **Independent Test**: Create an active schedule, archive it, verify it disappears from the default list, is visible under an “Archived” filter, audit entry exists, and scheduler/job do not dispatch/execute archived schedules. ### Tests (write first) - [X] T007 [P] [US1] Add archive lifecycle tests in tests/Feature/BackupScheduling/BackupScheduleLifecycleTest.php - [X] T008 [P] [US1] Add scheduler safety test (archived schedules not dispatched) in tests/Feature/BackupScheduling/DispatchIdempotencyTest.php - [X] T009 [P] [US1] Add job safety test (archived schedule skipped) in tests/Feature/BackupScheduling/RunBackupScheduleJobTest.php - [X] T009 [P] [US1] Add job safety test (archived schedule skipped) in tests/Feature/BackupScheduling/RunBackupScheduleJobTest.php (assert `OperationRun` is `completed` with outcome `blocked`, `summary_counts.skipped=1`, and `failure_summary` includes `code=schedule_archived`) ### Implementation - [X] T010 [US1] Add “Archived” filter to BackupSchedule table in app/Filament/Resources/BackupScheduleResource.php - [X] T011 [US1] Remove/disable bulk destructive actions for schedules in app/Filament/Resources/BackupScheduleResource.php - [X] T012 [US1] Replace hard-delete semantics with “Archive” action (soft delete) in app/Filament/Resources/BackupScheduleResource.php - [X] T013 [US1] Enforce RBAC-UX (non-member→404; member missing capability→403) for archive action using app/Support/Rbac/UiEnforcement.php in app/Filament/Resources/BackupScheduleResource.php - [X] T014 [US1] Emit audit event backup_schedule.archived via app/Services/Intune/AuditLogger.php from app/Filament/Resources/BackupScheduleResource.php - [X] T015 [US1] Ensure dispatcher excludes archived schedules in app/Services/BackupScheduling/BackupScheduleDispatcher.php - [X] T016 [US1] Add execution-time guard to skip archived schedules in app/Jobs/RunBackupScheduleJob.php - [X] T016 [US1] Add execution-time guard to skip archived schedules in app/Jobs/RunBackupScheduleJob.php (set `OperationRun` to `completed` + outcome `blocked`, `summary_counts.skipped=1`, `failure_summary.code=schedule_archived`, and emit `backup_schedule.run_skipped` with `reason=schedule_archived`) **Checkpoint**: Archive works end-to-end; archived schedules never execute. --- ## Phase 4: User Story 2 — Restore an archived schedule (Priority: P2) **Goal**: Tenant admins can restore archived schedules (no confirmation required) without changing enabled/disabled state. **Independent Test**: Archive a schedule, restore it, verify it returns to the default list, `is_enabled` is unchanged, and audit entry exists. ### Tests (write first) - [X] T017 [P] [US2] Add restore lifecycle tests (no confirmation required; is_enabled unchanged) in tests/Feature/BackupScheduling/BackupScheduleLifecycleTest.php ### Implementation - [X] T018 [US2] Add “Restore” action (only for archived records) in app/Filament/Resources/BackupScheduleResource.php - [X] T019 [US2] Enforce RBAC-UX for restore action using app/Support/Rbac/UiEnforcement.php in app/Filament/Resources/BackupScheduleResource.php - [X] T020 [US2] Emit audit event backup_schedule.restored via app/Services/Intune/AuditLogger.php from app/Filament/Resources/BackupScheduleResource.php **Checkpoint**: Restore is functional and independently testable. --- ## Phase 5: User Story 3 — Force delete as a privileged retention tool (Priority: P3) **Goal**: Highly privileged tenant admins can force delete archived schedules with confirmation, but only when no historical runs exist. **Independent Test**: Archive a schedule, attempt force delete without `TENANT_DELETE` (403), attempt force delete with historical runs (blocked), force delete with no historical runs (success), and audit entry exists. ### Tests (write first) - [X] T021 [P] [US3] Add force delete tests (capability gated; only archived; blocked when historical runs exist) in tests/Feature/BackupScheduling/BackupScheduleLifecycleTest.php ### Implementation - [X] T022 [US3] Add “Force delete” action (only for archived records; requires confirmation) in app/Filament/Resources/BackupScheduleResource.php - [X] T023 [US3] Enforce RBAC-UX for force delete using app/Support/Rbac/UiEnforcement.php in app/Filament/Resources/BackupScheduleResource.php - [X] T024 [US3] Block force delete when historical runs exist using BackupSchedule::operationRuns() in app/Models/BackupSchedule.php and enforce in app/Filament/Resources/BackupScheduleResource.php - [X] T024 [US3] Block force delete when historical runs exist using BackupSchedule::operationRuns() in app/Models/BackupSchedule.php and enforce in app/Filament/Resources/BackupScheduleResource.php (danger notification: title “Cannot force delete backup schedule”, body “Backup schedules referenced by historical runs cannot be removed.”; do not delete; do not emit `backup_schedule.force_deleted`) - [X] T025 [US3] Emit audit event backup_schedule.force_deleted via app/Services/Intune/AuditLogger.php from app/Filament/Resources/BackupScheduleResource.php **Checkpoint**: Force delete is safe (blocked when history exists) and audited. --- ## Phase 6: Polish & Cross-Cutting Concerns **Purpose**: Ensure contract compliance, update impacted tests, and validate via quickstart. - [X] T026 [P] Update bulk delete test to match “no bulk destructive actions” rule in tests/Feature/BackupScheduling/BackupScheduleBulkDeleteTest.php - [X] T027 Ensure BackupSchedule list inspect affordance opens Edit page in app/Filament/Resources/BackupScheduleResource.php - [X] T028 Ensure “max 2 visible row actions; everything else in More ActionGroup” in app/Filament/Resources/BackupScheduleResource.php - [X] T029 Run formatting in repo using vendor/bin/sail bin pint --dirty - [X] T030 Run focused test suite using vendor/bin/sail artisan test --compact tests/Feature/BackupScheduling - [ ] T031 Run Spec 091 manual checklist from specs/091-backupschedule-retention-lifecycle/quickstart.md --- ## Dependencies & Execution Order ### Phase Dependencies - **Setup (Phase 1)**: No dependencies. - **Foundational (Phase 2)**: Depends on Setup completion; BLOCKS all user stories. - **User Stories (Phase 3–5)**: Depend on Foundational completion. - **Polish (Phase 6)**: Depends on all desired user stories being complete. ### User Story Dependencies - **US1 (Archive)**: First; enables “Archived” state and execution safety. - **US2 (Restore)**: Depends on US1 (requires archived records to exist). - **US3 (Force delete)**: Depends on US1 (force delete only applies to archived records). --- ## Parallel Execution Examples ### US1 (after Phase 2) - T007 (lifecycle tests), T008 (dispatcher safety test), and T009 (job safety test) can be written in parallel. - T015 (dispatcher exclusion) and T016 (job guard) can be implemented in parallel. ### US3 (after US1) - T021 (force delete tests) can be written while UI action scaffolding is prepared (T022–T023). --- ## Implementation Strategy ### MVP First (US1 Only) 1. Complete Phase 1 and Phase 2. 2. Implement US1 (archive + execution safety + audit) and pass US1 tests. 3. Validate via Phase 6 tasks T029–T031. ### Incremental Delivery - Add US2 (restore) once US1 is stable. - Add US3 (force delete) last, with strict capability gating and history blocking. --- ## Additions (Consistency + Constitution Coverage) **Purpose**: Close remaining gaps found by the consistency analysis (terminology, FR-012 coverage, and explicit server-side RBAC enforcement + tests). - [X] T032 [US1] Allow editing archived schedules (SoftDeletes) in app/Filament/Resources/BackupScheduleResource/Pages/EditBackupSchedule.php - [X] T033 [P] [US1] Add test asserting an authorized tenant member can open Edit for a soft-deleted schedule in tests/Feature/BackupScheduling/BackupScheduleLifecycleTest.php - [X] T034 [US1] Enforce server-side authorization (Policy/Gate) for Archive action in app/Filament/Resources/BackupScheduleResource.php - [X] T035 [US2] Enforce server-side authorization (Policy/Gate) for Restore action in app/Filament/Resources/BackupScheduleResource.php - [X] T036 [US3] Enforce server-side authorization (Policy/Gate) for Force delete action in app/Filament/Resources/BackupScheduleResource.php - [X] T037 [P] [US1] Add explicit RBAC-UX tests for 404 vs 403 semantics in tests/Feature/BackupScheduling/BackupScheduleLifecycleAuthorizationTest.php - [X] T038 [P] [US1] Add idempotency tests for Archive/Restore (already archived / already active) in tests/Feature/BackupScheduling/BackupScheduleLifecycleTest.php