Files
ds-galo/openspec/changes/safe-album-offload/proposal.md
T
iu 1eb1177273 feat(android): статус синхронизации на карточке и безопасная разгрузка
Карточка альбома устройства получает третью строку: метку режима («Копии»/
«Перенос») и ход загрузки. Процент считается как (uploaded + running) / total
для обоих синхронизируемых режимов, пульсирует только при активной загрузке,
показывает очередь, ожидание Wi-Fi и ошибку. В режиме переноса карточка
показывает и карту памяти, и облако — режимы различает метка, а не значки.

Разгрузка оригиналов теперь требует подтверждённой серверной копии в текущем
целевом альбоме: устаревший serverPhotoId перепроверяется по альбому, смена
цели переносит уже загруженные фото и отклоняется, если перенести нельзя.
Потеря серверной копии видна на карточке и на экране альбома, автозатирания
превью нет.

Изменения OpenSpec: android-album-card-sync-status, safe-album-offload.
2026-10-16 18:36:51 +03:00

5.6 KiB

Proposal

Why

Реальный инцидент: альбом устройства U2 синхронизировался в режиме переноса в серверный альбом A (фото загружены, локальные оригиналы заменены превью), затем альбом A удалили на сервере, а альбом устройства перепривязали к новому серверному альбому U2. В U2 уехало всего 1 фото: остальные на телефоне уже были превью, и загрузить их заново было нечем. Оригиналы остались только в корзине сервера, а приложение молча оставило телефон с превью.

Три причины:

  • решение о разгрузке принимается по serverPhotoId в локальном индексе, без проверки, что это фото вообще есть в текущем целевом альбоме;
  • смена целевого альбома только перезаписывает связь: уже загруженные фото никто не переносит на сервере, а из превью повторно не загрузить;
  • потеря серверной копии — тихий тупик: ORPHANED виден, но нигде не сказано, что оригинал утрачен, и нет явного предупреждения.

What Changes

  • Доверие только к живой копии. Записанный serverPhotoId считается действительным, только если это фото присутствует в целевом альбоме. Если копии нет: при локальном оригинале ассет загружается заново, при одном превью элемент помечается потерявшим копию.
  • Разгрузка только под защитой. Замена оригинала превью выполняется, только если копия подтверждена в целевом альбоме; разгрузка «по памяти индекса» запрещена. Автоматическая разгрузка в режиме переноса сохраняется.
  • Смена цели переносит копии. При смене целевого альбома приложение сначала переносит на сервере уже загруженные этим альбомом устройства фото в новый альбом и переключает связь только если перенос удался; иначе связь не меняется и пользователь получает отказ.
  • Потеря копии видна. Экран альбома устройства и карточка альбома в списке показывают, сколько фото осталось без серверной копии; никакого автоматического удаления превью.
  • BREAKING: нет. Меняются только защитные условия; успешные сценарии (загрузка, разгрузка, повторная синхронизация) сохраняют поведение.

Capabilities

New Capabilities

Нет — поведение относится к существующим способностям.

Modified Capabilities

  • phone-album-sync: разгрузка требует живой копии в текущем целевом альбоме; записанный serverPhotoId перепроверяется по целевому альбому; смена целевого альбома переносит уже загруженные фото и отклоняется, если перенести нельзя.
  • android-client: потеря серверной копии показывается на экране альбома устройства и на карточке в списке; автоматического удаления превью нет.

Impact

  • Код (Android): data/sync/SyncPlan (доверие к живой копии), data/sync/SyncCoordinator (защищённая разгрузка, перенос при смене цели), data/sync/OffloadManager (условие разгрузки), data/upload/UploadWorker (передача живой копии после загрузки), data/db/dao/SyncDao и data/repo/SyncRepository (счёт потерянных копий), ui/devicealbum/DeviceAlbumViewModel (смена цели, разгрузка, предупреждение), ui/devicealbum/DeviceAlbumScreen (баннер), domain/sync/AlbumSyncProgress и ui/albums/* (сигнал на карточке).
  • Схема Room: без изменений; добавляются только запросы.
  • API и бэкенд: не затрагиваются (используется существующий /api/photo-batch/move).
  • Веб-клиент: не затрагивается.
  • Не затрагивается: ручные загрузки в серверный альбом; восстановление уже потерянных копий из корзины сервера (по решению пользователя это отдельная задача).