Files
ds-galo/openspec/changes/lightroom-workspace-ui/proposal.md
T
iu 61b45b2742 feat: context menus, unified photo panel, tags, album trash and counters
- backend: deleting an album moves its photos to the trash without losing files (photos.album_id nullable, FK ON DELETE SET NULL, migration 000006; dropped S3 prefix delete); restore accepts an album target (album_required when the album is gone); user-scoped tags (000007) with GET /tags, POST/DELETE /photos/:id/tags, tags included in photo responses; GET /trash/count
- frontend: right-click context menus for photos (grid + viewer) and albums (rail + overview); single shared PhotoPanel reused in viewer and gallery selection (not a copy); viewer download/delete moved to the panel 'Действия'; transparent compact viewer top bar; trash entry as last rail item with per-album photo counts and trash count; album rename/delete dialogs
- openspec: sync lightroom-workspace-ui artifacts (specs photos/ui-workspace, design #24-30, tasks 9.17-9.24)
2026-10-10 22:45:41 +03:00

13 KiB

Proposal

Why

Сейчас интерфейс — это центрированный «маркетинговый» лейаут: список альбомов с инлайн-формой создания, серая заглушка вместо обложек, отдельные страницы «Участники» и «Настройки», лайтбокс-оверлей. Обложки в бэкенде уже есть (albums.cover_photo_id, PATCH /albums/:id), но до UI не доходят. Пользователь хочет полноценный «рабочий стол» в духе Adobe Lightroom: постоянный рейл альбомов, контекстная панель, плотная сетка, режим просмотра как часть рабочего стола, обложки с явным выбором и единый тёмный графитовый хром.

What Changes

  • Рабочий стол (шелл). Группа (app) с постоянным левым рейлом альбомов, топбаром и контекстной правой панелью. Публичные маршруты (/login, /invites/[token], /share/[token]) остаются вне шелла, но в тех же токенах.
  • Создание альбома. Инлайн-форма заменяется иконочной кнопкой с хинтом, открывающей модалку ввода названия.
  • Обложки. Album получает cover_thumb_url; карточки и рейл показывают реальную миниатюру. Выбор обложки: пикер в правой панели (действие «сделать обложкой» в просмотре не используется). Автообложка пишется только когда обложка ещё не задана; FK albums.cover_photo_id -> photos(id) ON DELETE SET NULL чинит висячие ссылки.
  • Просмотр как маршрут. Lightbox-оверлей заменяется маршрутом /albums/:id/photos/:photoId внутри шелла: крупное фото, filmstrip снизу, панель метаданных/комментариев. share/[token] переиспользует тот же компонент.
  • Плотность сетки. Слайдер размера миниатюр в тулбаре (состояние в localStorage). Мультивыбор и массовые действия — вне объёма.
  • Загрузка. Крупный dropzone заменяется кнопкой в тулбаре, полноэкранным drag-overlay и dropzone-намёком только в пустом альбоме. Лимит — 100 МБ с понятной ошибкой при превышении.
  • Переименование фото. PATCH /photos/:id меняет original_filename; инлайн-редактор в правой панели, доступный автору фото и owner/admin.
  • Метаданные фото (EXIF). При загрузке система извлекает все распознаваемые EXIF-атрибуты (камера, объектив, экспозиция, ISO, дата съёмки, GPS и др.) и хранит их в photos.exif; они возвращаются вместе с фото и показываются в разделе «Информация». Для ранее загруженных фото есть команда бэкфилла метаданных из оригиналов.
  • Метки фото. Пользователь присваивает фото свои метки: создаёт новые и выбирает из списка с поиском; метки показываются и снимаются в разделе «Метки» панели фото.
  • Контекстные меню. Правый клик по фото (в сетке и в просмотре) открывает меню с пунктами раздела «Действия»; правый клик по альбому (в рейле и на обзоре) — меню «Переименовать»/ «Удалить».
  • Удаление альбома. Удаление альбома помещает его фото в корзину, не удаляя объекты хранилища; при восстановлении фото без альбома предлагается выбрать существующий альбом или создать новый.
  • Просмотр. Полноэкранный режим (кнопка и f) с автоскрытием верхней/нижней панелей и стрелок у кромок; зум колесом к указателю (без прокрутки, максимум 200%), Space возвращает из любого зума во вписанный вид, в зуме догружается оригинал изображения; действия просмотра (скачать, удалить, перенести, копировать) — в правой панели, в разделе «Действия»; удаление с модальным подтверждением; возврат к обзору.
  • Разделы и панели. Правая панель — сворачиваемые разделы (состояние сохраняется), с разделом «Информация» (EXIF/метаданные); левая и правая панели ресайзятся перетаскиванием. Выбор фото в сетке показывается в панели (одиночный клик), двойной клик открывает просмотр.
  • Настройки информации. Раздел «Информация» получает кнопку-шестерёнку, открывающую модалку со списком EXIF-атрибутов: галочки видимости (с действиями «отметить все»/«снять все»), пользовательские подписи и сброс. Скрытые атрибуты сворачиваются под элементом «…» (клик раскрывает все). Настройки хранятся в профиле пользователя (server-side), применяются ко всем фото, а при отсутствии настроек показывается базовый набор; «Сбросить» удаляет настройки из профиля.
  • Мультивыбор и операции. Ctrl/Shift-выбор нескольких фото в сетке; в правой панели — раздел «Действия» с пунктами «Открыть (просмотр)», «Переместить», «Копировать», «Удалить»; перетаскивание выделенных фото на альбом в рейле открывает диалог перенос/копирование. Перенос и копирование меняют только метаданные (объекты S3 не трогаются). Любое удаление помещает фото в корзину; объекты S3 удаляются лишь когда на них нет ссылок в других альбомах. Корзина — последний элемент списка альбомов в левом рейле (иконка корзины); на обзоре убрана пустая правая панель.
  • Счётчики. В ответе альбома — число фото и участников; в рейле у каждого альбома показано число фото, у корзины — число удалённых фото.
  • Темы и хром. Существующие 4 темы сохраняются; dark — графит Lightroom и дефолт, neutral — тёплый графит; переключатель упорядочен тёмная → нейтральная → светлая → системная; добавляются токены --chrome/--canvas; скроллбары стилизованы в тон темы. Верхняя панель приложения и верхняя панель режима просмотра — компактные (минимум высоты).
  • Адаптив. На узких экранах рейл становится off-canvas drawer, правая панель — bottom-sheet, filmstrip — горизонтальным скроллом.

Capabilities

New Capabilities

  • ui-workspace: рабочий стол приложения — шелл, рейл альбомов, контекстная панель, режим просмотра как маршрут, адаптивное поведение и тёмный хром.

Modified Capabilities

  • albums: отображение обложки, счётчики фото/участников, явный выбор обложки и удаление в корзину.
  • photos: автообложка только при отсутствии выбора; переименование фото; лимит размера загрузки; извлечение и хранение EXIF-метаданных; перенос/копирование, корзина и метки.
  • auth: хранение пользовательских настроек отображения информации в профиле.

Impact

  • Backend: миграция FK albums.cover_photo_id -> photos(id) ON DELETE SET NULL; internal/albums/store.go (LEFT JOIN photos → cover_thumb_key и счётчики photos_count/members_count в ListForUser/GetByID); internal/albums/service.go (presign → CoverThumbURL, обогащение списка); internal/models (Album.CoverThumbURL, PhotosCount, MembersCount); internal/photos (автообложка только при cover_photo_id IS NULL; PATCH /photos/:id для переименования; лимит загрузки 100 МБ с 413 file_too_large; событие photo.updated; извлечение EXIF через github.com/dsoprea/go-exif/v3 в photos.exif, миграция 000003_photo_exif, команда cmd/backfill-exif и storage.Get); миграция users.preferences, models.User.Preferences, internal/auth (Me отдаёт настройки, PATCH /auth/me/preferences с валидацией); миграции 000005_photo_trash (мягкое удаление), 000006_photo_album_nullable (FK photos.album_id → ON DELETE SET NULL, удаление альбома в корзину), 000007_photo_tags (метки); GET /trash/GET /trash/count, POST /photos/:id/restore (c album_id), DELETE /photos/:id/permanent, POST /photo-batch/{delete,move,copy}, GET /tags, POST/DELETE /photos/:id/tags.
  • Frontend: реструктуризация +layout.svelte в группы (app)/(public), AppShell с ресайзом панелей и кнопкой полного экрана; компоненты рейла, контекстной панели со сворачиваемыми разделами и EXIF, модалки создания/пикера обложки/подтверждения, Viewer с полноэкранным режимом и зумом, общий стор альбомов, контрол плотности; новый маршрут albums/[id]/photos/[photoId]; слот действий в PanelSection, модалка настроек атрибутов с пользовательскими подписями, стор настроек, фильтрация и «…» в панели; новые значения токенов темы и стили скроллбаров; types.ts (+cover_thumb_url, счётчики, photos_count, preferences, tags); общие компоненты PhotoPanel, ContextMenu, TransferDialog, AlbumActionsDialogs; маршрут /trash; сторы selection, transfer, contextMenu, albumActions, trash, viewerActions; новые иконки в реестре.
  • Спеки: ui-workspace (новая), albums, photos, auth (дельты). ui-iconography не затрагивается — иконки по-прежнему наследуют цвет темы.
  • Совместимость: API-контракты сохраняются; добавляется поле ответа и один FK. Ломающих изменений API нет.