diff --git a/openspec/changes/lightroom-workspace-ui/.openspec.yaml b/openspec/changes/archive/2026-10-10-lightroom-workspace-ui/.openspec.yaml similarity index 100% rename from openspec/changes/lightroom-workspace-ui/.openspec.yaml rename to openspec/changes/archive/2026-10-10-lightroom-workspace-ui/.openspec.yaml diff --git a/openspec/changes/lightroom-workspace-ui/design.md b/openspec/changes/archive/2026-10-10-lightroom-workspace-ui/design.md similarity index 100% rename from openspec/changes/lightroom-workspace-ui/design.md rename to openspec/changes/archive/2026-10-10-lightroom-workspace-ui/design.md diff --git a/openspec/changes/lightroom-workspace-ui/proposal.md b/openspec/changes/archive/2026-10-10-lightroom-workspace-ui/proposal.md similarity index 100% rename from openspec/changes/lightroom-workspace-ui/proposal.md rename to openspec/changes/archive/2026-10-10-lightroom-workspace-ui/proposal.md diff --git a/openspec/changes/lightroom-workspace-ui/specs/albums/spec.md b/openspec/changes/archive/2026-10-10-lightroom-workspace-ui/specs/albums/spec.md similarity index 78% rename from openspec/changes/lightroom-workspace-ui/specs/albums/spec.md rename to openspec/changes/archive/2026-10-10-lightroom-workspace-ui/specs/albums/spec.md index 90093a9..3e0ff15 100644 --- a/openspec/changes/lightroom-workspace-ui/specs/albums/spec.md +++ b/openspec/changes/archive/2026-10-10-lightroom-workspace-ui/specs/albums/spec.md @@ -37,3 +37,13 @@ #### Scenario: Счётчики в ответе - **WHEN** клиент запрашивает список альбомов или альбом по id - **THEN** ответ содержит число фото и число участников альбома + +## MODIFIED Requirements + +### Requirement: Удаление альбома +Владелец SHALL иметь возможность удалить альбом; фото альбома SHALL помещаться в корзину без +удаления объектов хранилища, а участники и share-ссылки SHALL удаляться вместе с альбомом. + +#### Scenario: Удаление альбома +- **WHEN** владелец удаляет альбом +- **THEN** фото альбома попадают в корзину без привязки к альбому и файлы сохраняются, участники и share-ссылки удаляются diff --git a/openspec/changes/lightroom-workspace-ui/specs/auth/spec.md b/openspec/changes/archive/2026-10-10-lightroom-workspace-ui/specs/auth/spec.md similarity index 100% rename from openspec/changes/lightroom-workspace-ui/specs/auth/spec.md rename to openspec/changes/archive/2026-10-10-lightroom-workspace-ui/specs/auth/spec.md diff --git a/openspec/changes/lightroom-workspace-ui/specs/photos/spec.md b/openspec/changes/archive/2026-10-10-lightroom-workspace-ui/specs/photos/spec.md similarity index 100% rename from openspec/changes/lightroom-workspace-ui/specs/photos/spec.md rename to openspec/changes/archive/2026-10-10-lightroom-workspace-ui/specs/photos/spec.md diff --git a/openspec/changes/lightroom-workspace-ui/specs/ui-workspace/spec.md b/openspec/changes/archive/2026-10-10-lightroom-workspace-ui/specs/ui-workspace/spec.md similarity index 100% rename from openspec/changes/lightroom-workspace-ui/specs/ui-workspace/spec.md rename to openspec/changes/archive/2026-10-10-lightroom-workspace-ui/specs/ui-workspace/spec.md diff --git a/openspec/changes/lightroom-workspace-ui/tasks.md b/openspec/changes/archive/2026-10-10-lightroom-workspace-ui/tasks.md similarity index 100% rename from openspec/changes/lightroom-workspace-ui/tasks.md rename to openspec/changes/archive/2026-10-10-lightroom-workspace-ui/tasks.md diff --git a/openspec/specs/albums/spec.md b/openspec/specs/albums/spec.md index 7c96668..2be8109 100644 --- a/openspec/specs/albums/spec.md +++ b/openspec/specs/albums/spec.md @@ -35,8 +35,47 @@ - **THEN** система сохраняет изменения ### Requirement: Удаление альбома -Владелец SHALL иметь возможность удалить альбом вместе с содержимым. +Владелец SHALL иметь возможность удалить альбом; фото альбома SHALL помещаться в корзину без +удаления объектов хранилища, а участники и share-ссылки SHALL удаляться вместе с альбомом. #### Scenario: Удаление альбома - **WHEN** владелец удаляет альбом -- **THEN** система удаляет альбом, его фото, участников и share-ссылки +- **THEN** фото альбома попадают в корзину без привязки к альбому и файлы сохраняются, участники и share-ссылки удаляются + +### Requirement: Отображение обложки альбома +Данные альбома SHALL включать URL миниатюры обложки, когда обложка задана, чтобы клиенты +могли показать её в списке, рейле и карточке. + +#### Scenario: Обложка задана +- **WHEN** клиент запрашивает список альбомов или альбом по id, и у альбома есть обложка +- **THEN** ответ содержит URL миниатюры обложки + +#### Scenario: Обложка отсутствует +- **WHEN** у альбома нет обложки или фото обложки удалено +- **THEN** ответ не содержит URL обложки, и клиент показывает плейсхолдер + + +### Requirement: Выбор обложки +Владелец и админ SHALL иметь возможность назначить обложкой любое фото альбома или сбросить +обложку; после сброса обложка определяется заново по умолчанию. + +#### Scenario: Назначение обложки +- **WHEN** владелец выбирает фото альбома как обложку +- **THEN** система сохраняет выбор и отражает его в списке и карточках + +#### Scenario: Сброс обложки +- **WHEN** админ сбрасывает обложку +- **THEN** система удаляет явный выбор, и обложка возвращается к значению по умолчанию + +#### Scenario: Нет прав на смену обложки +- **WHEN** участник без права редактирования пытается сменить обложку +- **THEN** система отклоняет запрос + + +### Requirement: Счётчики альбома +Данные альбома SHALL включать количество фото и участников, чтобы панель и карточки могли +показать их без отдельных запросов. + +#### Scenario: Счётчики в ответе +- **WHEN** клиент запрашивает список альбомов или альбом по id +- **THEN** ответ содержит число фото и число участников альбома diff --git a/openspec/specs/auth/spec.md b/openspec/specs/auth/spec.md index 7f06609..e17aef3 100644 --- a/openspec/specs/auth/spec.md +++ b/openspec/specs/auth/spec.md @@ -45,3 +45,24 @@ #### Scenario: Выход - **WHEN** пользователь вызывает logout с действующим refresh-токеном - **THEN** система отзывает refresh-токен, и его дальнейшее использование отклоняется + +### Requirement: Хранение пользовательских настроек интерфейса +Система SHALL хранить настройки отображения в профиле пользователя и SHALL возвращать их при +получении текущего пользователя. Настройки SHALL быть приватными для пользователя. +Отсутствие настроек SHALL трактоваться как значения по умолчанию. + +#### Scenario: Получение настроек +- **WHEN** аутентифицированный пользователь запрашивает свой профиль +- **THEN** ответ содержит его настройки отображения (или пустой объект по умолчанию) + +#### Scenario: Сохранение настроек +- **WHEN** пользователь сохраняет настройки отображения +- **THEN** система сохраняет их в профиле и возвращает сохранённое состояние + +#### Scenario: Изоляция настроек +- **WHEN** другой пользователь запрашивает свой профиль +- **THEN** он не получает настройки первого пользователя + +#### Scenario: Некорректные настройки +- **WHEN** пользователь присылает настройки недопустимой структуры или размера +- **THEN** система отклоняет запрос с ошибкой и не меняет сохранённые настройки diff --git a/openspec/specs/photos/spec.md b/openspec/specs/photos/spec.md index f49f173..6d6c90b 100644 --- a/openspec/specs/photos/spec.md +++ b/openspec/specs/photos/spec.md @@ -55,3 +55,125 @@ #### Scenario: Удаление чужого фото участником - **WHEN** участник с ролью member пытается удалить чужое фото - **THEN** система отклоняет запрос + +### Requirement: Обложка по умолчанию +При обработке загруженного фото система SHALL назначать его обложкой альбома только если +обложка ещё не задана. + +#### 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** система принимает multipart-загрузку и обрабатывает фото + + +### Requirement: Метаданные фото (EXIF) +При загрузке фото система SHALL извлекать распознаваемые EXIF-атрибуты и SHALL возвращать их +вместе с данными фото; при отсутствии метаданных SHALL возвращать пустой набор. + +#### Scenario: Фото с метаданными +- **WHEN** загружается фото с EXIF +- **THEN** данные фото содержат извлечённые атрибуты (камера, экспозиция, ISO, дата съёмки и др.) + +#### Scenario: Фото без метаданных +- **WHEN** загружается фото без читаемых EXIF +- **THEN** данные фото не содержат атрибутов, а загрузка выполняется успешно + + +### Requirement: Перенос и копирование фото между альбомами +Пользователь с правом удаления в исходном альбоме и правом загрузки в целевом SHALL иметь +возможность перенести или скопировать фото в другой альбом. Операции SHALL изменять только +метаданные и SHALL не изменять объекты хранилища. + +#### Scenario: Перенос +- **WHEN** пользователь переносит фото в другой альбом +- **THEN** фото исчезает из исходного альбома и появляется в целевом, объекты S3 не меняются + +#### Scenario: Копирование +- **WHEN** пользователь копирует фото в другой альбом +- **THEN** в целевом альбоме появляется новая запись, ссылающаяся на те же объекты S3 + + +### 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** метка отвязывается от фото diff --git a/openspec/specs/ui-workspace/spec.md b/openspec/specs/ui-workspace/spec.md new file mode 100644 index 0000000..e622bf3 --- /dev/null +++ b/openspec/specs/ui-workspace/spec.md @@ -0,0 +1,384 @@ +# ui-workspace Specification + +## Purpose + +Рабочий стол веб-приложения: постоянный каркас с рейлом альбомов, контекстной панелью, +режимом просмотра фото и адаптивным поведением, обеспечивающий цельный «lightroom»-вид. + +## Requirements + +### Requirement: Рабочий стол приложения +Аутентифицированные экраны SHALL отображаться внутри постоянного каркаса с топбаром, левым +рейлом альбомов и контекстной правой панелью. Публичные экраны (вход, инвайт, share-ссылка) +SHALL отображаться вне каркаса, но в общей теме оформления. + +#### Scenario: Внутренний экран +- **WHEN** аутентифицированный пользователь открывает список альбомов или альбом +- **THEN** экран отрисован внутри каркаса с рейлом и панелью, рейл не перезагружается при переходе + +#### Scenario: Публичный экран +- **WHEN** пользователь открывает публичную share-ссылку без входа +- **THEN** экран отрисован без рейла и контекстной панели, но в тех же цветовых токенах + +### Requirement: Рейл альбомов +Рейл SHALL постоянно показывать список доступных альбомов с их обложками и отмечать +активный альбом. + +#### Scenario: Активный альбом +- **WHEN** пользователь находится в альбоме +- **THEN** соответствующий элемент рейла выделен, остальные показывают обложки или плейсхолдер + +### Requirement: Создание альбома +Создание альбома SHALL выполняться через иконочную кнопку с подсказкой, открывающую +модальное окно ввода названия, вместо инлайн-формы. + +#### Scenario: Создание через модалку +- **WHEN** пользователь нажимает кнопку создания, вводит название и подтверждает +- **THEN** система создаёт альбом и делает его активным + +#### Scenario: Пустое название +- **WHEN** пользователь подтверждает пустое название +- **THEN** создание не выполняется + +### Requirement: Контекстная панель альбома +Правая панель SHALL показывать превью обложки, название, счётчики фото и участников, +управление обложкой и переходы к участникам, настройкам и ссылкам. Элементы управления +обложкой SHALL быть доступны только owner и admin. + +#### Scenario: Владелец альбома +- **WHEN** owner открывает альбом +- **THEN** панель показывает управление обложкой и переходы к участникам и настройкам + +#### Scenario: Наблюдатель +- **WHEN** viewer открывает альбом +- **THEN** панель не показывает управление обложкой + +### Requirement: Режим просмотра фотографии +Просмотр фото SHALL быть отдельным маршрутом внутри каркаса с крупным изображением, +лентой миниатюр снизу и панелью метаданных и комментариев. Тот же режим SHALL +использоваться на публичных share-страницах. + +#### Scenario: Открытие фото +- **WHEN** пользователь выбирает фото в сетке +- **THEN** открывается маршрут фото в каркасе, рейл и панель остаются доступны, адрес отражает фото + +#### Scenario: Навигация в просмотре +- **WHEN** пользователь использует стрелки влево/вправо или ленту миниатюр +- **THEN** показывается соседнее фото, адрес обновляется + +#### Scenario: Публичный просмотр +- **WHEN** посетитель share-ссылки открывает фото +- **THEN** используется тот же режим просмотра без рейла и панели + +### Requirement: Плотность сетки +Сетка SHALL давать пользователю управлять размером миниатюр, и выбранный размер SHALL +сохраняться между сессиями. + +#### Scenario: Изменение размера +- **WHEN** пользователь двигает регулятор плотности +- **THEN** размер миниатюр меняется, значение сохраняется и восстанавливается при следующем открытии + +### Requirement: Загрузка фотографий из рабочего стола +Загрузка SHALL запускаться действием в тулбаре; перетаскивание файлов над альбомом SHALL +показывать оверлей и загружать их; пустой альбом SHALL показывать подсказку-зону загрузки. +Загрузка SHALL быть доступна только ролям с правом загрузки. + +#### Scenario: Перетаскивание +- **WHEN** пользователь с правом загрузки перетаскивает файлы над альбомом +- **THEN** показывается оверлей загрузки, и файлы загружаются + +#### Scenario: Пустой альбом +- **WHEN** пользователь открывает альбом без фото и имеет право загрузки +- **THEN** в центре показана зона-подсказка загрузки + +### Requirement: Темы и графитовый хром +Тёмная тема SHALL использовать графитовый хром Lightroom и SHALL применяться по умолчанию; +нейтральная тема SHALL быть тёплым графитом; остальные темы SHALL оставаться доступными, а +скроллбары SHALL быть стилизованы в цвет темы. + +#### Scenario: Первый вход +- **WHEN** пользователь впервые открывает приложение без сохранённой темы +- **THEN** применяется тёмная графитовая тема + +#### Scenario: Смена темы +- **WHEN** пользователь выбирает другую тему +- **THEN** интерфейс, иконки и скроллбары меняются согласованно, и выбор сохраняется + +#### Scenario: Нейтральная тема +- **WHEN** пользователь выбирает нейтральную тему +- **THEN** применяется тёплый графитовый хром, отличный от холодной тёмной темы + +### Requirement: Адаптивность рабочего стола +На узких экранах рейл SHALL становиться выдвижной панелью, контекстная панель — +сворачиваемой секцией, а лента миниатюр — горизонтально прокручиваемой. + +#### Scenario: Узкий экран +- **WHEN** ширина окна меньше порога рабочего стола +- **THEN** рейл скрыт за кнопкой открытия, панель сворачиваема, лента прокручивается горизонтально + +### Requirement: Доступность рабочего стола +Иконочные органы управления каркаса SHALL иметь доступные имена, панели SHALL быть +достижимы с клавиатуры с видимым фокусом, анимации SHALL учитывать +предпочтение уменьшенного движения. + +#### Scenario: Клавиатурная навигация +- **WHEN** пользователь работает только с клавиатуры +- **THEN** органы управления каркаса достижимы, доступные имена присутствуют, фокус виден + +### Requirement: Изменение ширины панелей +Пользователь SHALL иметь возможность менять ширину левой и правой панелей перетаскиванием, а +выбранная ширина SHALL сохраняться между сессиями. + +#### Scenario: Перетаскивание разделителя +- **WHEN** пользователь тянет разделитель у панели на рабочем столе +- **THEN** панель меняет ширину в допустимых пределах + +#### Scenario: Сохранение ширины +- **WHEN** пользователь перезагружает приложение +- **THEN** восстановленные панели имеют сохранённую ширину + +### Requirement: Сворачиваемые разделы панели +Контекстная панель SHALL группировать содержимое в сворачиваемые разделы, а состояние +сворачивания SHALL сохраняться; раздел «Информация» SHALL показывать метаданные фото, +включая извлечённые EXIF-атрибуты. + +#### Scenario: Сворачивание раздела +- **WHEN** пользователь нажимает заголовок раздела +- **THEN** содержимое раздела скрывается или показывается, состояние сохраняется + +#### Scenario: Метаданные фото +- **WHEN** открыт просмотр фото +- **THEN** раздел «Информация» показывает размер, тип, разрешение, дату съёмки, координаты и извлечённые EXIF-атрибуты + +### Requirement: Полноэкранный просмотр фотографии +В режиме просмотра SHALL быть доступен переход в полноэкранный режим кнопкой и хоткеем `f`. +В полноэкранном режиме верхняя и нижняя панели SHALL скрываться и показываться у +соответствующей кромки экрана. + +#### Scenario: Вход в полный экран +- **WHEN** пользователь нажимает кнопку полного экрана или клавишу `f` +- **THEN** просмотр разворачивается на весь экран, панели скрыты + +#### Scenario: Панель по кромке +- **WHEN** курсор касается верхней или нижней кромки экрана +- **THEN** соответствующая панель показывается, а при уходе курсора скрывается сразу + +#### Scenario: Выход из полного экрана +- **WHEN** пользователь повторно нажимает кнопку или клавишу `f` +- **THEN** полноэкранный режим закрывается + +#### Scenario: Полноэкранный режим приложения +- **WHEN** включён полноэкранный режим приложения, и пользователь нажимает `f` +- **THEN** открывается полноэкранный просмотр фото (вложенно), а полноэкранный режим приложения не выключается + +### Requirement: Зум в просмотре +Просмотр SHALL поддерживать зум колесом мыши без прокрутки, с привязкой к указателю и +верхним пределом 200% размеров фото. `Space` SHALL возвращать изображение из любого зума во +вписанный вид, а из вписанного — в 100%. При зуме SHALL догружаться оригинал изображения. +Стрелки соседних фото SHALL появляться у левой/правой кромки и прятаться в зуме. Зум SHALL +работать и в полноэкранном режиме. + +#### Scenario: Зум колесом к указателю +- **WHEN** пользователь вращает колесо мыши над фото +- **THEN** масштаб меняется относительно курсора, страница не прокручивается, предел — 200% + +#### Scenario: Пробел +- **WHEN** пользователь нажимает `Space` +- **THEN** из вписанного вида изображение переходит в 100%, а из любого зума возвращается во вписанный + +#### Scenario: Оригинал в зуме +- **WHEN** пользователь входит в зум +- **THEN** догружается оригинал изображения и подменяется по факту загрузки + +#### Scenario: Стрелки соседних фото +- **WHEN** курсор находится у левой или правой кромки области просмотра +- **THEN** показывается соответствующая стрелка, скрываясь сразу после ухода; в зуме стрелки скрыты + +#### Scenario: Панорамирование +- **WHEN** фото увеличено +- **THEN** пользователь может перемещать изображение перетаскиванием и прокруткой + +### Requirement: Удаление фото из просмотра +Автор фото, владелец и админ альбома SHALL иметь возможность удалить текущее фото из режима +просмотра; удаление SHALL подтверждаться диалогом. + +#### Scenario: Подтверждение удаления +- **WHEN** пользователь с правом удаления нажимает «Удалить» +- **THEN** открывается диалог подтверждения, и после подтверждения фото удаляется + +#### Scenario: Лента после удаления +- **WHEN** фото удалено +- **THEN** просмотр переходит к соседнему фото, а лента миниатюр обновляется без удалённого + +### Requirement: Возврат к обзору +Из альбома и из режима просмотра SHALL быть доступен возврат к обзору альбомов. + +#### Scenario: Возврат из альбома +- **WHEN** пользователь нажимает кнопку «назад» слева от названия альбома +- **THEN** открывается обзор альбомов + +#### Scenario: Возврат из просмотра +- **WHEN** пользователь нажимает кнопку «назад» в режиме просмотра +- **THEN** открывается альбом с сеткой фото + +### Requirement: Настройки списка атрибутов информации +Раздел «Информация» SHALL предоставлять доступ к настройкам (иконка-шестерёнка), открывающим +модальное окно со списком EXIF-атрибутов, где пользователь SHALL отмечать отображаемые +атрибуты и задавать их подписи. В окне SHALL быть доступны действия «отметить все» и +«снять все». Настройки SHALL применяться ко всем фото и SHALL сохраняться в профиле +пользователя. При отсутствии сохранённых настроек SHALL отображаться базовый набор атрибутов +(камера, объектив, выдержка, диафрагма, ISO, фокусное расстояние). + +#### Scenario: Открытие настроек +- **WHEN** пользователь нажимает иконку настроек в разделе «Информация» +- **THEN** открывается модальное окно со списком EXIF-атрибутов: галочки видимости и поля подписей, а также действия «отметить все»/«снять все» + +#### 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** отметка выбора сбрасывается + +### Requirement: Мультивыбор фото в сетке +В режиме альбома пользователь SHALL выбирать несколько фото: обычный клик — одно фото, +Ctrl/Cmd-клик — добавить или убрать, Shift-клик — диапазон. Выбранные фото SHALL быть отмечены. + +#### Scenario: Мультивыбор +- **WHEN** пользователь кликает по фото с зажатым Ctrl/Cmd или Shift +- **THEN** соответствующие фото отмечены, а панель показывает количество выбранных + +### Requirement: Действия с выбранными фото +Когда выбрано одно или несколько фото, правая панель SHALL показывать раздел «Действия» со +строками-пунктами (иконка + подпись) «Открыть (просмотр)», «Переместить», «Копировать» и +«Удалить»; удаление SHALL подтверждаться диалогом. + +#### Scenario: Действия +- **WHEN** выбрано одно или несколько фото +- **THEN** панель показывает раздел «Действия» с пунктами «Открыть (просмотр)», «Переместить», «Копировать» и «Удалить» + +### Requirement: Перетаскивание выбранных фото на альбом +Выбранные фото SHALL перетаскиваться на альбом в рейле; при отпускании SHALL открываться +диалог выбора переноса или копирования с указанием целевого альбома. Во время такого +перетаскивания зона загрузки файлов SHALL не показываться. + +#### 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: Контекстное меню альбома +Правый клик по альбому в рейле и по карточке на обзоре SHALL открывать меню с пунктами +«Переименовать» и «Удалить»; переименование SHALL открывать диалог, удаление — подтверждение. + +#### Scenario: Меню альбома +- **WHEN** пользователь кликает правой кнопкой по альбому +- **THEN** открывается меню с «Переименовать» и «Удалить» + +#### Scenario: Удаление альбома +- **WHEN** пользователь подтверждает удаление альбома +- **THEN** альбом удаляется, а его фото попадают в корзину + +### Requirement: Счётчики в рейле +Рейл SHALL показывать число фото у каждого альбома и число элементов в корзине. + +#### Scenario: Счётчики +- **WHEN** пользователь смотрит на рейл альбомов +- **THEN** у каждого альбома показано число фото, а у корзины — число удалённых фото + +### Requirement: Метки в панели фото +Панель фото SHALL содержать раздел «Метки» с чипами меток фото и полем добавления, дающим +поиск по меткам пользователя и создание новых. + +#### Scenario: Раздел «Метки» +- **WHEN** открыт просмотр или выбран один фото в сетке +- **THEN** в панели есть раздел «Метки» с текущими метками и полем добавления с поиском + +### Requirement: Компактный верхний хром +Верхняя панель приложения и верхняя панель режима просмотра SHALL иметь минимальную высоту +(узкие отступы, иконочные органы управления), сохраняя все действия доступными. Верхняя панель +режима просмотра SHALL быть прозрачным оверлеем и SHALL не занимать место в раскладке, +увеличивая область фото. + +#### Scenario: Компактные верхние панели +- **WHEN** открыт список альбомов или режим просмотра фото +- **THEN** верхняя панель занимает минимум высоты, а её действия (навигация, полный экран, скачивание, удаление) доступны + +#### Scenario: Прозрачная панель просмотра +- **WHEN** открыт режим просмотра фото +- **THEN** верхняя панель нарисована поверх фото без фона и не уменьшает область изображения