## Summary <!-- Kurz: Was ändert sich und warum? --> ## Spec-Driven Development (SDD) - [ ] Es gibt eine Spec unter `specs/<NNN>-<feature>/` - [ ] Enthaltene Dateien: `plan.md`, `tasks.md`, `spec.md` - [ ] Spec beschreibt Verhalten/Acceptance Criteria (nicht nur Implementation) - [ ] Wenn sich Anforderungen während der Umsetzung geändert haben: Spec/Plan/Tasks wurden aktualisiert ## Implementation - [ ] Implementierung entspricht der Spec - [ ] Edge cases / Fehlerfälle berücksichtigt - [ ] Keine unbeabsichtigten Änderungen außerhalb des Scopes ## Tests - [ ] Tests ergänzt/aktualisiert (Pest/PHPUnit) - [ ] Relevante Tests lokal ausgeführt (`./vendor/bin/sail artisan test` oder `php artisan test`) ## Migration / Config / Ops (falls relevant) - [ ] Migration(en) enthalten und getestet - [ ] Rollback bedacht (rückwärts kompatibel, sichere Migration) - [ ] Neue Env Vars dokumentiert (`.env.example` / Doku) - [ ] Queue/cron/storage Auswirkungen geprüft ## UI (Filament/Livewire) (falls relevant) - [ ] UI-Flows geprüft - [ ] Screenshots/Notizen hinzugefügt ## Notes <!-- Links, Screenshots, Follow-ups, offene Punkte --> Co-authored-by: Ahmed Darrazi <ahmeddarrazi@adsmac.local> Reviewed-on: #4
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_runstable in database/migrations/YYYY_MM_DD_HHMMSS_create_bulk_operation_runs_table.php - T002 Create migration to add
ignored_atcolumn 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_atscope 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 NULLin 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)
- Bulk delete 10 policies (sync, no type-to-confirm)
- Bulk delete 25 policies (async, type-to-confirm)
- Bulk export 30 policies (progress tracking)
- Bulk prune 30 versions (eligibility checks)
- 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