# Backup & Upload This document describes the photo/video backup functionality, including foreground and background uploads. ## Backup Overview The backup system automatically uploads photos and videos from the device to the server: ``` ┌─────────────────────────────────────────────────────────────┐ │ Backup Flow │ ├─────────────────────────────────────────────────────────────┤ │ Device Photos → Backup Service → Server │ │ │ │ 1. Select albums to backup │ │ 2. Find new/changed assets │ │ 3. Check for duplicates (hash) │ │ 4. Upload assets │ │ 5. Update local database │ └─────────────────────────────────────────────────────────────┘ ``` ## Backup Configuration ### Backup Controller Screen ``` ┌─────────────────────────────────────────────────────────────┐ │ ← Backup │ ├─────────────────────────────────────────────────────────────┤ │ Backup Status │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ ✓ Backup Complete │ │ │ │ 1,234 of 1,234 backed up │ │ │ │ Last backup: 2 hours ago │ │ │ └─────────────────────────────────────────────────────┘ │ ├─────────────────────────────────────────────────────────────┤ │ Backup Albums │ │ [Select albums to backup] │ ├─────────────────────────────────────────────────────────────┤ │ Excluded Albums │ │ [Select albums to exclude] │ ├─────────────────────────────────────────────────────────────┤ │ Settings │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ Background Backup [Toggle: ON] │ │ │ │ Use Wi-Fi only [Toggle: ON] │ │ │ │ Require charging [Toggle: OFF] │ │ │ │ Ignore iCloud assets [Toggle: OFF] │ │ │ └─────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────┘ ``` ## Album Selection ### Backup Albums - Select which device albums to back up - "Recents" includes all photos - Individual albums for selective backup ### Excluded Albums - Exclude specific albums - Useful for Screenshots, WhatsApp Images, etc. - Takes precedence over selected albums ### Album Selection Logic ``` Backup Candidates = Selected Albums - Excluded Albums If "Recents" selected (Android): - Back up all device photos - Individual album folders tracked for sync If "Recents" selected (iOS): - Use "All Photos" album - Check against excluded albums per asset ``` ## Backup Process ### Step 1: Build Upload Candidates ``` 1. Get selected backup albums 2. Get excluded backup albums 3. For each selected album: a. Check if album modified since last backup b. Get assets newer than last backup time c. Add album name to asset metadata 4. Remove assets from excluded albums ``` ### Step 2: Remove Already Uploaded ``` 1. Check local duplicates database 2. Call server to check existing assets POST /assets/exist Body: { "deviceAssetIds": ["local-id-1", "local-id-2", ...], "deviceId": "device-uuid" } Response: { "existingIds": ["local-id-1"] } ``` ### Step 3: Upload Assets For each asset: ``` 1. Get original file from device 2. If live photo, also get video component 3. Calculate upload metadata 4. Upload via multipart form POST /assets Content-Type: multipart/form-data Fields: - deviceAssetId: local ID - deviceId: device UUID - fileCreatedAt: creation timestamp - fileModifiedAt: modification timestamp - isFavorite: boolean - duration: video duration Files: - assetData: the file - livePhotoData: motion video (if applicable) ``` ### Step 4: Handle Response ``` 200 OK: Asset already exists (duplicate) 201 Created: Asset uploaded successfully Response: { "id": "remote-asset-uuid", "deviceAssetId": "local-id", ... } ``` ## Upload Progress Tracking ### Progress Model ``` CurrentUploadAsset { id: String // Local asset ID fileName: String // File name fileType: String // IMAGE, VIDEO, etc. fileSize: Integer // Bytes fileCreatedAt: DateTime iCloudAsset: Boolean // Downloading from iCloud } UploadProgress { bytesUploaded: Integer totalBytes: Integer percentage: Double } ``` ### Progress UI ``` ┌─────────────────────────────────────────────────────────────┐ │ Uploading... │ │ │ │ IMG_1234.jpg │ │ [████████████░░░░░░░░░░░░░░░░░] 45% │ │ │ │ 12 of 50 • 2.4 MB / 5.1 MB │ └─────────────────────────────────────────────────────────────┘ ``` ## Background Backup ### Platform Differences **Android:** - Uses WorkManager for scheduling - Triggers on content changes - Requires battery optimization disabled **iOS:** - Uses Background App Refresh - Limited execution time - BGProcessingTask for longer uploads ### Background Service Configuration ``` RequireUnmetered: true/false // Wi-Fi only RequireCharging: true/false // Charging only TriggerDelay: 5000ms // Minimum delay MaxDelay: 50000ms // Maximum delay ``` ### Background Notification ``` ┌─────────────────────────────────────────────────────────────┐ │ Immich │ │ Uploading 12/50 photos... │ │ [Progress bar] │ └─────────────────────────────────────────────────────────────┘ ``` ### Background Process Flow ``` 1. System triggers background task 2. Acquire lock (prevent concurrent runs) 3. Load translations 4. Initialize database 5. Set API endpoint 6. Get selected/excluded albums 7. Run backup process 8. Update last backup timestamps 9. Release lock ``` ## iCloud Assets (iOS) ### Handling iCloud Photos 1. Check if asset is locally available 2. If not, option to download from iCloud 3. Show progress during download 4. Upload after download complete ### Settings - `ignoreIcloudAssets`: Skip assets not on device ## Album Sync Feature ### Purpose Automatically organize uploads into server albums matching device album names. ### How It Works 1. Asset uploaded with album names in metadata 2. After upload, check for matching albums 3. Create album if doesn't exist 4. Add asset to album ### API ``` POST /albums/{albumName}/assets Body: { "assetIds": ["uploaded-asset-id"] } ``` ## Duplicate Detection ### Hash-Based Detection 1. Calculate file hash (checksum) 2. Store in local duplicates database 3. Skip uploads for known duplicates ### Server-Side Check ``` POST /assets/exist Checks if assets already on server by device ID + local ID ``` ## Error Handling ### Retry Logic - Failed uploads retry automatically - Exponential backoff - Maximum retry attempts ### Error Notifications ``` ┌─────────────────────────────────────────────────────────────┐ │ ⚠️ Upload Failed │ │ IMG_5678.jpg could not be uploaded │ │ Error: Network connection lost │ └─────────────────────────────────────────────────────────────┘ ``` ### Common Errors | Error | Cause | Action | |-------|-------|--------| | Network error | No connection | Retry when online | | Quota exceeded | Storage full | Stop backup, notify user | | File not found | Asset deleted | Skip asset | | Permission denied | Gallery access lost | Request permission | ## Failed Uploads Screen ### Layout ``` ┌─────────────────────────────────────────────────────────────┐ │ ← Failed Uploads │ ├─────────────────────────────────────────────────────────────┤ │ 5 uploads failed │ ├─────────────────────────────────────────────────────────────┤ │ ┌─────────────────────────────────────────────────────┐ │ │ │ 📷 IMG_1234.jpg │ │ │ │ Network timeout │ │ │ │ [Retry] │ │ │ └─────────────────────────────────────────────────────┘ │ │ ... │ ├─────────────────────────────────────────────────────────────┤ │ [Retry All] │ └─────────────────────────────────────────────────────────────┘ ``` ## Backup Statistics ### Tracked Metrics - Total assets to backup - Successfully uploaded - Failed uploads - Duplicate (already on server) - Last backup timestamp ### Storage Usage ``` GET /users/me Response includes: { "quotaUsageInBytes": 1234567890, "quotaSizeInBytes": 10737418240 } ``` ## Cellular Data Settings ### Options - `useCellularForUploadPhotos`: Allow photo upload on cellular - `useCellularForUploadVideos`: Allow video upload on cellular --- [Previous: Gallery Viewer](./gallery-viewer.md) | [Next: Download](./download.md)