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)
6.8 KiB
6.8 KiB
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(jsoncover_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".