diff --git a/openspec/changes/photo-curve-presets/.openspec.yaml b/openspec/changes/archive/2026-10-23-photo-curve-presets/.openspec.yaml similarity index 100% rename from openspec/changes/photo-curve-presets/.openspec.yaml rename to openspec/changes/archive/2026-10-23-photo-curve-presets/.openspec.yaml diff --git a/openspec/changes/photo-curve-presets/design.md b/openspec/changes/archive/2026-10-23-photo-curve-presets/design.md similarity index 100% rename from openspec/changes/photo-curve-presets/design.md rename to openspec/changes/archive/2026-10-23-photo-curve-presets/design.md diff --git a/openspec/changes/photo-curve-presets/proposal.md b/openspec/changes/archive/2026-10-23-photo-curve-presets/proposal.md similarity index 100% rename from openspec/changes/photo-curve-presets/proposal.md rename to openspec/changes/archive/2026-10-23-photo-curve-presets/proposal.md diff --git a/openspec/changes/photo-curve-presets/specs/auth/spec.md b/openspec/changes/archive/2026-10-23-photo-curve-presets/specs/auth/spec.md similarity index 100% rename from openspec/changes/photo-curve-presets/specs/auth/spec.md rename to openspec/changes/archive/2026-10-23-photo-curve-presets/specs/auth/spec.md diff --git a/openspec/changes/photo-curve-presets/specs/photos/spec.md b/openspec/changes/archive/2026-10-23-photo-curve-presets/specs/photos/spec.md similarity index 100% rename from openspec/changes/photo-curve-presets/specs/photos/spec.md rename to openspec/changes/archive/2026-10-23-photo-curve-presets/specs/photos/spec.md diff --git a/openspec/changes/photo-curve-presets/tasks.md b/openspec/changes/archive/2026-10-23-photo-curve-presets/tasks.md similarity index 100% rename from openspec/changes/photo-curve-presets/tasks.md rename to openspec/changes/archive/2026-10-23-photo-curve-presets/tasks.md diff --git a/openspec/specs/auth/spec.md b/openspec/specs/auth/spec.md index 86804ee..c3989ec 100644 --- a/openspec/specs/auth/spec.md +++ b/openspec/specs/auth/spec.md @@ -59,18 +59,20 @@ E.164 — и паролю. - **THEN** система отзывает refresh-токен, и его дальнейшее использование отклоняется ### Requirement: Хранение пользовательских настроек интерфейса -Система SHALL хранить настройки отображения в профиле пользователя и SHALL возвращать их при -получении текущего пользователя. Настройки SHALL быть приватными для пользователя. -Отсутствие настроек SHALL трактоваться как значения по умолчанию. +Система SHALL хранить пользовательские настройки (отображение интерфейса и пресеты кривой) в профиле пользователя и SHALL возвращать их при получении текущего пользователя. Настройки SHALL быть приватными для пользователя. Отсутствие настроек SHALL трактоваться как значения по умолчанию. Сохранение одного раздела настроек SHALL не затирать остальные разделы. #### Scenario: Получение настроек - **WHEN** аутентифицированный пользователь запрашивает свой профиль -- **THEN** ответ содержит его настройки отображения (или пустой объект по умолчанию) +- **THEN** ответ содержит его настройки отображения и пресеты кривой (или пустой объект по умолчанию) #### Scenario: Сохранение настроек -- **WHEN** пользователь сохраняет настройки отображения +- **WHEN** пользователь сохраняет настройки - **THEN** система сохраняет их в профиле и возвращает сохранённое состояние +#### Scenario: Сохранение раздела не затирает другие +- **WHEN** пользователь сохраняет только один раздел настроек (например, сведения о фото или пресеты кривой) +- **THEN** остальные разделы профиля сохраняются без изменений + #### Scenario: Изоляция настроек - **WHEN** другой пользователь запрашивает свой профиль - **THEN** он не получает настройки первого пользователя diff --git a/openspec/specs/photos/spec.md b/openspec/specs/photos/spec.md index bcdc304..739a2c1 100644 --- a/openspec/specs/photos/spec.md +++ b/openspec/specs/photos/spec.md @@ -346,3 +346,84 @@ SHALL быть доступно и для фото без альбома (нап #### Scenario: Серверная версия заменяет предпросмотр - **WHEN** серверный рендер цветовых правок завершён - **THEN** просмотрщик показывает отрендеренную версию + +### Requirement: Тоновая кривая +Тоновая кривая SHALL задаваться контрольными точками для каналов RGB, R, G и B. Крайние точки SHALL существовать по умолчанию, SHALL двигаться по обеим осям и SHALL задавать плоские участки вне себя. Кривая SHALL быть плавной и монотонной между точками; первый клик по полю SHALL добавлять точку между крайними. Сброс SHALL возвращать линейную кривую. + +#### Scenario: Крайние узлы существуют с самого начала +- **WHEN** пользователь открывает инструмент «Кривая» +- **THEN** у каждого канала уже есть крайние точки, и их можно перетаскивать + +#### Scenario: Добавление точки +- **WHEN** пользователь кликает по свободному полю кривой +- **THEN** между крайними точками добавляется новая точка, а крайние остаются на месте + +#### Scenario: Подвижные крайние узлы +- **WHEN** пользователь двигает крайнюю точку по x или y +- **THEN** вне крайних точек кривая остаётся плоской, а между точками — плавной + +#### Scenario: Плавная интерполяция +- **WHEN** кривая сохранена и отрендерена +- **THEN** предпросмотр и итоговое фото используют одну и ту же плавную монотонную кривую + +#### Scenario: Встроенные пресеты +- **WHEN** пользователь выбирает «Линейный», «Средний контраст» или «Сильный контраст» +- **THEN** кривые всех четырёх каналов заменяются кривыми пресета (контраст — в RGB, R/G/B — линейные), а подпись показывает выбранный пресет + +#### Scenario: Пользовательская правка +- **WHEN** пользователь вручную меняет точки кривой +- **THEN** подпись показывает «Пользовательский» + +#### Scenario: Сброс +- **WHEN** пользователь сбрасывает кривую +- **THEN** текущий канал возвращается к линейной кривой с крайними точками + +#### Scenario: Независимые каналы +- **WHEN** пользователь выбирает канал R, G или B +- **THEN** он меняет только выбранный канал, остальные каналы остаются прежними + +### Requirement: Переключение фото в редакторе +При переключении фото правая панель SHALL сохранять выбранную вкладку. Несохранённые правки SHALL сохраняться тому фото, для которого они сделаны, в том числе если пользователь уже переключился на другое фото. Ответы фоновых запросов SHALL NOT подменять текущее фото или его параметры. + +#### Scenario: Вкладка не меняется +- **WHEN** пользователь переключает фото +- **THEN** выбранная вкладка правой панели остаётся прежней + +#### Scenario: Правки уходят текущему фото +- **WHEN** пользователь меняет настройки после переключения +- **THEN** изменения сохраняются текущему фото, а не предыдущему + +#### Scenario: Фоновое сохранение не подменяет фото +- **WHEN** сохранение предыдущего фото завершается после переключения +- **THEN** панель продолжает показывать текущее фото, а его параметры не меняются + +### Requirement: Пользовательские пресеты кривой +Пользователь SHALL сохранять текущие кривые всех каналов (RGB, R, G и B) как именованный пресет, применять, переименовывать и удалять его. Пресет SHALL содержать кривую для каждого из четырёх каналов. Пресеты SHALL храниться в профиле пользователя и SHALL быть приватными. Импорт и экспорт SHALL выполняться JSON-файлом; импорт SHALL добавлять пресеты в профиль. + +#### Scenario: Сохранение пресета +- **WHEN** пользователь сохраняет текущие кривые под именем +- **THEN** пресет появляется в списке и сохраняется в профиле вместе с кривыми RGB, R, G и B + +#### Scenario: Применение пресета +- **WHEN** пользователь выбирает пользовательский пресет +- **THEN** кривые всех четырёх каналов заменяются сохранёнными, а текущий канал не меняется + +#### Scenario: Переименование и удаление +- **WHEN** пользователь переименовывает или удаляет пресет +- **THEN** список пресетов и профиль обновляются + +#### Scenario: Приватность пресетов +- **WHEN** другой пользователь открывает свои пресеты +- **THEN** он не видит пресеты первого пользователя + +#### Scenario: Экспорт пресетов +- **WHEN** пользователь экспортирует пресеты +- **THEN** он получает JSON-файл с пользовательскими пресетами и кривыми всех четырёх каналов + +#### Scenario: Импорт пресетов +- **WHEN** пользователь импортирует корректный JSON-файл +- **THEN** пресеты добавляются или обновляются в его профиле + +#### Scenario: Некорректный файл или пресет +- **WHEN** имя или кривая хотя бы одного канала недопустимы +- **THEN** система отклоняет пресет и не меняет профиль