Files
ds-galo/openspec/changes/archive/2026-10-15-album-live-sync/tasks.md
T
iu 6e68242ec2 chore(openspec): архивировать album-live-sync и синхронизировать основные спеки
- realtime: личный поток несёт события жизненного цикла альбома и изменения
  счётчика фото; добавлены требования о жизненном цикле, получателях, форме
  payload'а, догоне и потере доступа
- albums: photos_count считает только фото вне корзины
2026-10-15 23:25:07 +03:00

46 lines
9.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Tasks
## 1. Аудитория альбома и доставка в личный поток
- [x] 1.1 Добавить в `members.Repository` метод, возвращающий id пользователей альбома (владелец + участники) без join с `users`; реализовать в sqlite- и postgres-сторах; проверить новым тестом репозитория: `cd backend && go test ./internal/members/`
- [x] 1.2 Добавить в `albums.Service` публикацию события альбома в личные каналы получателей: перечитать альбом через `Store.GetByID` и обогатить `attachCover`, разослать по аудитории через `Hub.PublishUser`; закрыть доступ к резолверу аудитории интерфейсом для `members.Service`; проверить тестом с подпиской `Hub.SubscribeUser`, что получатель видит событие с тем же набором полей, что элемент `GET /api/albums`
- [x] 1.3 Проверить, что публикация в личный поток безопасна при отсутствии подписчиков и не затрагивает пер-альбомный канал: тест на хаб, где событие уходит пользователю без подписки, не паникует и не создаёт подписку, а подписчик канала альбома событие не получает; `cd backend && go test ./internal/sse/ ./internal/albums/`
## 2. Создание, метаданные и удаление альбома
- [x] 2.1 Публиковать `album.created` владельцу при создании альбома; проверить тестом, что владелец получает событие, а объект перечитан и содержит `photos_count` и `members_count`
- [x] 2.2 Публиковать `album.updated` владельцу и участникам при изменении названия, описания и обложки, сохранив существующую публикацию в канал альбома; проверить тестом, что обе подписки получают событие и payload совпадает по полям с ответом `GET /api/albums/:id`
- [x] 2.3 Публиковать `album.deleted` с идентификатором владельцу и участникам, вычисляя аудиторию до удаления альбома (состав удаляется каскадом); проверить тестом, что событие получено владельцем и участником, а после удаления `members.List` для альбома пуст
## 3. Состав участников
- [x] 3.1 При принятии приглашения публиковать `album.created` приглашённому и `album.updated` владельцу и остальным участникам; проверить тестом, что приглашённый получает ровно одно событие с объектом альбома, а владелец — обновлённый `members_count`
- [x] 3.2 При смене роли участника публиковать `album.updated` владельцу и участникам; проверить тестом, что событие получает и пользователь, чью роль изменили
- [x] 3.3 При исключении участника публиковать `album.updated` оставшимся и `album.deleted` с идентификатором исключённому; проверить тестом, что исключённый получает ровно одно событие и в нём нет объекта альбома
- [x] 3.4 Обновить документацию контракта в `project.md` (§11 «Real-time (SSE)» и §12 «SSE — детали реализации»): состав событий личного потока, форма payload'а, догон списка альбомов при переподключении; проверить, что перечисленные типы событий совпадают с реализованными публикациями, а описанные поля — с ответом `GET /api/albums`
## 4. Web-клиент
- [x] 4.1 Подписаться на `/api/sse/me` один раз на уровне layout'а `(app)`: `album.created` и `album.updated` применять через `albums.upsert`, `album.deleted` — через `albums.remove`, на `onReconnect` вызывать `albums.load()`; проверить `cd frontend && npm run check` и сценарием в двух вкладках: переименование и смена обложки отражаются без перезагрузки, порядок списка не меняется
- [x] 4.2 Обрабатывать потерю доступа на странице альбома: при событии удаления/исключения страница перестаёт отображать альбом и уходит на главную; проверить сценарием: владелец удаляет альбом, у участника с открытой страницей происходит переход на главную, а альбом исчезает из рейла
- [x] 4.3 Проверить жизненный цикл подписки: соединение создаётся один раз за сессию, не пересоздаётся при навигации между страницами и закрывается при выходе из аккаунта; проверить в DevTools (одно соединение `/api/sse/me` на сессию) и сценарием logout/login
## 5. Интеграционная проверка
- [x] 5.1 Сквозной сценарий на двух аккаунтах (два профиля браузера) на локальном сервере: создание альбома, приглашение, смена роли, исключение, удаление — список и открытая страница у второго пользователя обновляются без перезагрузки; проверить вручную и приложить результат (какие шаги и что наблюдалось)
- [x] 5.2 Проверить догон состояния: остановить сервер, изменить и удалить альбом, поднять сервер и убедиться, что после восстановления потока список на клиенте совпадает с `GET /api/albums` (удалённый альбом не возвращается); проверить сценарием и приложить вывод
- [x] 5.3 Прогнать на финальной ревизии `make test`, `cd frontend && npm run check` и `cd frontend && npm run build`; зафиксировать, что все три проходят без ошибок
## 6. Живое обновление состава фото
- [x] 6.1 В `albums.Service` добавить рассылку `album.updated` получателям личного потока без публикации в канал альбома (перечитать через `GetByID` + `attachCover`); закрыть метод интерфейсом для `photos.Service`; проверить тестом, что после вызова получатель видит событие, а подписчик канала альбома — нет
- [x] 6.2 Публиковать `photo.created` при загрузке фото и `album.updated` получателям при загрузке, копировании, перемещении, восстановлении, переводе в корзину и окончательном удалении; проверить тестом, что `photos_count` меняется у владельца и участника, а подписчик канала альбома получает `photo.created`
- [x] 6.3 Считать `photos_count` только по фото вне корзины: добавить `deleted_at IS NULL` в подзапросы счётчика в sqlite- и postgres-сторах; проверить тестом, что перевод в корзину уменьшает, а восстановление увеличивает счётчик
- [x] 6.4 Обновить `project.md` (§11/§12): состав фото в личном потоке, `photo.created` при загрузке, семантика `photos_count`
- [x] 6.5 Прогнать `make test`, `cd frontend && npm test`, `cd frontend && npm run check` и `cd frontend && npm run build`
## Workflow follow-up
- Заархивировать change после прохождения ревью проекта (`openspec archive album-live-sync`).
- Проверить, что после архивации дельта вошла в `openspec/specs/realtime/spec.md`, а `openspec validate --strict album-live-sync` не выдаёт ошибок.