|
| 1 | +--- |
| 2 | +id: TASK-341 |
| 3 | +title: Sync local library to attached iOS device with configurable filters and caps |
| 4 | +status: In Progress |
| 5 | +assignee: [] |
| 6 | +created_date: '2026-05-06 02:24' |
| 7 | +updated_date: '2026-05-22 03:39' |
| 8 | +labels: |
| 9 | + - feature |
| 10 | + - macos |
| 11 | + - library |
| 12 | + - usb |
| 13 | + - sync |
| 14 | +dependencies: |
| 15 | + - TASK-214 |
| 16 | +priority: high |
| 17 | +ordinal: 27250 |
| 18 | +--- |
| 19 | + |
| 20 | +## Description |
| 21 | + |
| 22 | +<!-- SECTION:DESCRIPTION:BEGIN --> |
| 23 | +When an iOS device is detected (via the mechanism delivered in task-214), sync a subset of the local library one-way (local β device) to the configured mount path (default `~/Music/Doppler`). Sync is driven by composable include/exclude rules and total caps so users can curate a rotating subset of a large collection on the device. |
| 24 | + |
| 25 | +This task adds the sync engine, configuration surface, and trigger flow. It does not change detection logic from task-214 β it consumes it. |
| 26 | + |
| 27 | +## Dependency |
| 28 | + |
| 29 | +Requires task-214: iPhone mount detection, mount path discovery, and disconnect handling are owned by that task and not duplicated here. |
| 30 | +<!-- SECTION:DESCRIPTION:END --> |
| 31 | + |
| 32 | +## Acceptance Criteria |
| 33 | +<!-- AC:BEGIN --> |
| 34 | +- [ ] #1 Sync runs only on macOS (#[cfg(target_os = "macos")]) and only when an iOS device is detected via task-214's detection mechanism |
| 35 | +- [ ] #2 Sync target directory is configurable; default matches the mount path from task-214 (~/Music/Doppler, $HOME expanded at runtime) |
| 36 | +- [ ] #3 Inclusion filter β minimum play count: include tracks where play_count >= N (configurable) |
| 37 | +- [ ] #4 Inclusion filter β last-played age: include tracks played within the last N days (configurable) |
| 38 | +- [ ] #5 Inclusion filter β latest additions: include the N most recently added tracks (configurable) |
| 39 | +- [ ] #6 Total cap β max albums: cap the sync to at most N albums (configurable) |
| 40 | +- [ ] #7 Total cap β max artists: cap the sync to at most N artists (configurable) |
| 41 | +- [ ] #8 Total cap β recency window: include only tracks added or last-played within the last N weeks (configurable) |
| 42 | +- [ ] #9 Total cap β max track count and/or max total bytes (configurable) |
| 43 | +- [ ] #10 Removal rule β last-played age: remove device tracks not played within the last N days (configurable) |
| 44 | +- [ ] #11 Removal rule β date-added age: remove device tracks whose library date-added is more than N days ago (configurable) |
| 45 | +- [ ] #12 Removal rule β min plays: remove device tracks with fewer than N total plays (configurable) |
| 46 | +- [ ] #13 Removal supports a dry-run preview before any destructive file operation is performed |
| 47 | +- [ ] #14 Sync is idempotent: re-running with no rule changes is a no-op (no redundant copies, no mtime/atime churn) |
| 48 | +- [ ] #15 Sync progress and per-track results (added / skipped / removed / failed) are emitted as Tauri events for the frontend to render |
| 49 | +- [ ] #16 Sync configuration is persisted via the settings store and exposed in settings-view.js |
| 50 | +- [ ] #17 Sync engine exposes a Rust API and a Tauri command |
| 51 | +- [ ] #18 Unit tests cover filter composition, cap enforcement, removal logic, and dry-run behavior |
| 52 | +- [ ] #19 User documentation added to docs/ covering rule semantics, defaults, and dry-run workflow |
| 53 | +<!-- AC:END --> |
0 commit comments