Жизненный цикл медиа: байты, запись CMS и публикация
Оглавление · Объектное хранение · Контент
Задача: определить, что уже сохранено после каждого шага и как проверить частичный отказ. Нужны S3-модель и неизвестный результат операции.
Три независимых состояния
Для одной фотографии существуют байты в хранилище, запись файла в CMS и связь с публикацией. Draft & Publish регулирует контент, а не автоматически доступ к объекту. В Atmanki website bucket публичен: прикрепление к черновику не делает изображение приватным.
Исходник схемы
flowchart LR Upload["Загрузка байтов"] --> Object["Объект"] Object --> Record["Запись файла CMS"] Record --> Link["Связь с публикацией"] Link --> Publish["Публикация контента"] Publish --> Webhook["Инвалидирование страницы"] Webhook --> Read["Следующее чтение страницы"]
Это упрощённый путь с границами отказа, не обещание атомарности Strapi и Garage. Загрузка может создавать также производные изображения; сохраняйте сведения о них при проверке и удалении.
Сбой между шагами
| Свидетельство | Чего оно ещё не доказывает |
|---|---|
| Upload ответил успешно | Запись CMS и связь с контентом сохранены |
| Запись файла есть в CMS | Объект доступен и байты верны |
| GET объекта успешен | Файл относится к нужной записи и допустим читателю |
| Статья опубликована | Каждая активная вкладка уже получила новый результат |
| Webhook принят | Обновлена каждая серверная и браузерная копия |
Потерянный ответ загрузки оставляет неизвестный результат. Повтор с новым key может создать лишний объект; повтор по прежнему key может заменить чужую версию. Нужны правила идентичности, проверки существования и разрешённых повторов. Не выводите их только из идемпотентности HTTP PUT.
Объект без записи может быть артефактом сбоя, но не всякий такой объект безопасно удалять: он может принадлежать незавершённой загрузке или ещё не учтённой связи. Для очистки нужны область, возраст, перечень владельцев, план и согласование. В текущем проекте автоматическая сборка таких объектов не добавлена.
Данные, которые проверяются на входе
Расширение и Content-Type — сведения от отправителя, а не подтверждение содержимого. Задайте допустимые форматы, предел размера и проверку декодирования для изображений. Импорт проекта использует sharp; CMS имеет собственные allowed/denied types. Upload-конфигурация, импорт.
Веб-адаптер ограничивает URL и файловые пути: это защищает границу доставки, но не является проверкой всех байтов изображения. SVG/HTML нельзя считать обычной фотографией только по имени. Правила преобразования и принятия формата должны соответствовать конкретному пути загрузки.
Замена, удаление и кеши
Если байты меняются под прежним URL, браузер или прокси может ещё хранить старую копию. Новый key для новой версии меняет адрес, но требует обновить ссылки и определить судьбу старого объекта. Это отдельный выбор, не автоматическое следствие использования S3.
Удаление файла должно учитывать связи, встроенные Blocks, варианты и внешние ссылки. Медиабиблиотека объясняет, какие редакторские изменения сохраняют URL. Не путайте переименование карточки с удалением физического объекта.
404 одного запроса не подтверждает отсутствие всех копий или версий; успешный DELETE не доказывает, что закрытые данные исчезли из ранее скачанных файлов. Правила версионирования и сроков хранения нужно знать до обещания удаления.
Сохранность и восстановление
Исходник схемы
flowchart TD Scope["Согласованный момент и состав копии"] --> DB["База CMS и связи"] Scope --> Data["Данные объектов"] Scope --> Meta["Метаданные Garage, конфигурация и доступ"] DB --> Restore["Восстановление в отдельной среде"] Data --> Restore Meta --> Restore Restore --> Verify["GET байтов, связи, варианты и страницы"]
У текущего Garage replication_factor=1; CMS и хранилище находятся на одном VPS. Том переживает пересоздание контейнера, но не обеспечивает независимую копию от потери хоста. Репликация также не заменяет защиту от ошибочного удаления. Конфигурация Garage.
Для проекта нужны база CMS, оба тома Garage, конфигурация/секреты, старые uploads и release refs. Состав и порядок cold backup описаны в инструкции Garage и эксплуатации. Обычное копирование файлов работающей metadata-БД не подтверждает согласованность. Восстановление проверяют отдельно; реальные секреты не попадают в учебные примеры.
Локальный практикум и границы проверки
Сценарий выполняется только в своей локальной CMS с вымышленным тестовым изображением:
- Зафиксируйте исходное состояние и подготовьте небольшой валидный PNG/JPEG.
- Загрузите через штатную форму Strapi и найдите запись файла, URL и варианты.
- Сопоставьте key с конфигурацией provider; проверьте публичный GET через Caddy.
- Скачайте оригинал и сравните байты/контрольную сумму с исходным файлом. Оригинал и преобразованный вариант сравнивайте по разным ожиданиям.
- Прикрепите только к тестовой записи; сравните доступность файла и draft/publish записи. Объясните границу публичности.
- Удалите только собственный тестовый файл после проверки его связей. Проверьте запись CMS, оригинал и варианты; отдельно учитывайте кеш ответа.
Этот сценарий в текущем этапе не запускался. Исторический upload/read/delete в README Garage относится к прежней проверке, а не подтверждает сегодняшнее состояние сервера. Happy-dom и разбор схем также не проверяют S3-транспорт.
На бумаге добавьте сбой после записи байтов и до записи CMS. Укажите, как различить незавершённую операцию и лишний объект без слепого повторного удаления.