---

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
