В спеку phone-album-sync добавлены требования о роли локального файла, подтверждении новой версии до удаления устаревшей и разгрузке без незавершённой загрузки; уточнены синхронизация изменений, провенанс и возврат оригиналов.
41 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 трактоваться как новая загрузка, а устаревшая собственная загрузка SHALL удаляться после подтверждения новой версии и SHALL NOT удаляться из-за смены локальной роли файла (оригинал ↔ превью).
Scenario: Новое содержимое
- WHEN в альбоме устройства появилось медиа, которого нет на сервере
- THEN приложение загружает его в целевой серверный альбом
Scenario: Переименование доходит до сервера
- WHEN медиа переименовано на устройстве и уже синхронизировано
- THEN приложение переименовывает соответствующее серверное фото
Scenario: Изменение содержимого
- WHEN содержимое медиа изменено на устройстве
- THEN приложение загружает новую версию и после её подтверждения удаляет устаревшую собственную загрузку
Requirement: Подтверждение новой версии до удаления устаревшей
Устаревшая собственная загрузка элемента SHALL удаляться только после подтверждения новой версии: сообщённая сервером контрольная сумма принятого объекта SHALL совпадать с отправленной. При расхождении приложение SHALL отклонить загрузку, удалив принятую копию, и SHALL NOT считать элемент загруженным. Если сервер контрольную сумму не сообщил, загрузка SHALL считаться состоявшейся, но устаревшая копия SHALL NOT удаляться, а замена SHALL повториться при следующей синхронизации.
Scenario: Новая версия подтверждена
- WHEN новая версия загружена, а сообщённая сервером контрольная сумма совпала с отправленной
- THEN приложение удаляет устаревшую собственную загрузку (мягко, в корзину)
Scenario: Контрольная сумма не совпала
- WHEN сервер сообщил для принятого объекта контрольную сумму, отличную от отправленной
- THEN приложение удаляет принятую копию, не считает элемент загруженным и оставляет прежнюю серверную копию в альбоме
Scenario: Контрольная сумма не сообщена
- WHEN сервер не сообщил контрольную сумму принятого объекта
- THEN загрузка считается состоявшейся, прежняя серверная копия остаётся в альбоме, а замена повторяется при следующей синхронизации
Scenario: Загрузка не удалась
- WHEN загрузка новой версии завершилась ошибкой
- THEN прежняя серверная копия остаётся в альбоме
Requirement: Идентичность по контрольной сумме
Приложение SHALL сопоставлять локальный ассет с серверным фото по контрольной сумме содержимого и SHALL NOT повторно загружать содержимое, уже присутствующее на сервере.
Scenario: Повторная синхронизация
- WHEN синхронизация запускается повторно без изменений содержимого
- THEN приложение не создаёт новых загрузок
Scenario: Уже загруженное содержимое
- WHEN содержимое ассета уже присутствует на сервере (в том числе загружено ранее)
- THEN приложение связывает ассет с существующим серверным фото без загрузки
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 NOT заменять оригинал превью, пока для этого элемента есть незавершённая загрузка (в очереди или выполняющаяся), чтобы загрузка не отправила превью вместо оригинала.
Scenario: Загрузка в очереди
- WHEN для элемента есть задание загрузки в очереди или выполняющееся
- THEN оригинал на устройстве не заменяется превью
Scenario: Загрузка подтверждена
- WHEN загрузка элемента подтверждена сервером
- THEN приложение выполняет обычную разгрузку в режиме переноса
Requirement: Провенанс разгруженных превью
Разгруженные превью, постеры видео и скачанные с сервера элементы SHALL содержать метаданные провенанса, включая признак происхождения (загружено клиентом или скачано с сервера), достаточные для восстановления связи с серверным альбомом и принадлежности загрузок после переустановки приложения. Метка SHALL также служить признаком того, что локальный файл является созданным приложением превью: элемент с такой меткой SHALL NOT считаться содержащим оригинал, даже если состояние локального индекса утверждает обратное.
Scenario: Восстановление после переустановки
- WHEN приложение переустановлено или его данные очищены, а альбом устройства содержит разгруженные превью
- THEN приложение восстанавливает связь с серверным альбомом и принадлежность своих загрузок из метаданных превью
Scenario: Метка скачанного элемента
- WHEN метка провенанса восстанавливается у элемента, скачанного с сервера
- THEN элемент восстанавливается как скачанный, а не как собственная загрузка клиента
Scenario: Метка утрачена
- WHEN метаданные провенанса недоступны (например, файл перезаписан сторонним редактором)
- THEN элемент считается неопознанным, не удаляется и не загружается повторно
Scenario: Метка против состояния индекса
- WHEN файл несёт метку созданного приложением превью, а состояние индекса указывает оригинал
- THEN элемент считается разгруженным, а не новым оригиналом
Requirement: Роль локального файла не является содержимым
Приложение SHALL отличать превью, созданное им самим при разгрузке (в том числе по метке провенанса), от новой версии оригинала: разгруженный элемент SHALL NOT загружаться повторно и SHALL NOT вызывать удаление серверной копии, а расхождение состояния в локальном индексе SHALL выправляться. Это SHALL относиться и к постеру, которым в режиме переноса заменяется видео.
Scenario: Разгруженный элемент не создаёт новую версию
- WHEN серверная копия элемента есть в целевом альбоме, а на устройстве лежит созданное приложением превью, в том числе если состояние локального индекса ошибочно указывает оригинал
- THEN приложение не ставит загрузку и не удаляет серверную копию
Scenario: Состояние выправляется
- WHEN файл на устройстве является созданным приложением превью, а индекс считает его оригиналом
- THEN приложение помечает элемент как разгруженный и последующие проходы не создают загрузок
Scenario: Постер разгруженного видео
- WHEN видео разгружено (заменено постером под новым элементом MediaStore), а его метка указывает на исходное видео
- 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 связь создаётся заново, а восстановление происхождения снова действует по обычным правилам
Scenario: Возврат устойчив
- WHEN оригиналы возвращены на устройство после выхода из режима переноса
- THEN приложение не разгружает их повторно, пока альбом не переведён в режим переноса снова
Requirement: Автоматическая фоновая синхронизация
Синхронизация SHALL выполняться автоматически в обе стороны: при открытом приложении — по событиям изменения, в фоне — периодически, с учётом ограничений сети, выбранных пользователем. В режиме C разгрузка оригиналов SHALL выполняться автоматически после того, как копия оказалась на сервере.
Scenario: Фоновая синхронизация
- WHEN приложение не открыто, а в альбоме устройства появились изменения
- THEN синхронизация выполняется в фоне при ближайшей возможности
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 операция не запускается и ход не показывается
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 приложение связывает элемент с серверным фото, не создавая второй файл