Files
iu 7ae9bcf305 chore(openspec): archive media-object-layer and sync main specs
- move change media-object-layer to openspec/changes/archive/2026-10-10-media-object-layer
- add main spec specs/media-objects (opaque keys, object journal, shared
  objects, reference-based GC, lifecycle recovery, variant generation queue)
- update specs/photos deletion requirement to place photos in the trash
  without deleting storage objects
2026-10-10 23:32:21 +03:00

4.8 KiB

Tasks

1. Схема и миграции

  • 1.1 Добавить миграцию, создающую objects, photo_objects (PK photo_id,role, индекс object_id) и variant_jobs; проверить, что make migrate применяется и таблицы видны в БД
  • 1.2 Добавить миграцию, удаляющую photos.storage_key, photos.thumb_key, photos.preview_key, photos.size, photos.width, photos.height, photos.mime_type; проверить, что up и down миграции проходят в обе стороны без ошибок

2. Слой хранения

  • 2.1 Удалить DeletePrefix из internal/storage/storage.go; проверить go build ./... и отсутствие вызовов метода в коде
  • 2.2 Ввести хелпер ключа объекта вида objects/{id}/{role}.{ext} без идентификатора альбома; покрыть юнит-тестом, что ключ не содержит album_id

3. Метаданные объектов

  • 3.1 Реализовать стор объектов: создание pending, активация ready, пометка deleting, удаление строки, выборка pending старше порога; покрыть тестами переходы состояний
  • 3.2 Реализовать привязку photo_objects с блокировкой объекта FOR UPDATE и отказом при state != 'ready'; тест на повторную привязку одного объекта к двум фото
  • 3.3 Реализовать запрос GC (объекты ready без связок) и тесты сценариев «последняя ссылка удалена» и «остались ссылки»

4. Сервис фото

  • 4.1 Переписать Upload: строка объекта pending → S3 Put → ready → привязка original + задание в variant_jobs; тест, что загрузка даёт фото с URL оригинала и ключом без альбома
  • 4.2 Переписать List/Get/attachURLs на вывод ключей и size/width/height/mime_type джойном к объекту-оригиналу; тест, что JSON-поля и URL присутствуют как раньше
  • 4.3 Переписать CopyBatch/MoveBatch на работу только через связки; тест, что объекты хранилища не меняются и делятся между фото
  • 4.4 Переписать PermanentDelete: удалить связки и пометить осиротевшие объекты deleting; тест, что объект с нулём ссылок становится кандидатом на GC
  • 4.5 Убрать обращения к удалённым колонкам во всех запросах и моделях; проверить go build ./... и прохождение internal/repo тестов

5. Фоновый воркер

  • 5.1 Реализовать цикл забора variant_jobs через FOR UPDATE SKIP LOCKED, генерацию thumb/preview, привязку и публикацию SSE; тест обработки задания и повтора при ошибке
  • 5.2 Реализовать в воркере удаление deleting (с повторной проверкой нуля ссылок) и досасывание зависших pending; тест повторной попытки S3 Delete и очистки pending
  • 5.3 Встроить старт/останов воркера в жизненный цикл приложения; проверить, что сервер запускается и воркер выполняет петлю (по логам/интеграционному тесту)

6. Интеграция и документация

  • 6.1 Перевести обложку альбома (CoverThumbKey) на вывод через photo_objects+objects; тест, что список альбомов отдаёт URL обложки
  • 6.2 Обновить project.md §10 (структура в S3 и слои); проверить, что описание совпадает с реализованными ключами
  • 6.3 Сквозная проверка: загрузка → генерация вариантов → копирование между альбомами (0 операций S3) → перенос → окончательное удаление → сборка объектов; проверить, что объекты удаляются только при нуле ссылок