TenantAtlas/specs/005-bulk-operations/tasks.md
Ahmed Darrazi 9eb3a849e2 feat(005): Generate task breakdown for Bulk Operations feature
98 tasks across 10 phases organized by user story:
- Phase 1-2: Setup + Foundational (13 tasks)
- Phase 3-4: US1 Bulk Delete + US2 Export (22 tasks) - MVP
- Phase 5: US5 Type-to-Confirm (7 tasks)
- Phase 6: US6 Progress Tracking (12 tasks)
- Phase 7-9: US3 Prune + US4 Delete Runs + Backup Sets (31 tasks)
- Phase 10: Polish + QA (13 tasks)

MVP Scope: 35 tasks (16-22 hours)
Full P1/P2: 85 tasks (26-34 hours)
Production Ready: 98 tasks (30-40 hours)

Each user story independently testable:
- US1: Bulk delete policies (local, ignored_at flag)
- US2: Bulk export to backup set
- US3: Prune old policy versions (eligibility checks)
- US4: Delete restore runs (skip running)
- US5: Type-to-confirm for ≥20 items
- US6: Progress tracking with Livewire polling

Parallel opportunities identified:
- All tests per story can run parallel
- User stories can be worked on by different devs
- Models/jobs in different files can be created parallel

Critical path to MVP: T001→T007→T014→T024 (12-16 hours)
2025-12-22 01:32:05 +01:00

20 KiB

Tasks: Feature 005 - Bulk Operations

Branch: feat/005-bulk-operations | Date: 2025-12-22
Input: spec.md, plan.md, data-model.md, research.md

Task Format

  • Checkbox: - [ ] for incomplete, - [x] for complete
  • Task ID: Sequential T001, T002, T003...
  • [P] marker: Task can run in parallel (different files, no blocking dependencies)
  • [Story] label: User story tag (US1, US2, US3...) - omit for Setup/Foundational/Polish phases
  • File path: Always include exact file path in description

Phase 1: Setup (Project Initialization)

Purpose: Database schema and base infrastructure for bulk operations

  • T001 Create migration for bulk_operation_runs table in database/migrations/YYYY_MM_DD_HHMMSS_create_bulk_operation_runs_table.php
  • T002 Create migration to add ignored_at column to policies table in database/migrations/YYYY_MM_DD_HHMMSS_add_ignored_at_to_policies_table.php
  • T003 [P] Create BulkOperationRun model in app/Models/BulkOperationRun.php
  • T004 [P] Create BulkOperationService in app/Services/BulkOperationService.php
  • T005 Run migrations and verify schema: ./vendor/bin/sail artisan migrate
  • T006 Run Pint formatting: ./vendor/bin/sail composer pint

Checkpoint: Database ready, base models created


Phase 2: Foundational (Shared Components)

Purpose: Core components used by ALL bulk operations - MUST complete before user stories

⚠️ CRITICAL: No user story work can begin until this phase is complete

  • T007 Extend Policy model with ignored_at scope and methods in app/Models/Policy.php
  • T008 [P] Extend PolicyVersion model with pruneEligible() scope in app/Models/PolicyVersion.php
  • T009 [P] Extend RestoreRun model with deletable() scope in app/Models/RestoreRun.php
  • T010 Extend AuditLogger service to support bulk operation events in app/Services/Audit/AuditLogger.php (or equivalent)
  • T011 Update SyncPoliciesJob to filter by ignored_at IS NULL in app/Jobs/SyncPoliciesJob.php
  • T012 Create BulkOperationRun factory in database/factories/BulkOperationRunFactory.php
  • T013 Create test seeder BulkOperationsTestSeeder in database/seeders/BulkOperationsTestSeeder.php

Checkpoint: Foundation ready - user story implementation can now begin in parallel


Phase 3: User Story 1 - Bulk Delete Policies (Priority: P1) 🎯 MVP

Goal: Enable admins to soft-delete multiple policies locally with ignored_at flag, preventing re-sync

Independent Test: Select 15 policies → bulk delete → verify ignored_at set, policies hidden from listings, audit log created, Intune unchanged

Tests for User Story 1

  • T014 [P] [US1] Write unit test for BulkPolicyDeleteJob in tests/Unit/BulkPolicyDeleteJobTest.php
  • T015 [P] [US1] Write feature test for bulk delete <20 items (sync) in tests/Feature/BulkDeletePoliciesTest.php
  • T016 [P] [US1] Write feature test for bulk delete ≥20 items (async) in tests/Feature/BulkDeletePoliciesAsyncTest.php
  • T017 [P] [US1] Write permission test for bulk delete in tests/Unit/BulkActionPermissionTest.php

Implementation for User Story 1

  • T018 [P] [US1] Create BulkPolicyDeleteJob in app/Jobs/BulkPolicyDeleteJob.php
  • T019 [US1] Add bulk delete action to PolicyResource in app/Filament/Resources/PolicyResource.php
  • T020 [US1] Implement type-to-confirm modal (≥20 items) in PolicyResource bulk action
  • T021 [US1] Wire BulkOperationService to create tracking record and dispatch job
  • T022 [US1] Test bulk delete with 10 policies (sync, manual QA)
  • T023 [US1] Test bulk delete with 25 policies (async, manual QA)
  • T024 [US1] Run tests: ./vendor/bin/sail artisan test tests/Feature/BulkDeletePoliciesTest.php
  • T025 [US1] Verify audit log entry created with correct metadata

Checkpoint: Bulk delete policies working (sync + async), audit logged, tests passing


Phase 4: User Story 2 - Bulk Export Policies to Backup (Priority: P1)

Goal: Enable admins to export multiple policies to a new Backup Set with progress tracking

Independent Test: Select 25 policies → export to backup → verify BackupSet created, 25 BackupItems exist, progress notification shown

Tests for User Story 2

  • T026 [P] [US2] Write unit test for BulkPolicyExportJob in tests/Unit/BulkPolicyExportJobTest.php
  • T027 [P] [US2] Write feature test for bulk export in tests/Feature/BulkExportToBackupTest.php
  • T028 [P] [US2] Write test for export with failures (3/25 fail) in tests/Feature/BulkExportFailuresTest.php

Implementation for User Story 2

  • T029 [P] [US2] Create BulkPolicyExportJob in app/Jobs/BulkPolicyExportJob.php
  • T030 [US2] Add bulk export action to PolicyResource in app/Filament/Resources/PolicyResource.php
  • T031 [US2] Create export form with backup_name and include_assignments fields
  • T032 [US2] Implement export logic (create BackupSet, capture BackupItems)
  • T033 [US2] Handle partial failures (some policies fail to backup)
  • T034 [US2] Test export with 30 policies (manual QA)
  • T035 [US2] Run tests: ./vendor/bin/sail artisan test tests/Feature/BulkExportToBackupTest.php

Checkpoint: Bulk export working, BackupSets created, failures handled gracefully


Phase 5: User Story 5 - Type-to-Confirm (Priority: P1)

Goal: Require typing "DELETE" for destructive operations with ≥20 items

Independent Test: Bulk delete 25 policies → modal requires "DELETE" → button disabled until correct input → operation proceeds

Note: This is implemented within US1 (T020) but tested separately here

Tests for User Story 5

  • T036 [P] [US5] Write test for type-to-confirm with correct input in tests/Feature/BulkTypeToConfirmTest.php
  • T037 [P] [US5] Write test for type-to-confirm with incorrect input (lowercase "delete")
  • T038 [P] [US5] Write test for type-to-confirm disabled for <20 items

Validation for User Story 5

  • T039 [US5] Manual test: Bulk delete 10 policies → confirm without typing (should work)
  • T040 [US5] Manual test: Bulk delete 25 policies → type "delete" → button stays disabled
  • T041 [US5] Manual test: Bulk delete 25 policies → type "DELETE" → button enables, operation proceeds
  • T042 [US5] Run tests: ./vendor/bin/sail artisan test tests/Feature/BulkTypeToConfirmTest.php

Checkpoint: Type-to-confirm working correctly for all thresholds


Phase 6: User Story 6 - Progress Tracking (Priority: P2)

Goal: Show real-time progress for queued bulk operations with Livewire polling

Independent Test: Bulk delete 100 policies → progress notification updates every 5s → final notification shows outcomes

Tests for User Story 6

  • T043 [P] [US6] Write test for progress updates in BulkOperationRun in tests/Unit/BulkOperationRunProgressTest.php
  • T044 [P] [US6] Write feature test for progress notification in tests/Feature/BulkProgressNotificationTest.php
  • T045 [P] [US6] Write test for circuit breaker (abort >50% fail) in tests/Unit/CircuitBreakerTest.php

Implementation for User Story 6

  • T046 [P] [US6] Create Livewire progress component in app/Livewire/BulkOperationProgress.php
  • T047 [P] [US6] Create progress view in resources/views/livewire/bulk-operation-progress.blade.php
  • T048 [US6] Update BulkPolicyDeleteJob to emit progress after each chunk
  • T049 [US6] Update BulkPolicyExportJob to emit progress after each chunk
  • T050 [US6] Implement circuit breaker logic (abort if >50% fail) in jobs
  • T051 [US6] Add progress polling to Filament notifications or sidebar widget
  • T052 [US6] Test progress with 100 policies (manual QA, observe updates)
  • T053 [US6] Test circuit breaker with mock failures (manual QA)
  • T054 [US6] Run tests: ./vendor/bin/sail artisan test tests/Feature/BulkProgressNotificationTest.php

Checkpoint: Progress tracking working, polling updates UI, circuit breaker aborts high-failure jobs


Phase 7: User Story 3 - Bulk Delete Policy Versions (Priority: P2)

Goal: Enable admins to prune old policy versions that are NOT referenced and meet retention threshold (>90 days)

Independent Test: Select 30 old versions → bulk prune → verify eligible deleted, ineligible skipped with reasons

Tests for User Story 3

  • T055 [P] [US3] Write unit test for pruneEligible() scope in tests/Unit/PolicyVersionEligibilityTest.php
  • T056 [P] [US3] Write unit test for BulkPolicyVersionPruneJob in tests/Unit/BulkPolicyVersionPruneJobTest.php
  • T057 [P] [US3] Write feature test for bulk prune in tests/Feature/BulkPruneVersionsTest.php
  • T058 [P] [US3] Write test for skip reasons (referenced, too recent, current) in tests/Feature/BulkPruneSkipReasonsTest.php

Implementation for User Story 3

  • T059 [P] [US3] Create BulkPolicyVersionPruneJob in app/Jobs/BulkPolicyVersionPruneJob.php
  • T060 [US3] Add bulk delete action to PolicyVersionResource in app/Filament/Resources/PolicyVersionResource.php
  • T061 [US3] Implement eligibility check per version in job (reuse pruneEligible scope)
  • T062 [US3] Collect skip reasons for ineligible versions
  • T063 [US3] Add type-to-confirm for ≥20 versions
  • T064 [US3] Test prune with 30 versions (15 eligible, 15 ineligible) - manual QA
  • T065 [US3] Verify skip reasons in notification and audit log
  • T066 [US3] Run tests: ./vendor/bin/sail artisan test tests/Feature/BulkPruneVersionsTest.php

Checkpoint: Policy versions pruning working, eligibility enforced, skip reasons logged


Phase 8: User Story 4 - Bulk Delete Restore Runs (Priority: P2)

Goal: Enable admins to delete completed/failed restore runs to declutter history

Independent Test: Select 20 completed runs → bulk delete → verify soft-deleted, running runs skipped

Tests for User Story 4

  • T067 [P] [US4] Write unit test for deletable() scope in tests/Unit/RestoreRunDeletableTest.php
  • T068 [P] [US4] Write unit test for BulkRestoreRunDeleteJob in tests/Unit/BulkRestoreRunDeleteJobTest.php
  • T069 [P] [US4] Write feature test for bulk delete restore runs in tests/Feature/BulkDeleteRestoreRunsTest.php
  • T070 [P] [US4] Write test for mixed statuses (skip running) in tests/Feature/BulkDeleteMixedStatusTest.php

Implementation for User Story 4

  • T071 [P] [US4] Create BulkRestoreRunDeleteJob in app/Jobs/BulkRestoreRunDeleteJob.php
  • T072 [US4] Add bulk delete action to RestoreRunResource in app/Filament/Resources/RestoreRunResource.php
  • T073 [US4] Filter by deletable() scope (completed, failed, aborted only)
  • T074 [US4] Skip running restore runs with warning
  • T075 [US4] Add type-to-confirm for ≥20 runs
  • T076 [US4] Test delete with 20 completed + 5 running (manual QA, verify 5 skipped)
  • T077 [US4] Run tests: ./vendor/bin/sail artisan test tests/Feature/BulkDeleteRestoreRunsTest.php

Checkpoint: Restore runs bulk delete working, running runs protected, skip warnings shown


Phase 9: Additional Resource - Bulk Delete Backup Sets (Priority: P2)

Goal: Enable admins to delete backup sets with cascade-delete of backup items

Independent Test: Select 10 backup sets → bulk delete → verify sets deleted, items cascade-deleted

Tests for Additional Resource

  • T078 [P] Write unit test for BulkBackupSetDeleteJob in tests/Unit/BulkBackupSetDeleteJobTest.php
  • T079 [P] Write feature test for bulk delete backup sets in tests/Feature/BulkDeleteBackupSetsTest.php

Implementation for Additional Resource

  • T080 [P] Create BulkBackupSetDeleteJob in app/Jobs/BulkBackupSetDeleteJob.php
  • T081 Add bulk delete action to BackupSetResource in app/Filament/Resources/BackupSetResource.php
  • T082 Verify cascade-delete logic for backup items (should be automatic via foreign key)
  • T083 Add type-to-confirm for ≥10 sets
  • T084 Test delete with 15 backup sets (manual QA)
  • T085 Run tests: ./vendor/bin/sail artisan test tests/Feature/BulkDeleteBackupSetsTest.php

Checkpoint: Backup sets bulk delete working, cascade-delete verified


Phase 10: Polish & Cross-Cutting Concerns

Purpose: Documentation, cleanup, performance optimization

  • T086 [P] Update README.md with bulk operations feature description
  • T087 [P] Update quickstart.md with manual testing scenarios (already done in planning)
  • T088 Code cleanup: Remove debug statements, refactor duplicated logic
  • T089 Performance test: Bulk delete 500 policies (should complete <5 minutes)
  • T090 Load test: Concurrent bulk operations (2-3 admins, different resources)
  • T091 [P] Security review: Verify tenant isolation in all jobs
  • T092 [P] Permission audit: Verify all bulk actions respect RBAC
  • T093 Run full test suite: ./vendor/bin/sail artisan test
  • T094 Run Pint formatting: ./vendor/bin/sail composer pint
  • T095 Manual QA checklist: Complete all scenarios from quickstart.md
  • T096 Document configuration options (chunk size, polling interval, retention days)
  • T097 Create BulkOperationRun resource page in Filament (view progress, retry failed)
  • T098 Add bulk operation metrics to dashboard (total runs, success rate)

Checkpoint: Feature polished, tested, documented, ready for staging deployment


Dependencies & Execution Order

Phase Dependencies

Setup (Phase 1)
    ↓
Foundational (Phase 2) ← BLOCKS all user stories
    ↓
┌───────────────────────────────────┐
│  User Stories (Parallel Capable)  │
├───────────────────────────────────┤
│ US1: Bulk Delete Policies (P1)    │ ← MVP
│ US2: Bulk Export (P1)              │ ← MVP
│ US5: Type-to-Confirm (P1)          │ ← Embedded in US1
├───────────────────────────────────┤
│ US6: Progress Tracking (P2)        │ ← Enhances US1, US2
│ US3: Prune Versions (P2)           │
│ US4: Delete Runs (P2)              │
│ Additional: Delete Sets (P2)       │
└───────────────────────────────────┘
    ↓
Polish (Phase 10)

User Story Dependencies

  • US1 (P1): Depends on Foundational (T007, T010, T011). Fully independent after that.
  • US2 (P1): Depends on Foundational (T010). Fully independent after that.
  • US5 (P1): Implemented within US1 (T020), tested separately.
  • US6 (P2): Depends on US1 and US2 (adds progress to existing jobs). Can be implemented after US1/US2 are functional.
  • US3 (P2): Depends on Foundational (T008, T010). Fully independent.
  • US4 (P2): Depends on Foundational (T009, T010). Fully independent.
  • Additional (P2): Depends on Foundational (T010). Fully independent.

Parallel Opportunities Within Phases

Setup (Phase 1):

  • T003, T004 can run in parallel (different files)

Foundational (Phase 2):

  • T008, T009, T012 can run in parallel (different files)
  • T007, T010, T011 must be sequential (modify same services)

User Story 1 Tests (T014-T017): All parallel (different test files)

User Story 1 Implementation:

  • T018 parallel with T019-T021 (different files initially)
  • T019-T021 sequential (same file edits)
  • T022-T025 sequential (testing/validation)

User Story 2 Tests (T026-T028): All parallel

User Story 2 Implementation:

  • T029 parallel with T030-T031 (different files)
  • T030-T035 sequential (same file, progressive features)

User Story 3-4 and Additional: Can all run in parallel after Foundational complete (different resources, no overlap)

Critical Path (Fastest Route to MVP)

T001 → T002 → T005 (Setup migrations, run)
    ↓
T007 → T010 → T011 (Foundational: Policy scope, AuditLogger, SyncJob)
    ↓
T014-T017 (US1 tests) → T018 → T019 → T020 (US1 core) → T024 (verify)
    ↓
MVP Ready: Bulk delete policies with type-to-confirm

Estimated MVP Time: ~12-16 hours (Setup + Foundational + US1)


Parallel Example: User Story 1 Implementation

If working with a team, these tasks can run concurrently:

Developer A:

# Write tests first (TDD)
tests/Unit/BulkPolicyDeleteJobTest.php (T014)
tests/Feature/BulkDeletePoliciesTest.php (T015)

Developer B (after foundational complete):

# Implement job
app/Jobs/BulkPolicyDeleteJob.php (T018)

Developer C (after T018 complete):

# Wire up Filament UI
app/Filament/Resources/PolicyResource.php (T019-T021)

Developer A (after implementation complete):

# Run tests, verify passing
./vendor/bin/sail artisan test tests/Feature/BulkDeletePoliciesTest.php (T024)

Parallel Example: Multiple User Stories

After Foundational phase completes, these can proceed in parallel (different team members):

Team Member 1: US1 Bulk Delete Policies (T014-T025)
Team Member 2: US2 Bulk Export (T026-T035)
Team Member 3: US3 Prune Versions (T055-T066)
Team Member 4: US6 Progress Tracking (T043-T054)

All integrate at the end without conflicts (different resources/files).


Testing Strategy

Unit Tests (tests/Unit/)

  • BulkPolicyDeleteJob
  • BulkPolicyExportJob
  • BulkPolicyVersionPruneJob
  • BulkBackupSetDeleteJob
  • BulkRestoreRunDeleteJob
  • BulkActionPermission
  • PolicyVersion::pruneEligible scope
  • RestoreRun::deletable scope
  • BulkOperationRun progress helpers
  • Circuit breaker logic

Feature Tests (tests/Feature/)

  • BulkDeletePolicies (sync, async)
  • BulkExportToBackup
  • BulkTypeToConfirm
  • BulkProgressNotification
  • BulkPruneVersions (eligibility, skip reasons)
  • BulkDeleteRestoreRuns (mixed statuses)
  • BulkDeleteBackupSets (cascade)

Manual QA Scenarios (from quickstart.md)

  1. Bulk delete 10 policies (sync, no type-to-confirm)
  2. Bulk delete 25 policies (async, type-to-confirm)
  3. Bulk export 30 policies (progress tracking)
  4. Bulk prune 30 versions (eligibility checks)
  5. Circuit breaker with mock failures (>50% fail)

Implementation Strategy

MVP First (P1 Features Only)

Goal: Ship minimal viable feature to get user feedback

Scope:

  • Setup (T001-T006)
  • Foundational (T007-T013)
  • US1: Bulk Delete Policies (T014-T025)
  • US2: Bulk Export (T026-T035)
  • US5: Type-to-Confirm (T036-T042) - already in US1

Estimated Time: 16-22 hours
Deliverable: Admins can bulk delete and export policies with safety gates

Iteration 2 (P2 Features)

Goal: Add progress tracking and additional resources

Scope:

  • US6: Progress Tracking (T043-T054)
  • US3: Prune Versions (T055-T066)
  • US4: Delete Runs (T067-T077)
  • Additional: Delete Sets (T078-T085)

Estimated Time: 10-12 hours
Deliverable: Full feature set with progress UI and all resources

Iteration 3 (Polish)

Goal: Production readiness

Scope:

  • Polish (T086-T098)
  • Performance testing
  • Security audit
  • Documentation finalization

Estimated Time: 4-6 hours
Deliverable: Production-ready feature


Success Criteria

  • All P1 tests passing (US1, US2, US5)
  • Bulk delete 100 policies in <2 minutes
  • Type-to-confirm prevents accidents (≥20 items)
  • Progress updates every 5-10s for queued jobs
  • Audit log captures per-item outcomes
  • Circuit breaker aborts at >50% failure rate
  • Tenant isolation enforced (verified via tests)
  • Manual QA checklist complete (5 scenarios)

Total Task Count

  • Setup: 6 tasks (T001-T006)
  • Foundational: 7 tasks (T007-T013)
  • US1: 12 tasks (T014-T025)
  • US2: 10 tasks (T026-T035)
  • US5: 7 tasks (T036-T042)
  • US6: 12 tasks (T043-T054)
  • US3: 12 tasks (T055-T066)
  • US4: 11 tasks (T067-T077)
  • Additional: 8 tasks (T078-T085)
  • Polish: 13 tasks (T086-T098)

Total: 98 tasks

MVP Scope: 35 tasks (Setup + Foundational + US1 + US2 + US5)
Full P1/P2 Scope: 85 tasks (all user stories)
Production Ready: 98 tasks (including polish)


Status: Tasks Ready for Implementation
Next Step: Begin Phase 1 (Setup) → Run migrations → Start US1 tests