From 7ae9bcf3051de23dbe8d551e1edae2b6e218f532 Mon Sep 17 00:00:00 2001 From: Iu Date: Sat, 10 Oct 2026 23:32:21 +0300 Subject: [PATCH] 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 --- .../.openspec.yaml | 0 .../2026-10-10-media-object-layer}/design.md | 0 .../proposal.md | 0 .../specs/media-objects/spec.md | 0 .../specs/photos/spec.md | 0 .../2026-10-10-media-object-layer}/tasks.md | 0 openspec/specs/media-objects/spec.md | 90 +++++++++++++++++++ openspec/specs/photos/spec.md | 4 +- 8 files changed, 92 insertions(+), 2 deletions(-) rename openspec/changes/{media-object-layer => archive/2026-10-10-media-object-layer}/.openspec.yaml (100%) rename openspec/changes/{media-object-layer => archive/2026-10-10-media-object-layer}/design.md (100%) rename openspec/changes/{media-object-layer => archive/2026-10-10-media-object-layer}/proposal.md (100%) rename openspec/changes/{media-object-layer => archive/2026-10-10-media-object-layer}/specs/media-objects/spec.md (100%) rename openspec/changes/{media-object-layer => archive/2026-10-10-media-object-layer}/specs/photos/spec.md (100%) rename openspec/changes/{media-object-layer => archive/2026-10-10-media-object-layer}/tasks.md (100%) create mode 100644 openspec/specs/media-objects/spec.md diff --git a/openspec/changes/media-object-layer/.openspec.yaml b/openspec/changes/archive/2026-10-10-media-object-layer/.openspec.yaml similarity index 100% rename from openspec/changes/media-object-layer/.openspec.yaml rename to openspec/changes/archive/2026-10-10-media-object-layer/.openspec.yaml diff --git a/openspec/changes/media-object-layer/design.md b/openspec/changes/archive/2026-10-10-media-object-layer/design.md similarity index 100% rename from openspec/changes/media-object-layer/design.md rename to openspec/changes/archive/2026-10-10-media-object-layer/design.md diff --git a/openspec/changes/media-object-layer/proposal.md b/openspec/changes/archive/2026-10-10-media-object-layer/proposal.md similarity index 100% rename from openspec/changes/media-object-layer/proposal.md rename to openspec/changes/archive/2026-10-10-media-object-layer/proposal.md diff --git a/openspec/changes/media-object-layer/specs/media-objects/spec.md b/openspec/changes/archive/2026-10-10-media-object-layer/specs/media-objects/spec.md similarity index 100% rename from openspec/changes/media-object-layer/specs/media-objects/spec.md rename to openspec/changes/archive/2026-10-10-media-object-layer/specs/media-objects/spec.md diff --git a/openspec/changes/media-object-layer/specs/photos/spec.md b/openspec/changes/archive/2026-10-10-media-object-layer/specs/photos/spec.md similarity index 100% rename from openspec/changes/media-object-layer/specs/photos/spec.md rename to openspec/changes/archive/2026-10-10-media-object-layer/specs/photos/spec.md diff --git a/openspec/changes/media-object-layer/tasks.md b/openspec/changes/archive/2026-10-10-media-object-layer/tasks.md similarity index 100% rename from openspec/changes/media-object-layer/tasks.md rename to openspec/changes/archive/2026-10-10-media-object-layer/tasks.md diff --git a/openspec/specs/media-objects/spec.md b/openspec/specs/media-objects/spec.md new file mode 100644 index 0000000..f697120 --- /dev/null +++ b/openspec/specs/media-objects/spec.md @@ -0,0 +1,90 @@ +# media-objects Specification + +## Purpose + +Физическое объектное хранилище с непрозрачными ключами и журналом объектов: +привязка объектов к фото по ролям, совместное использование объектов несколькими +фото и сборка мусора по отсутствию ссылок. + +## Requirements + +### Requirement: Непрозрачные ключи хранилища +Слой хранения SHALL адресоваться непрозрачными ключами объектов, не содержащими +идентификаторов сущностей метаданных (таких как альбом или фото); сопоставление +ключей и сущностей SHALL храниться только в слое метаданных. + +#### Scenario: Ключ без альбома +- **WHEN** система сохраняет объект в хранилище +- **THEN** ключ объекта не содержит идентификатора альбома + +#### Scenario: Перенос не трогает ключи +- **WHEN** фото переносится в другой альбом +- **THEN** ключи его объектов остаются неизменными + +### Requirement: Журнал объектов +Каждый физический объект SHALL иметь ровно одну запись в слое метаданных с ключом, +MIME-типом, размером, габаритами и состоянием; фото SHALL ссылаться на объекты по +ролям original, thumb и preview. + +#### Scenario: Привязка ролей +- **WHEN** фото загружено и обработано +- **THEN** фото ссылается на объект-оригинал и, когда они готовы, на объекты thumb и preview + +#### Scenario: Оригинал без вариантов +- **WHEN** варианты ещё не сгенерированы +- **THEN** фото доступно с оригиналом, а thumb и preview отсутствуют + +### Requirement: Совместные объекты +Несколько фото SHALL иметь возможность ссылаться на один и тот же физический +объект; перенос и копирование SHALL изменять только ссылки и SHALL не изменять +объекты хранилища. + +#### Scenario: Копирование +- **WHEN** пользователь копирует фото в другой альбом +- **THEN** создаётся новая запись, ссылающаяся на те же объекты, без операций с хранилищем + +#### Scenario: Перенос +- **WHEN** пользователь переносит фото в другой альбом +- **THEN** изменяется только привязка к альбому, объекты хранилища не меняются + +### Requirement: Сборка мусора по ссылкам +Объект хранилища SHALL удаляться только когда на него не ссылается ни одно фото; +удаление альбома и попадание фото в корзину SHALL сохранять объекты. + +#### Scenario: Последняя ссылка удалена +- **WHEN** фото удаляется навсегда и больше ни одно фото не ссылается на его объекты +- **THEN** объекты удаляются из хранилища + +#### Scenario: Остались ссылки +- **WHEN** на объект ссылается другое фото +- **THEN** объект сохраняется в хранилище + +#### Scenario: Удаление альбома +- **WHEN** владелец удаляет альбом +- **THEN** объекты хранилища не удаляются + +### Requirement: Устойчивость жизненного цикла объекта +Объект SHALL иметь состояние жизненного цикла, и незавершённые операции SHALL +самовосстанавливаться: неудачная загрузка не оставляет осиротевших объектов, а +удаление объекта SHALL доводиться до конца после сбоя. + +#### Scenario: Сбой загрузки +- **WHEN** запись объекта создана, но загрузка в хранилище не завершилась +- **THEN** объект очищается без ручного вмешательства + +#### Scenario: Сбой удаления +- **WHEN** удаление объекта из хранилища не удалось +- **THEN** попытка повторяется до успешного удаления + +### Requirement: Генерация вариантов +Генерация thumb и preview SHALL выполняться через надёжную очередь заданий с +однократным выполнением и повтором при сбое; готовый результат SHALL +транслироваться подписчикам альбома. + +#### Scenario: Повтор после рестарта +- **WHEN** процесс перезапускается с незавершёнными заданиями +- **THEN** генерация вариантов продолжается + +#### Scenario: Событие после генерации +- **WHEN** варианты фото готовы +- **THEN** подписчикам альбома публикуется событие с этим фото diff --git a/openspec/specs/photos/spec.md b/openspec/specs/photos/spec.md index 6d6c90b..ba8aebb 100644 --- a/openspec/specs/photos/spec.md +++ b/openspec/specs/photos/spec.md @@ -46,11 +46,11 @@ - **THEN** система возвращает presigned URL оригинала ### Requirement: Удаление фото -Автор SHALL иметь возможность удалить своё фото; владелец и админ SHALL иметь возможность удалить любое фото. +Автор SHALL иметь возможность удалить своё фото; владелец и админ SHALL иметь возможность удалить любое фото. Удаление SHALL помещать фото в корзину и SHALL не удалять объекты хранилища. #### Scenario: Удаление своего фото - **WHEN** автор удаляет своё фото -- **THEN** система удаляет запись и файлы в S3 +- **THEN** фото помещается в корзину, а объекты хранилища сохраняются #### Scenario: Удаление чужого фото участником - **WHEN** участник с ролью member пытается удалить чужое фото