Дельта-спеки перенесены в основные: phone-album-sync (+8 требований, 6 изменено, 1 удалено — «Удаление только собственных загрузок»), android-client. Change перемещён в openspec/changes/archive/2026-10-16-phone-album-two-way-sync.
21 KiB
Spec Delta
MODIFIED Requirements
Requirement: Отражение серверных изменений на устройстве
Приложение SHALL приводить локальное представление целевого серверного альбома в соответствие с его составом: новое серверное фото SHALL материализоваться на устройстве (оригинал в режиме копий, превью в режиме переноса), переименования, теги и подписи SHALL отражаться, а серверное удаление SHALL убирать локальный элемент. Удаление снятого на устройстве оригинала SHALL учитывать права сервера и системное согласие.
Scenario: Новое с другого устройства
- WHEN другое устройство добавляет фото в целевой серверный альбом
- THEN приложение материализует его в альбоме устройства — оригинал в режиме копий, превью в режиме переноса
Scenario: Удалено на сервере
- WHEN серверное фото удалено на сервере
- THEN приложение убирает соответствующий локальный элемент, а для снятого на устройстве оригинала запрашивается системное согласие на удаление
Requirement: Разгрузка оригиналов в режиме переноса
В режиме C после того, как оригинал элемента оказывается на сервере (загружен этим клиентом или скачан при двусторонней синхронизации), приложение SHALL автоматически заменять оригинал на устройстве превью, без отдельного действия на экране; видео SHALL заменяться постером-кадром. При включении режима C приложение SHALL запрашивать широкий доступ к файлам, чтобы замена выполнялась без системного диалога согласия.
Scenario: Разгрузка фото
- WHEN оригинал фото успешно загружен
- THEN файл в галерее автоматически заменяется превью с сохранением даты съёмки и места в альбоме
Scenario: Разгрузка скачанного оригинала
- WHEN альбом переключён в режим переноса, а оригинал элемента был скачан с сервера
- THEN оригинал автоматически заменяется превью
Scenario: Разгрузка видео
- WHEN оригинал видео успешно загружен
- THEN видео в галерее автоматически заменяется статичным постером-кадром, а элемент в приложении остаётся видео с оригиналом на сервере
Scenario: Доступ к файлам для разгрузки
- WHEN пользователь включает режим переноса
- THEN приложение запрашивает широкий доступ к файлам, и разгрузка выполняется без системного диалога согласия
Requirement: Провенанс разгруженных превью
Разгруженные превью, постеры видео и скачанные с сервера элементы SHALL содержать метаданные провенанса, включая признак происхождения (загружено клиентом или скачано с сервера), достаточные для восстановления связи с серверным альбомом и принадлежности загрузок после переустановки приложения.
Scenario: Восстановление после переустановки
- WHEN приложение переустановлено или его данные очищены, а альбом устройства содержит разгруженные превью
- THEN приложение восстанавливает связь с серверным альбомом и принадлежность своих загрузок из метаданных превью
Scenario: Метка скачанного элемента
- WHEN метка провенанса восстанавливается у элемента, скачанного с сервера
- THEN элемент восстанавливается как скачанный, а не как собственная загрузка клиента
Scenario: Метка утрачена
- WHEN метаданные провенанса недоступны (например, файл перезаписан сторонним редактором)
- THEN элемент считается неопознанным, не удаляется и не загружается повторно
Requirement: Возврат оригиналов и отвязка
При выходе из режима C приложение SHALL предложить вернуть оригиналы на устройство и SHALL предупредить, если пользователь отказывается. Отвязка альбома и выключение синхронизации SHALL NOT удалять фото с сервера, а скачанные с сервера файлы SHALL оставаться в галерее как обычные. Выключение синхронизации SHALL быть явным и устойчивым: восстановление происхождения SHALL NOT возобновлять связь, пока пользователь не включит синхронизацию снова.
Scenario: Возврат оригиналов
- WHEN пользователь выходит из режима C и соглашается вернуть оригиналы
- THEN приложение возвращает оригиналы на устройство вместо превью
Scenario: Отказ от возврата
- WHEN пользователь выходит из режима C и отказывается возвращать оригиналы
- THEN приложение предупреждает, что на устройстве останутся только превью
Scenario: Отвязка
- WHEN пользователь отвязывает альбом устройства от серверного
- THEN фото на сервере сохраняются, а скачанные файлы остаются в галерее как обычные
Scenario: Выключение синхронизации
- WHEN пользователь выключает синхронизацию альбома устройства
- THEN связь с серверным альбомом снимается, а фото на сервере сохраняются
Scenario: Выключение не отменяется восстановлением
- WHEN пользователь выключил синхронизацию (или отвязал альбом), и затем выполняется проверка с восстановлением происхождения по меткам превью
- THEN связь не восстанавливается, а альбом остаётся локальным с выбранным режимом выключено
Scenario: Повторное включение
- WHEN пользователь снова включает синхронизацию после выключения
- THEN связь создаётся заново, а восстановление происхождения снова действует по обычным правилам
Requirement: Автоматическая фоновая синхронизация
Синхронизация SHALL выполняться автоматически в обе стороны: при открытом приложении — по событиям изменения, в фоне — периодически, с учётом ограничений сети, выбранных пользователем. В режиме C разгрузка оригиналов SHALL выполняться автоматически после того, как копия оказалась на сервере.
Scenario: Фоновая синхронизация
- WHEN приложение не открыто, а в альбоме устройства появились изменения
- THEN синхронизация выполняется в фоне при ближайшей возможности
Scenario: Фоновая загрузка серверных фото
- WHEN приложение не открыто, а в целевом серверном альбоме появилось новое фото
- THEN приложение материализует его на устройстве при ближайшей возможности
Scenario: Ограничение сети
- WHEN включено ограничение «только Wi-Fi», а доступна только сотовая сеть
- THEN синхронизация, включая скачивание серверных фото, не начинается до появления Wi-Fi
Scenario: Автоматическая разгрузка
- WHEN оригиналы загружены в режиме C
- THEN замена оригиналов превью выполняется автоматически, без отдельного подтверждения
REMOVED Requirements
Requirement: Удаление только собственных загрузок
Reason: двусторонний миррор заменяет одностороннюю политику: удаление элемента на устройстве теперь доводится до сервера, а серверное удаление убирает локальный элемент; разграничение идёт по правам сервера и признаку происхождения, а не по «своё/чужое».
Migration: поведение описано требованиями «Двустороннее удаление элементов», «Признак происхождения элемента» и «Журнал удалений и защита от эха».
ADDED Requirements
Requirement: Материализация серверных фото на устройстве
При появлении фото в целевом серверном альбоме приложение SHALL материализовать его на устройстве, записав файл в галерею (MediaStore) бакета альбома устройства: в режиме копий — оригинал, в режиме переноса — превью, для видео — постер. Файл SHALL содержать метку происхождения и дату съёмки серверного фото.
Scenario: Материализация в режиме копий
- WHEN в целевом серверном альбоме появилось новое фото, а альбом устройства в режиме копий
- THEN приложение скачивает оригинал и создаёт файл в бакете альбома устройства
Scenario: Материализация в режиме переноса
- WHEN в целевом серверном альбоме появилось новое фото, а альбом устройства в режиме переноса
- THEN приложение скачивает превью и создаёт файл в бакете альбома устройства
Scenario: Материализация видео
- WHEN в целевом серверном альбоме появилось видео
- THEN приложение создаёт в бакете постер-кадр, а оригинал остаётся на сервере
Scenario: Дата съёмки
- WHEN приложение материализует серверное фото
- THEN файл получает дату съёмки из серверных метаданных фото
Requirement: Признак происхождения элемента
Каждый элемент альбома устройства SHALL иметь явный признак происхождения: загружено этим клиентом или скачано с сервера. Политика удалений, разгрузка и восстановление SHALL опираться на признак, а не на наличие серверной ссылки.
Scenario: Скачанный элемент не считается своей загрузкой
- WHEN элемент скачан с сервера при двусторонней синхронизации
- THEN он помечается как скачанный, а не как загруженный этим клиентом
Requirement: Двустороннее удаление элементов
Удаление элемента в альбоме устройства SHALL удалять соответствующее фото на сервере (мягко, в корзину), а серверное удаление SHALL убирать локальный элемент. Для материализованного (серверного) элемента намерением считается только явное удаление в приложении: пропавшая локальная копия SHALL NOT удалять серверное фото, а SHALL материализоваться заново. Операция SHALL подчиняться правам сервера, а удаление файла, снятого на устройстве, SHALL требовать системного согласия.
Scenario: Удаление на устройстве
- WHEN пользователь удаляет элемент синхронизированного альбома устройства
- THEN приложение помещает соответствующее серверное фото в корзину
Scenario: Удаление на сервере
- WHEN серверное фото помещено в корзину
- THEN приложение убирает соответствующий локальный элемент
Scenario: Пропала локальная копия серверного фото
- WHEN локальная копия материализованного серверного фото исчезла (очистка галереи, перемещение файла)
- THEN приложение материализует фото заново и SHALL NOT удалять его на сервере
Scenario: Явное удаление в приложении
- WHEN пользователь удаляет материализованное серверное фото из приложения
- THEN приложение помечает намерение и удаляет фото на сервере
Scenario: Нет прав на серверное удаление
- WHEN пользователь удаляет элемент, а роль на сервере не позволяет удалить это фото
- THEN серверное удаление отклоняется, приложение не считает операцию успешной и сообщает об этом
Requirement: Журнал удалений и защита от эха
Локально удалённый элемент SHALL помечаться в журнале удалений, чтобы приложение SHALL NOT материализовать его повторно до подтверждения серверного удаления. Повторные и эхо-события удаления SHALL быть идемпотентны.
Scenario: Удаление ещё не подтверждено сервером
- WHEN элемент удалён на устройстве, а серверное удаление ещё не выполнено
- THEN при следующем проходе приложение не материализует этот элемент заново
Scenario: Эхо серверного события
- WHEN серверное событие удаления относится к уже удалённому локальному элементу
- THEN приложение ничего не меняет повторно
Requirement: Восстановление элемента из корзины
Если серверное фото, удалённое с устройства, восстановлено из корзины сервера, приложение SHALL снова материализовать соответствующий элемент на устройстве.
Scenario: Фото вернулось из корзины
- WHEN пользователь восстанавливает серверное фото из корзины
- THEN приложение материализует соответствующий элемент в альбоме устройства
Requirement: Первый проход и ограничение скачивания
При включении синхронизации приложение SHALL предложить выбрать: скачать всё содержимое целевого серверного альбома или только новое с этого момента. Скачивание SHALL подчиняться ограничению «только Wi-Fi»; при ожидании подходящей сети материализация не начинается.
Scenario: Только новое
- WHEN пользователь выбирает «только новое» при включении синхронизации
- THEN уже существующее содержимое серверного альбома не скачивается, а материализуются только последующие появления
Scenario: Скачать всё
- WHEN пользователь выбирает «скачать всё» при включении синхронизации
- THEN приложение материализует весь текущий состав серверного альбома
Scenario: Ожидание WiFi
- WHEN включено ограничение «только Wi-Fi», а доступна только сотовая сеть
- THEN скачивание не начинается до появления Wi-Fi
Requirement: Материализация при нескольких источниках
Когда несколько альбомов устройства указывают на один серверный альбом, приложение SHALL материализовать серверное фото ровно в один из них, чтобы не создавать дубликат в галерее. Выбор целевого бакета SHALL сохраняться. Содержимое, уже присутствующее на устройстве, SHALL NOT дублироваться.
Scenario: Несколько источников в одну цель
- WHEN два альбома устройства синхронизируются с одним серверным альбомом, и в нём появляется фото
- THEN приложение создаёт файл ровно в одном из бакетов
Scenario: Содержимое уже на устройстве
- WHEN появившееся серверное фото по содержимому уже присутствует на устройстве
- THEN приложение связывает элемент с серверным фото, не создавая второй файл