# Implementation Steps: Backup Progress System Refactoring

**Reference Documentation:** [backup-progress-architecture.md](backup-progress-architecture.md)
**Strategy:** Atomic steps with incremental testing. Unit tests are added only when implementing real calculation logic (steps 3-5, 7-8). Structural steps (1-2, 6) use verification instead of formal tests.

---

## Step 1: Create TraitPackageProgress with Core Structure [COMPLETED]

**Goal:** Create trait skeleton with getProgress() method and phase delegation logic

**Tasks:**
- [x] Create `src/Package/TraitPackageProgress.php`
- [x] Implement `getProgress()` method with instanceof validation
- [x] Add status-based phase delegation logic (switch on status ranges)
- [x] Define return structure: `['percent' => float, 'message' => string, 'phase' => string]`
- [x] Handle complete/error states
- [x] Add stub methods for phases (to be implemented in next steps)

**Additional Notes:**
No unit tests at this stage - only routing logic and stubs. Real tests will be added when implementing calculation logic in steps 3-5.

**Status:** COMPLETED

---

## Step 2: Implement Initialization Progress Method [COMPLETED]

**Goal:** Add getInitProgress() returning fixed 0% progress

**Tasks:**
- [x] Implement `getInitProgress()` protected method
- [x] Return 0% progress with localized message "Initializing backup"
- [x] Set phase identifier to 'init'

**Additional Notes:**
Already implemented in Step 1. Returns fixed 0% - no calculation logic to test.

**Status:** COMPLETED

---

## Step 3: Implement Database Progress Method [COMPLETED]

**Goal:** Calculate database export progress from row counters

**Tasks:**
- [x] Implement `getDatabaseProgress()` protected method
- [x] Read row counters from `db_build_progress->countCheckData`
- [x] Calculate: (countTotal / impreciseTotalRows) × 100
- [x] Handle division by zero (return 0%)
- [x] Return with localized message "Exporting database"
- [x] Clamp percentage to 0-100 range

**Unit Tests:**
- [x] TraitPackageProgressTests (10 tests, 30 assertions)
  - Test progress calculation with various row counts
  - Test zero total rows handling
  - Test missing countCheckData handling
  - Test progress range (0-100%)
  - Test progress doesn't exceed 100%
  - Test phase routing

**Status:** COMPLETED

---

## Step 4: Implement Archive Progress Method [COMPLETED]

**Goal:** Calculate archive creation progress from file counters

**Tasks:**
- [x] Implement `getArchiveProgress()` protected method
- [x] Read file counters: `build_progress->next_archive_file_index` and `Archive->FileCount`
- [x] Calculate: (next_archive_file_index / FileCount) × 100
- [x] Handle division by zero (return 0%)
- [x] Return with localized message "Creating archive"
- [x] Clamp percentage to 0-100 range

**Unit Tests:**
- [x] TraitPackageProgressTests (17 tests, 51 assertions total)
  - Test progress calculation with various file counts
  - Test zero total files handling
  - Test progress range (0-100%)
  - Test progress doesn't exceed 100%
  - Test phase routing
  - Test missing objects handling

**Status:** COMPLETED

---

## Step 5: Implement Storage Progress Method [COMPLETED]

**Goal:** Calculate storage upload progress with multi-storage support

**Tasks:**
- [x] Implement `getStorageProgress()` protected method
- [x] Find active UploadInfo: `hasStarted() && !hasCompleted()`
- [x] Get progress from `$uploadInfo->progress`
- [x] Get storage name via `$uploadInfo->getStorage()->getName()`
- [x] Calculate position: array index + 1, total: count($upload_infos)
- [x] Format message: "Upload [Name] [%]% [Storage X of Y]"
- [x] Handle no active storage case (return 0%)

**Unit Tests:**
- [x] TraitPackageProgressTests (26 tests, 78 assertions total)
  - Test single storage upload progress
  - Test multiple storages with position tracking
  - Test no active storage handling
  - Test message formatting with storage name (single and multiple)
  - Test progress from UploadInfo object
  - Test progress clamping (0-100%)
  - Test empty upload_infos handling
  - Test phase routing

**Status:** COMPLETED

---

## Step 6: Integrate Trait into AbstractPackage [COMPLETED]

**Goal:** Add trait to AbstractPackage and deprecate old progress methods

**Tasks:**
- [x] Add `use TraitPackageProgress;` to AbstractPackage
- [x] Deprecate `setProgressPercent()` method (convert to no-op with @deprecated tag)
- [x] Remove `setProgressPercent()` call from `setStatus()` method
- [x] Keep `progressPercent` property for backward compatibility (not updated)
- [x] Fix PHPStan warnings (isset on non-nullable properties)

**Verification:**
✅ Verified `getProgress()` method is available on AbstractPackage instances via the trait.
✅ All 26 unit tests passing (78 assertions)

**Status:** COMPLETED

---

## Step 7: Update DupPackage [COMPLETED]

**Goal:** Refactor DupPackage to use new progress system

**Tasks:**
- [x] Remove `getStatusProgress()` from DupPackage (moved to TraitPackageProgress)
- [x] Add `getStatusProgress()` deprecated wrapper in TraitPackageProgress
- [x] Add `getStatusProgressText()` deprecated wrapper in TraitPackageProgress
- [x] Centralize all progress logic in trait (no logic in child classes)
- [x] Ensure backward compatibility for existing callers

**Implementation Notes:**
Both methods are now simple deprecated wrappers in TraitPackageProgress that delegate to `getProgress()`.
This centralizes all progress logic in the trait, eliminating complex per-status calculations from DupPackage.

**Unit Tests:**
No additional tests needed - wrapper methods are trivial delegates to `getProgress()`, which is already fully tested (26 tests, 78 assertions).

**Status:** COMPLETED

---

## Step 8: Update ServicesPackage AJAX Endpoint [COMPLETED]

**Goal:** Update package status API to return new progress data

**Tasks:**
- [x] Update `getPackageStatusInfo()` to call `getProgress()` once
- [x] Set `status_progress` from result `['percent']`
- [x] Set `status_progress_text` from result `['message']`
- [x] Remove conditional logic for storage-specific text

**Implementation Notes:**
Simplified `getPackageStatusInfo()` from 18 lines to 11 lines by:
- Single call to `getProgress()` instead of multiple method calls
- Eliminated conditional logic for active storage text
- All progress messages now come directly from TraitPackageProgress

**Unit Tests:**
No additional tests needed - the AJAX endpoint is a simple pass-through of `getProgress()` data, which is already fully tested.

**Status:** COMPLETED

---

## Step 9: Remove Database setProgressPercent Calls [PENDING]

**Goal:** Clean up deprecated progress updates in database export

**Tasks:**
- [ ] Remove all `setProgressPercent()` calls from `src/Package/Database/DatabasePkg.php`
- [ ] Verify row counter updates remain intact

**Verification:**
Run database export and verify progress calculation from row counters

**Status:** PENDING

---

## Step 10: Remove Archive setProgressPercent Calls [PENDING]

**Goal:** Clean up deprecated progress updates in archive creation

**Tasks:**
- [ ] Remove all `setProgressPercent()` calls from `src/Package/Archive/PackageArchiveZip.php`
- [ ] Remove all `setProgressPercent()` calls from `src/Package/Create/DupArchive/PackageDupArchive.php`
- [ ] Verify file index counter updates remain intact

**Verification:**
Run archive creation and verify progress calculation from file counters

**Status:** PENDING

---

## Step 11: Integration Testing [PENDING]

**Goal:** Verify end-to-end progress tracking across all phases

**Tasks:**
- [ ] Create integration test for full backup workflow
- [ ] Verify progress transitions: Init → Database → Archive → Storage
- [ ] Verify each phase starts at 0% and reaches 100%
- [ ] Verify progress messages update correctly
- [ ] Test with multiple storage destinations

**Integration Tests:**
- [ ] BackupProgressIntegrationTest
  - Test complete backup flow with progress tracking
  - Test multi-storage upload progress
  - Test progress API response format

**Verification:**
```bash
# Run full test suite
composer phpunit

# Manual verification: create backup and monitor AJAX responses
# Verify duplicator_pro_get_package_statii returns status_progress and status_progress_text
```

**Status:** PENDING
