Новое изменение: двусторонний миррор альбома устройства и серверного альбома (материализация серверных фото, признак происхождения, двусторонние удаления с явным намерением, устойчивое выключение, первый проход, n:1). Purpose основной спеки phone-album-sync обновлён под двустороннюю синхронизацию. Change проходит `openspec validate --strict`.
22 KiB
phone-album-sync Specification
Purpose
Двусторонняя синхронизация альбома устройства с существующим серверным альбомом (миррор состава): режимы A/B/C, материализация серверных фото на устройстве, отслеживание изменений, идентичность и дедупликация, удаления в обе стороны, разгрузка места и провенанс разгруженных превью.
Requirements
Requirement: Режимы синхронизации альбома устройства
Альбом устройства SHALL иметь выбираемый режим синхронизации: выключена (A — только локально), копии оригиналов на сервере (B), перенос оригиналов на сервер (C). Пока режим A, приложение SHALL показывать альбом локально и SHALL NOT обращаться к серверу по этому альбому.
Scenario: Выключенная синхронизация
- WHEN у альбома устройства выбран режим A
- THEN приложение показывает альбом из локальных файлов и не отправляет запросы на сервер по этому альбому
Scenario: Копии оригиналов
- WHEN у альбома устройства выбран режим B
- THEN оригиналы остаются на устройстве, а их копии загружаются в целевой серверный альбом
Scenario: Перенос оригиналов
- WHEN у альбома устройства выбран режим C
- THEN оригиналы загружаются на сервер, а на устройстве вместо них остаются превью
Requirement: Выбор целевого серверного альбома
При включении синхронизации пользователь SHALL выбрать серверный альбом назначения — существующий или созданный на месте, с именем, предзаполненным именем альбома устройства. Несколько альбомов устройства SHALL иметь возможность указывать на один серверный альбом.
Scenario: Выбор цели
- WHEN пользователь включает синхронизацию альбома устройства
- THEN приложение предлагает выбрать существующий серверный альбом или создать новый с предзаполненным именем и сохраняет выбор
Scenario: Несколько источников в одну цель
- WHEN два альбома устройства указывают на один серверный альбом
- THEN оба синхронизируются в него, а связь каждого отражается отдельно
Requirement: Отслеживание изменений на устройстве
Приложение SHALL отслеживать изменения содержимого синхронизируемого альбома устройства — добавление, удаление, переименование, перенос между альбомами и изменение содержимого — и SHALL хранить локальный индекс, позволяющий обнаружить удаления, произошедшие вне приложения.
Scenario: Добавление
- WHEN в альбоме устройства появляется новое медиа
- THEN приложение фиксирует его как новое и ставит в очередь синхронизации
Scenario: Удаление вне приложения
- WHEN медиа удалено из альбома устройства другим приложением или системной галереей
- THEN приложение обнаруживает отсутствие по локальному индексу
Scenario: Переименование и перенос
- WHEN медиа переименовано или перемещено между альбомами устройства
- THEN приложение фиксирует изменение имени или принадлежности альбому
Requirement: Синхронизация изменений с сервером
Для каждого отслеженного изменения приложение SHALL применить его к целевому серверному альбому: загрузить новое содержимое, переименовать и перенести через API, а изменение содержимого SHALL трактовать как новую загрузку с удалением устаревшей собственной загрузки.
Scenario: Новое содержимое
- WHEN в альбоме устройства появилось медиа, которого нет на сервере
- THEN приложение загружает его в целевой серверный альбом
Scenario: Переименование доходит до сервера
- WHEN медиа переименовано на устройстве и уже синхронизировано
- THEN приложение переименовывает соответствующее серверное фото
Scenario: Изменение содержимого
- WHEN содержимое медиа изменено на устройстве
- THEN приложение загружает новую версию, а устаревшую собственную загрузку удаляет
Requirement: Идентичность по контрольной сумме
Приложение SHALL сопоставлять локальный ассет с серверным фото по контрольной сумме содержимого и SHALL NOT повторно загружать содержимое, уже присутствующее на сервере.
Scenario: Повторная синхронизация
- WHEN синхронизация запускается повторно без изменений содержимого
- THEN приложение не создаёт новых загрузок
Scenario: Уже загруженное содержимое
- WHEN содержимое ассета уже присутствует на сервере (в том числе загружено ранее)
- THEN приложение связывает ассет с существующим серверным фото без загрузки
Requirement: Удаление только собственных загрузок
При удалении содержимого на устройстве приложение SHALL удалять на сервере только фото, загруженные этим клиентом, и SHALL сохранять остальные фото целевого альбома, в том числе загруженные из других источников.
Scenario: Собственная загрузка
- WHEN удалено содержимое, которое загрузил этот клиент, и его контрольная сумма отсутствует во всех локальных альбомах, льющихся в этот серверный
- THEN приложение удаляет соответствующее серверное фото
Scenario: Чужие фото
- WHEN в целевом серверном альбоме есть фото, загруженные из других источников
- THEN приложение не удаляет их
Requirement: Отражение серверных изменений на устройстве
Приложение SHALL отражать изменения целевого серверного альбома — новые фото, переименования, теги, подписи и удаления — в локальном представлении, SHALL NOT изменять или удалять оригиналы на устройстве.
Scenario: Новое с другого устройства
- WHEN другое устройство добавляет фото в целевой серверный альбом
- THEN приложение показывает его в серверном представлении альбома
Scenario: Удалено на сервере
- WHEN серверное фото удалено на сервере
- THEN приложение убирает его из локального представления, не трогая оригинал на устройстве
Requirement: Разгрузка оригиналов в режиме переноса
В режиме C после успешной загрузки приложение SHALL автоматически заменять оригинал на устройстве превью, без отдельного действия на экране; видео SHALL заменяться постером-кадром. При включении режима C приложение SHALL запрашивать широкий доступ к файлам, чтобы замена выполнялась без системного диалога согласия.
Scenario: Разгрузка фото
- WHEN оригинал фото успешно загружен
- THEN файл в галерее автоматически заменяется превью с сохранением даты съёмки и места в альбоме
Scenario: Разгрузка видео
- WHEN оригинал видео успешно загружен
- THEN видео в галерее автоматически заменяется статичным постером-кадром, а элемент в приложении остаётся видео с оригиналом на сервере
Scenario: Доступ к файлам для разгрузки
- WHEN пользователь включает режим переноса
- THEN приложение запрашивает широкий доступ к файлам, и разгрузка выполняется без системного диалога согласия
Requirement: Провенанс разгруженных превью
Разгруженные превью и постеры видео SHALL содержать метаданные провенанса, достаточные для восстановления связи с серверным альбомом и принадлежности загрузок после переустановки приложения.
Scenario: Восстановление после переустановки
- WHEN приложение переустановлено или его данные очищены, а альбом устройства содержит разгруженные превью
- THEN приложение восстанавливает связь с серверным альбомом и принадлежность своих загрузок из метаданных превью
Scenario: Метка утрачена
- WHEN метаданные провенанса недоступны (например, файл перезаписан сторонним редактором)
- THEN элемент считается неопознанным, не удаляется и не загружается повторно
Requirement: Возврат оригиналов и отвязка
При выходе из режима C приложение SHALL предложить вернуть оригиналы на устройство и SHALL предупредить, если пользователь отказывается. Отвязка альбома и выключение синхронизации SHALL NOT удалять фото с сервера.
Scenario: Возврат оригиналов
- WHEN пользователь выходит из режима C и соглашается вернуть оригиналы
- THEN приложение возвращает оригиналы на устройство вместо превью
Scenario: Отказ от возврата
- WHEN пользователь выходит из режима C и отказывается возвращать оригиналы
- THEN приложение предупреждает, что на устройстве останутся только превью
Scenario: Отвязка
- WHEN пользователь отвязывает альбом устройства от серверного
- THEN фото на сервере сохраняются
Scenario: Выключение синхронизации
- WHEN пользователь выключает синхронизацию альбома устройства
- THEN связь с серверным альбомом снимается, а фото на сервере сохраняются
Requirement: Автоматическая фоновая синхронизация
Синхронизация SHALL выполняться автоматически: при открытом приложении — по событиям изменения, в фоне — периодически, с учётом ограничений сети, выбранных пользователем. В режиме C разгрузка оригиналов SHALL выполняться автоматически после успешной загрузки.
Scenario: Фоновая синхронизация
- WHEN приложение не открыто, а в альбоме устройства появились изменения
- THEN синхронизация выполняется в фоне при ближайшей возможности
Scenario: Ограничение сети
- WHEN включено ограничение «только Wi-Fi», а доступна только сотовая сеть
- THEN синхронизация не начинается до появления Wi-Fi
Scenario: Автоматическая разгрузка
- WHEN оригиналы загружены в режиме C
- THEN замена оригиналов превью выполняется автоматически, без отдельного подтверждения
Requirement: Локальные превью
Приложение SHALL генерировать превью на устройстве и хранить их локально; при просмотре элемента без локального оригинала приложение SHALL подгружать оригинал с сервера.
Scenario: Сетка из превью
- WHEN открыт альбом устройства
- THEN сетка показывает локальные превью
Scenario: Просмотр без локального оригинала
- WHEN пользователь открывает элемент, чей оригинал разгружен на сервер
- THEN приложение подгружает оригинал с сервера для полноэкранного просмотра
Requirement: Обнаружение потери серверной копии превью
При проверке синхронизации приложение SHALL сопоставлять серверное фото каждого разгруженного превью с фото целевого альбома и при его отсутствии SHALL помечать элемент как потерявший серверную копию, сохраняя превью и провенанс.
Scenario: Копии больше нет
- WHEN серверное фото разгруженного превью отсутствует в целевом альбоме
- THEN приложение помечает элемент как потерявший серверную копию
Scenario: Превью не трогается
- WHEN элемент помечен как потерявший серверную копию
- THEN превью-файл на устройстве сохраняется и не загружается повторно как оригинал
Requirement: Восстановление связи при возврате серверного фото
При проверке синхронизации приложение SHALL снимать пометку с элемента, если его серверное фото снова присутствует в целевом альбоме.
Scenario: Фото вернулось на сервер
- WHEN серверное фото помеченного элемента снова присутствует в целевом альбоме
- THEN элемент возвращается к обычному разгруженному состоянию с серверной копией
Requirement: Удаление потерянного превью с устройства
Приложение SHALL позволять удалить потерявшее серверную копию превью с устройства; удаление SHALL удалять превью-файл и запись локального индекса и SHALL NOT обращаться к серверу, поскольку копии там уже нет.
Scenario: Удаление с устройства
- WHEN пользователь удаляет потерявшее серверную копию превью с устройства
- THEN превью-файл и запись локального индекса удаляются, а сервер не затрагивается
Scenario: Согласие системы
- WHEN превью-файл не принадлежит приложению
- THEN удаление выполняется после системного согласия на удаление
Requirement: Повторная заливка вернувшегося оригинала
Если содержимое с исходной контрольной суммой потерявшего копию элемента снова присутствует на устройстве, приложение SHALL загрузить его на сервер как новую загрузку этого элемента.
Scenario: Вернулся в тот же альбом
- WHEN оригинал с исходной контрольной суммой снова появился в альбоме устройства
- THEN приложение загружает его в целевой серверный альбом
Scenario: Вернулся в другой альбом
- WHEN содержимое с исходной контрольной суммой присутствует в другом альбоме устройства
- THEN приложение загружает его в целевой серверный альбом
Scenario: Режим переноса
- WHEN загрузка вернувшегося оригинала завершена в режиме переноса
- THEN элемент снова проходит обычную разгрузку в превью
Requirement: Ход и устойчивость восстановления оригиналов
При возврате оригиналов на устройство приложение SHALL выполнять операцию до конца независимо от того, остаётся ли открыт экран альбома устройства, и SHALL сообщать ход: сколько элементов восстановлено из скольких намечено.
Scenario: Уход с экрана
- WHEN восстановление оригиналов запущено и пользователь покидает экран альбома устройства
- THEN восстановление продолжается и завершается
Scenario: Ход операции
- WHEN восстановление оригиналов идёт
- THEN приложение знает и сообщает, сколько элементов уже восстановлено из намеченных
Scenario: Нечего восстанавливать
- WHEN среди элементов альбома нет превью с серверной копией
- THEN операция не запускается и ход не показывается