Files
ds-galo/openspec/changes/lightroom-workspace-ui/tasks.md
T
iu 304cfedb75 feat: lightroom-style workspace UI with album covers
Backend:
- expose cover thumbnail URL on album responses (LEFT JOIN + presign)
- auto-assign cover only when empty; FK cover_photo_id -> photos ON DELETE SET NULL
- add photos_count / members_count to album responses; cover repo test

Frontend:
- split layouts into (app) shell (resizable rail + contextual panel) and (public)
- album rail + create-album dialog; album panel with cover picker / make-cover
- photo viewer route with filmstrip, replacing lightbox; share reuses it
- grid density slider, toolbar + drag-and-drop upload, dark graphite default

OpenSpec: add lightroom-workspace-ui change (proposal, design, specs, tasks)
2026-10-10 18:15:13 +03:00

6.8 KiB
Raw Blame History

Tasks

1. Backend: обложка и целостность

  • 1.1 Добавить миграцию 000002_album_cover_fk (up/down): обнулить висячие cover_photo_id, затем ADD CONSTRAINT ... FOREIGN KEY (cover_photo_id) REFERENCES photos(id) ON DELETE SET NULL. Проверка: make migrate применяется, \d albums показывает constraint, down-миграция снимает его.
  • 1.2 Добавить CoverThumbURL в models.Album (json cover_thumb_url,omitempty). Проверка: cd backend && go build ./... проходит.
  • 1.3 В albums/store.go добавить LEFT JOIN photos p ON p.id = a.cover_photo_id и выбирать p.thumb_key AS cover_thumb_key в ListForUser и GetByID. Проверка: запрос возвращает cover_thumb_key для альбома с обложкой и NULL без неё.
  • 1.4 В albums/service.go пресигнить cover_thumb_key в CoverThumbURL в List и Get. Проверка: GET /api/albums в ответе содержит cover_thumb_url у альбома с обложкой.
  • 1.5 В photos/service.go вызывать SetCover только при cover_photo_id IS NULL. Проверка: загрузка двух фото в новый альбом оставляет обложкой первое; после удаления фото-обложки cover становится NULL, следующая загрузка ставит новый.
  • 1.6 Покрыть тестами store-join обложки и автообложку; проверить cd backend && go test ./....

2. Frontend: темы и каркас

  • 2.1 Добавить токены --chrome/--canvas, перенастроить dark в графит и сделать его дефолтом (при отсутствии сохранённого выбора). Проверка: cd frontend && npm run check проходит, все три темы визуально согласованы.
  • 2.2 Добавить cover_thumb_url в lib/types.ts и недостающие иконки (обложка, плотность/меню) в lib/icons/registry.ts. Проверка: npm run check без ошибок типов.
  • 2.3 Разбить +layout.svelte на группы (app)/(public) и ввести AppShell (топбар, слот рейла, слот панели, центр = маршрут). Проверка: навигация между альбомами не перезагружает рейл; /login, /invites/[token], /share/[token] рендерятся без каркаса.
  • 2.4 Реализовать адаптивный каркас: рейл → drawer, панель → сворачиваемая секция, лента → горизонтальный скролл на узкой ширине. Проверка: при ширине меньше порога каркас управляем без горизонтального overflow.

3. Рейл и создание альбома

  • 3.1 Компонент AlbumRail: список альбомов с обложками, плейсхолдер, подсветка активного. Проверка: активный альбом выделен, остальные показывают обложку/плейсхолдер.
  • 3.2 Кнопка создания + с хинтом и модалка ввода названия (замена инлайн-формы). Проверка: создание альбома через модалку, новый альбом становится активным; пустое название не создаёт альбом.

4. Контекстная панель и обложки

  • 4.1 Компонент AlbumPanel: превью обложки, название, счётчики, переходы к участникам/настройкам/ссылкам; управление обложкой только для owner/admin. Проверка: viewer не видит управление обложкой.
  • 4.2 Модальный CoverPicker (сетка миниатюр) + PATCH /albums/:id с cover_photo_id/clear_cover. Проверка: назначение и сброс обложки отражаются в рейле, карточке и панели.
  • 4.3 Действие «Сделать обложкой» в тулбаре просмотра (роль-gated). Проверка: из просмотра текущее фото становится обложкой альбома.

5. Центр: сетка, плотность, загрузка

  • 5.1 Сетка альбомов edge-to-edge с реальными обложками вместо карточек-заглушек. Проверка: карточки показывают cover_thumb_url, при отсутствии — плейсхолдер.
  • 5.2 Регулятор плотности миниатюр в тулбаре сетки с сохранением в localStorage. Проверка: размер меняется и восстанавливается после перезагрузки.
  • 5.3 Загрузка: иконочная кнопка в тулбаре, полноэкранный drag-overlay, зона-подсказка в пустом альбоме; прогресс компактной полосой. Проверка: перетаскивание и выбор файлов загружают фото, пустой альбом показывает подсказку.

6. Просмотр как маршрут

  • 6.1 Маршрут albums/[id]/photos/[photoId] и компонент Viewer (крупное фото, filmstrip, панель метаданных/комментариев, тулбар, клавиши ←/→/Esc). Проверка: переход из сетки открывает маршрут, адрес отражает фото, навигация синхронна с filmstrip.
  • 6.2 Переиспользовать Viewer на share/[token] вместо инлайн-лайтбокса. Проверка: публичный просмотр использует тот же компонент без рейла/панели.

7. Интеграция

  • 7.1 Пройти сценарий: создать альбом → загрузить фото → задать обложку → открыть просмотр → открыть share-ссылку; проверить поведение на десктопе и узком экране.
  • 7.2 Проверить make build (сборка фронтенда в backend/static, статический Go-бинарник) и openspec validate "lightroom-workspace-ui".