Files
ds-galo/openspec/specs/photos/spec.md
T

16 KiB
Raw Blame History

photos Specification

Purpose

Загрузка, хранение в S3 и просмотр фотографий с генерацией вариантов и извлечением EXIF.

Requirements

Requirement: Загрузка фото

Пользователь с правом загрузки SHALL иметь возможность загружать медиа (изображения и видео) по одному и массово; система SHALL принимать ввод image/* и video/*.

Scenario: Успешная загрузка

  • WHEN участник с правом загрузки отправляет файл изображения
  • THEN система сохраняет оригинал и создаёт запись фото с метаданными

Scenario: Успешная загрузка видео

  • WHEN участник с правом загрузки отправляет видеофайл
  • THEN система сохраняет оригинал и создаёт медиа-запись с признаком видео

Scenario: Загрузка без права

  • WHEN наблюдатель пытается загрузить фото
  • THEN система отклоняет запрос

Scenario: Неподдерживаемый файл

  • WHEN загружается файл, не являющийся изображением или видео
  • THEN система отклоняет загрузку

Requirement: Варианты изображений

Система SHALL генерировать четыре варианта: thumb (200×200, квадратный кроп), medium (800×800, квадратный кроп), preview (1200×1200, вписанный) и оригинал, в WebP, и извлекать EXIF (дата, координаты, размеры).

Scenario: Генерация вариантов

  • WHEN фото загружено
  • THEN система асинхронно генерирует thumb, medium и preview и заполняет EXIF-поля

Scenario: Форма вариантов сетки

  • WHEN генерируются thumb и medium
  • THEN они обрезаны до квадрата, а preview вписан с сохранением пропорций

Requirement: Листинг фото с пагинацией

Система SHALL возвращать фото альбома с cursor-пагинацией.

Scenario: Пагинация по курсору

  • WHEN клиент запрашивает список с курсором и лимитом
  • THEN система возвращает не более лимита фото и курсор следующей страницы

Requirement: Получение фото по требованию

Клиент SHALL иметь возможность получить актуальные данные фото с подписанным URL, обслуживаемым бэкендом, независимо от бэкенда хранения. Подпись SHALL быть детерминированной в пределах окна действия, чтобы повторные выдачи одного и того же объекта давали идентичный URL.

Scenario: Выдача свежего URL

  • WHEN клиент запрашивает фото по id
  • THEN система возвращает подписанный URL бэкенда для просмотра

Scenario: Повторная выдача совпадает

  • WHEN один и тот же объект запрашивается повторно в пределах окна действия подписи
  • THEN система возвращает идентичный URL

Requirement: Скачивание одиночного фото

Любой участник, включая viewer, SHALL иметь возможность скачать одиночное фото.

Scenario: Скачивание фото

  • WHEN участник запрашивает скачивание фото
  • THEN система возвращает подписанный URL оригинала, обслуживаемый бэкендом

Requirement: Удаление фото

Автор SHALL иметь возможность удалить своё фото; владелец и админ SHALL иметь возможность удалить любое фото. Удаление SHALL помещать фото в корзину и SHALL не удалять объекты хранилища.

Scenario: Удаление своего фото

  • WHEN автор удаляет своё фото
  • THEN фото помещается в корзину, а объекты хранилища сохраняются

Scenario: Удаление чужого фото участником

  • WHEN участник с ролью member пытается удалить чужое фото
  • THEN система отклоняет запрос

Requirement: Обложка по умолчанию

При загрузке фото система SHALL назначать его обложкой альбома, если обложка ещё не задана, то есть обложкой становится первое загруженное фото. Когда фото, выбранное обложкой, покидает альбом (помещено в корзину или перенесено в другой альбом), система SHALL снять обложку.

Scenario: Первое фото

  • WHEN фото загружено, и у альбома нет обложки
  • THEN система назначает это фото обложкой альбома

Scenario: Обложка уже задана

  • WHEN фото загружено, а обложка уже задана
  • THEN система не меняет обложку

Scenario: Фото-обложка в корзине

  • WHEN фото, назначенное обложкой, помещается в корзину
  • THEN система снимает обложку, и альбом отображается без обложки

Scenario: Фото-обложка перенесено

  • WHEN фото, назначенное обложкой, переносится в другой альбом
  • THEN система снимает обложку исходного альбома

Requirement: Переименование фото

Автор фото, владелец и админ альбома SHALL иметь возможность изменить имя файла фото; остальные SHALL получать отказ, а пустое имя SHALL отклоняться.

Scenario: Переименование автором

  • WHEN автор меняет имя файла своего фото на непустое
  • THEN система сохраняет новое имя и транслирует изменение подписчикам альбома

Scenario: Пустое имя

  • WHEN пользователь подтверждает пустое имя файла
  • THEN система отклоняет запрос

Scenario: Нет прав

  • WHEN участник без прав переименовывает чужое фото
  • THEN система отклоняет запрос

Requirement: Ограничение размера загрузки

Система SHALL ограничивать размер загружаемых файлов отдельно для изображений и видео и SHALL отвечать понятной ошибкой при превышении лимита, а не ошибкой разбора формы.

Scenario: Превышение лимита

  • WHEN загружаемый файл превышает максимальный размер
  • THEN система отклоняет загрузку с явной ошибкой о превышении размера

Scenario: Превышение лимита видео

  • WHEN загружаемое видео превышает лимит видео
  • THEN система отклоняет загрузку с явной ошибкой о превышении размера

Scenario: Файл в пределах лимита

  • WHEN файл не превышает лимит
  • THEN система принимает multipart-загрузку и обрабатывает фото

Requirement: Метаданные фото (EXIF)

При загрузке фото система SHALL извлекать распознаваемые EXIF-атрибуты и SHALL возвращать их вместе с данными фото; при отсутствии метаданных SHALL возвращать пустой набор.

Scenario: Фото с метаданными

  • WHEN загружается фото с EXIF
  • THEN данные фото содержат извлечённые атрибуты (камера, экспозиция, ISO, дата съёмки и др.)

Scenario: Фото без метаданных

  • WHEN загружается фото без читаемых EXIF
  • THEN данные фото не содержат атрибутов, а загрузка выполняется успешно

Requirement: Перенос и копирование фото между альбомами

Пользователь с правом удаления в исходном альбоме и правом загрузки в целевом SHALL иметь возможность перенести или скопировать фото в другой альбом. Операции SHALL изменять только метаданные и SHALL не изменять объекты хранилища.

Scenario: Перенос

  • WHEN пользователь переносит фото в другой альбом
  • THEN фото исчезает из исходного альбома и появляется в целевом, объекты хранилища не меняются

Scenario: Копирование

  • WHEN пользователь копирует фото в другой альбом
  • THEN в целевом альбоме появляется новая запись, ссылающаяся на те же объекты хранилища

Requirement: Корзина фото

Удаление фото SHALL помещать его в корзину (мягкое удаление). Восстановление SHALL возвращать фото в его альбом. Окончательное удаление SHALL удалять запись, а объекты хранилища SHALL удаляться только когда на них не остаётся ссылок ни в одном альбоме.

Scenario: Удаление в корзину

  • WHEN пользователь удаляет фото
  • THEN фото пропадает из альбома и появляется в корзине

Scenario: Восстановление

  • WHEN пользователь восстанавливает фото из корзины
  • THEN фото возвращается в свой альбом

Scenario: Окончательное удаление без ссылок

  • WHEN пользователь удаляет фото из корзины навсегда, и на те же объекты нет ссылок в других альбомах
  • THEN запись и объекты хранилища удаляются

Scenario: Окончательное удаление при наличии ссылок

  • WHEN на объект хранилища ссылается копия в другом альбоме
  • THEN запись удаляется, а объект хранилища сохраняется

Requirement: Удаление альбома и восстановление фото без альбома

Удаление альбома SHALL помещать его фото в корзину, не удаляя объекты хранилища. Если при восстановлении фото его альбом отсутствует, система SHALL предложить выбрать существующий альбом или создать новый.

Scenario: Удаление альбома

  • WHEN владелец удаляет альбом
  • THEN его фото оказываются в корзине без привязки к альбому, файлы сохраняются

Scenario: Восстановление без альбома

  • WHEN пользователь восстанавливает фото, у которого нет альбома
  • THEN система предлагает выбрать альбом или создать новый и восстанавливает фото в него

Requirement: Метки фото

Пользователь SHALL присваивать фото свои метки (область — пользователь): создавать новые и выбирать из списка с поиском; метки SHALL отдаваться вместе с фото и сниматься.

Scenario: Создание метки

  • WHEN пользователь вводит новую метку и подтверждает
  • THEN метка создаётся и привязывается к фото

Scenario: Выбор из списка с поиском

  • WHEN пользователь вводит часть названия метки
  • THEN показываются подходящие метки пользователя для выбора

Scenario: Снятие метки

  • WHEN пользователь убирает метку с фото
  • THEN метка отвязывается от фото

Requirement: Кэширование объектов

Доставка объектов SHALL помечать ответы как кэшируемые, чтобы браузер переиспользовал уже полученные превью, а повторное открытие альбома не вызывало повторную загрузку неизменившихся объектов.

Scenario: Заголовки кэширования

  • WHEN клиент получает объект (оригинал, превью или thumb) по подписанному URL
  • THEN ответ содержит заголовок кэширования с ограниченным сроком годности

Scenario: Повторный показ без перезагрузки

  • WHEN сетка превью перерисовывается, а URL объектов не изменились
  • THEN браузер отдаёт объекты из кэша без повторного запроса к бэкенду

Requirement: Медиа-запись фото

Данные фото SHALL включать вид медиа (image | video), длительность для видео и адрес воспроизведения, когда видео-вариант готов; для изображений адрес воспроизведения отсутствует.

Scenario: Запись изображения

  • WHEN клиент получает данные изображения
  • THEN вид медиа — изображение, длительность и адрес воспроизведения отсутствуют

Scenario: Запись видео без готового варианта

  • WHEN клиент получает данные видео, а вариант ещё не готов
  • THEN вид медиа — видео, длительность присутствует, адрес воспроизведения отсутствует

Scenario: Запись видео с готовым вариантом

  • WHEN видео-вариант готов
  • THEN данные медиа содержат адрес воспроизведения