# storage-backends Specification ## Purpose Выбор и работа объектного хранилища: S3-совместимое (Garage) или локальная файловая система. Блобы всегда отдаются через бэкенд по подписанному URL, хранилище клиенту не раскрывается. ## Requirements ### Requirement: Выбор бэкенда хранилища Система SHALL поддерживать выбор бэкенда объектного хранилища параметром конфигурации, при этом локальная файловая система SHALL быть значением по умолчанию. #### Scenario: Выбор по умолчанию - **WHEN** бэкенд хранилища не задан в конфигурации - **THEN** система хранит и отдаёт блобы из локальной файловой системы с корнем по умолчанию #### Scenario: Выбор S3-совместимого бэкенда - **WHEN** в конфигурации задан S3-совместимый бэкенд - **THEN** система хранит и отдаёт блобы через S3-совместимое хранилище #### Scenario: Выбор локальной ФС - **WHEN** в конфигурации задан бэкенд локальной ФС - **THEN** система хранит и отдаёт блобы из каталога локальной файловой системы #### Scenario: Неполная конфигурация - **WHEN** конфигурация выбранного бэкенда неполна - **THEN** система отказывается стартовать с явной ошибкой конфигурации ### Requirement: Единая абстракция хранилища Операции записи, чтения, удаления и проверки доступности SHALL выполняться через единый интерфейс хранилища, одинаковый для всех бэкендов; ключи объектов SHALL оставаться непрозрачными и независимыми от бэкенда. #### Scenario: Ключи переносимы между бэкендами - **WHEN** один и тот же ключ объекта используется на разных бэкендах - **THEN** он адресует тот же логический блоб без изменения формата #### Scenario: Удаление объекта - **WHEN** система удаляет объект через интерфейс хранилища - **THEN** блоб удаляется выбранным бэкендом ### Requirement: Отдача блобов через бэкенд Клиент SHALL получать любой блоб по URL, обслуживаемому бэкендом, с ограниченным сроком действия; ни один бэкенд SHALL не отдавать клиенту ссылку напрямую на объектное хранилище. Для анонимного доступа по share-ссылке подписанный URL SHALL быть действителен без пользовательской сессии. #### Scenario: Свежий URL просмотра - **WHEN** клиент запрашивает фото - **THEN** система возвращает подписанный URL бэкенда со сроком действия до 1 часа #### Scenario: Доступ по share-ссылке - **WHEN** аноним открывает альбом по действующей share-ссылке - **THEN** полученные подписанные URL позволяют загрузить фото без сессии #### Scenario: Истёкшая подпись - **WHEN** клиент обращается к URL с истёкшей или неверной подписью - **THEN** система отказывает в доступе ### Requirement: Хранилище не раскрывается клиенту Адрес и учётные данные объектного хранилища SHALL оставаться внутренними; клиент SHALL взаимодействовать с медиа только через бэкенд, независимо от бэкенда хранения. #### Scenario: S3-совместимый бэкенд - **WHEN** хранилищем выбран S3-совместимый бэкенд - **THEN** выдаваемый клиенту URL указывает на бэкенд, а не на S3-эндпоинт #### Scenario: Локальная ФС - **WHEN** хранилищем выбрана локальная ФС - **THEN** выдаваемый клиенту URL указывает на бэкенд #### Scenario: Хранилище недоступно извне - **WHEN** объектное хранилище недоступно из внешней сети - **THEN** просмотр и скачивание медиа продолжают работать ### Requirement: Локальное хранение на ФС Бэкенд локальной ФС SHALL хранить блобы в пределах заданного корневого каталога по непрозрачным ключам объектов и SHALL отвергать ключи, выводящие за пределы корня. #### Scenario: Запись и чтение блоба - **WHEN** система сохраняет объект с ключом - **THEN** блоб размещается под корневым каталогом и позже читается по тому же ключу #### Scenario: Попытка выхода из корня - **WHEN** ключ содержит элементы обхода каталога - **THEN** система отвергает операцию и не обращается за пределы корня ### Requirement: Диапазонные запросы и тип содержимого При отдаче блоба система SHALL возвращать корректный тип содержимого и SHALL поддерживать диапазонные запросы для докачки и больших файлов. #### Scenario: Запрос диапазона - **WHEN** клиент запрашивает часть блоба через диапазон - **THEN** система возвращает запрошенный диапазон и соответствующий статус #### Scenario: Тип содержимого - **WHEN** клиент загружает блоб - **THEN** ответ содержит тип содержимого, соответствующий объекту ### Requirement: Доступность выбранного хранилища Система SHALL сообщать о доступности выбранного бэкенда хранилища и отражать его в состоянии здоровья сервиса. #### Scenario: Хранилище доступно - **WHEN** выбранный бэкенд отвечает на проверку - **THEN** состоянии здоровья отражает хранилище как доступное #### Scenario: Хранилище недоступно - **WHEN** выбранный бэкенд не отвечает на проверку - **THEN** состояние здоровья отражает деградацию ### Requirement: Хост-независимые URL объектов Выдаваемый клиенту подписанный URL объекта SHALL быть относительным к текущему источнику (same-origin) и SHALL не содержать настроенный хост. Просмотр и скачивание медиа SHALL работать за любым хостом или обратным прокси без настройки внешнего базового URL. #### Scenario: Другой хост - **WHEN** приложение доступно по адресу, отличному от адреса по умолчанию, и клиент запрашивает фото - **THEN** URL объекта указывает на тот же источник, что и страница, и превью загружается без дополнительной настройки #### Scenario: Обратный прокси - **WHEN** приложение доступно за обратным прокси - **THEN** URL объектов сохраняют тот же источник, что и страница приложения #### Scenario: Подпись сохраняется - **WHEN** клиент получает относительный URL объекта - **THEN** подпись, срок действия и кэширование объекта работают как прежде