Дельта-спеки перенесены в основные: phone-album-sync (+8 требований, 6 изменено, 1 удалено — «Удаление только собственных загрузок»), android-client. Change перемещён в openspec/changes/archive/2026-10-16-phone-album-two-way-sync.
7.5 KiB
7.5 KiB
Tasks
1. Модель индекса и провенанс
- 1.1 Добавить в
DeviceAssetEntityпризнак происхождения (OWN|MIRROR) и Room-миграцию сOWNдля существующих строк; проверить миграционным тестомandroid/app/src/test(или instrumented), что старая база открывается без потери строк - 1.2 Добавить таблицу надгробий (photoId, момент, состояние) и watermark первого прохода в Room с миграцией; проверить тестом DAO на вставку/чтение/снятие надгробия
- 1.3 Расширить
ProvenanceStampпризнаком происхождения; проверить юнит-тестом encode/decode и тестомSyncRecovery, что скачанный элемент восстанавливается какMIRROR, а не какOWN
2. Конвейер материализации
- 2.1 Реализовать загрузчик объекта по подписанному URL (
original_urlдля B,preview_url/medium_urlдля C, постер для видео); проверить юнит-тестом на выбор URL и обработку ошибок сети - 2.2 Реализовать запись файла в бакет альбома устройства (уникальное имя,
DATE_TAKENизtaken_at, метка происхождения); проверить instrumented-тестом, что файл появляется в MediaStore нужного бакета с датой - 2.3 Реализовать дедуп перед вставкой: если содержимое уже на устройстве — связать элемент, не создавая файл; проверить тестом планировщика, что второго файла нет
- 2.4 Реализовать правило n:1 — материализация ровно в один выбранный бакет; проверить тестом, что при двух связанных бакетах файл создаётся в одном
3. Двусторонний планировщик
- 3.1 Реализовать дельту серверных фото (
?since=/курсор) с учётом watermark и ограничения «только Wi-Fi»; проверить тестом, что при «только новое» существующий состав не скачивается, а новое — скачивается - 3.2 Реализовать планирование материализации по режиму (B — оригинал, C — превью); проверить тестами
SyncPlanner: режим копий → оригинал, режим переноса → превью - 3.3 Реализовать двустороннее удаление с учётом прав и надгробий (локальное → в корзину сервера, серверное → снятие локального, 403 не роняет проход); проверить тестами: идемпотентность, эхо, отказ прав
- 3.4 Реализовать рематериализацию при восстановлении серверного фото из корзины; проверить тестом, что элемент возвращается в альбом устройства
- 3.5 Реализовать отвязку и выключение синхронизации так, чтобы серверные фото и скачанные файлы сохранялись; проверить тестом, что после отвязки файлы остаются и сервер не затронут
4. Интерфейс
- 4.1 Включить скачанные элементы в сетку альбома устройства и обновлять её по завершении прохода; проверить UI-тестом, что новое серверное фото появляется, а удалённое исчезает без ручного действия
- 4.2 Добавить при включении синхронизации выбор «только новое» / «скачать всё» с сохранением выбора; проверить UI-тестом, что выбор влияет на первый проход
5. Интеграция и документация
- 5.1 Проверить сквозной сценарий: фото, добавленное в веб-интерфейсе, материализуется на устройстве; удаление с устройства убирает его на сервере; удаление на сервере убирает локальный элемент; проверить e2e-тестом на эмуляторе
- 5.2 Обновить Purpose спеки
phone-album-sync(двусторонний миррор вместо односторонней синхронизации) и убедиться, чтоopenspec validate phone-album-two-way-sync --strictпроходит
6. Устойчивость выключения синхронизации
- 6.1 Записать явный признак «синхронизация выключена» при отвязке/выключении и блокировать им восстановление происхождения; повторное включение снимает признак; проверить unit-тестами
SyncRepositoryTestиSyncRecoveryTest - 6.2 Добавить instrumented-тест всех режимов и переключений (A/B/C, B→C, C→B, C→A, B→A, A→B, восстановление) и прогнать на эмуляторе
- 6.3 Вынести объёмную нагрузку (100 фото + 20 видео на тест) в отдельный
SyncVolumeE2ETest, а функциональные тесты держать малыми; проверить на эмуляторе - 6.4 Очередь загрузки: одно дренирующее WorkManager-задание вместо задания на каждый файл (иначе JobScheduler перестаёт запускать оставшиеся задания); проверить заливкой 120 файлов на эмуляторе
- 6.5 Производительность: дебаунс
DeviceMediaObserverи кэш sha256 по(size, dateModified); проверить unit-набором и малыми наборами - 6.6 Корректность: неудачное чтение серверного списка не считается пустым альбомом (иначе удалялись локальные зеркала); проверить unit-тестом
a failed album read does not delete local mirrors - 6.7 Удаление зеркал: намерением считается только явное удаление в приложении (надгробие → удаление на сервере); пропавшая локальная копия материализуется заново; проверить unit-тестами и instrumented-тестом
explicitDeleteOfAMirrorRemovesTheServerPhoto
Workflow follow-up
- Archive the change after the project's review requirements are satisfied.