Files
2026-10-13 17:10:50 +03:00

6.9 KiB

Proposal

Why

Android-клиент работает только с серверными альбомами и ручной загрузкой через системный Photo Picker: он не видит альбомы самого телефона, не следит за их изменениями и не освобождает место. Основной мобильный сценарий — «снимаю на телефон и не думаю о переносе» — не покрыт. Нужна синхронизация альбомов устройства с серверным альбомом в трёх режимах, с отслеживанием изменений.

What Changes

  • Смешанный список альбомов: альбомы устройства (MediaStore bucket'ы) и серверные альбомы в одном списке; связанная пара «телефонный → серверный» показывается одной карточкой устройства с указателем связи и меткой режима, а связанный серверный альбом из списка скрывается.
  • Экран альбома устройства с настройками по свайпу вправо: только выбор режима синхронизации; целевой серверный альбом выбирается (или создаётся) при включении, допускается n:1.
  • Три режима синхронизации альбома:
    • A — выключена: оригиналы на телефоне, превью генерируются и хранятся на телефоне; сервера не касается.
    • B — копии оригиналов: оригиналы остаются на телефоне, копии загружаются на сервер.
    • C — перенос оригиналов: оригиналы уходят на сервер, на телефоне вместо них остаются превью; замена файла в галерее выполняется автоматически (широкий доступ к файлам запрашивается при включении режима, без системного диалога); видео заменяется постером.
  • Отслеживание и синхронизация изменений (добавление, удаление, переименование, перенос между альбомами, правка контента как «новый + удалить старый») автоматически в фоне (MediaStore.getGeneration/ContentObserver + периодический WorkManager) и при открытом приложении (SSE + ?since=).
  • Идентичность и дедупликация по content-hash (sha256) относительно контрольной суммы объекта на сервере; удаление на сервере — только для «наших» загрузок.
  • Провенанс, переживающий переустановку: в EXIF разгруженных в C превью пишется метка (серверный альбом/фото, hash оригинала), по которой связь и провенанс восстанавливаются.
  • Возврат оригиналов из C («вернуть оригиналы»); отвязка и выключение синхронизации никогда не удаляют фотографии с сервера.
  • Сервер начинает отдавать контрольную сумму оригинала в данных фото (малая правка API, без миграции БД — checksum уже хранится).
  • BREAKING: нет (добавляемое поле ответа; существующие клиенты не ломаются).

Capabilities

New Capabilities

  • phone-album-sync: синхронизация альбома устройства с существующим серверным альбомом — режимы A/B/C, отслеживание изменений, идентичность и дедуп по content-hash, политика удалений, разгрузка места и провенанс.

Modified Capabilities

  • android-client: смешанный список альбомов устройства и сервера, экран и настройки синхронизации телефонного альбома, широкий доступ к медиа (READ_MEDIA_*) и фоновая работа синхронизации.
  • photos: данные фото включают контрольную сумму оригинала, чтобы клиент мог сопоставлять локальный ассет с серверным фото и не загружать дубли.

Impact

  • android/: новый источник MediaStore (bucket'ы и ассеты), движок синхронизации и очередь на существующем UploadRepository/UploadWorker, локальный индекс и провенанс в Room, кэш превью, EXIF-метка, чтение/запись превью (широкий доступ к файлам MANAGE_EXTERNAL_STORAGE), правки навигации (GaloNavHost), манифеста (права) и AppContainer.
  • backend/: отдать checksum в моделях/запросах/ответах фото. Миграции БД не требуются.
  • Зависимости клиента: MediaStore, ExifInterface, MediaMetadataRetriever, WorkManager, Room, Coil — большинство уже подключено.
  • Платформенные ограничения: согласие ОС на изменение/удаление чужого медиа; фоновая работа ограничена WorkManager; Google Play ограничивает READ_MEDIA_*.
  • Предпосылка (побочно, вне объёма этой правки): .gitignore содержит правило data/, из-за которого весь Kotlin-слой android/.../com/galo/android/data/ не отслеживается git и отсутствует в git-истории. До реализации это нужно устранить, иначе новые файлы синхронизации тоже не попадут в коммит.
  • Вне объёма: iOS; синхронизация на уровне сервера (устройства/сессии на бэкенде); многопользовательские конфликты владения; редактирование изображений.