chore(openspec): архивировать album-live-sync и синхронизировать основные спеки

- realtime: личный поток несёт события жизненного цикла альбома и изменения
  счётчика фото; добавлены требования о жизненном цикле, получателях, форме
  payload'а, догоне и потере доступа
- albums: photos_count считает только фото вне корзины
This commit is contained in:
iu
2026-10-15 23:25:07 +03:00
parent e82f45647c
commit 6e68242ec2
8 changed files with 556 additions and 2 deletions
+10 -1
View File
@@ -82,8 +82,17 @@
### Requirement: Счётчики альбома
Данные альбома SHALL включать количество фото и участников, чтобы панель и карточки могли
показать их без отдельных запросов.
показать их без отдельных запросов. Количество фото SHALL учитывать только фото, доступные в
альбоме (не помещённые в корзину), и совпадать с числом фото, отображаемых в сетке альбома.
#### Scenario: Счётчики в ответе
- **WHEN** клиент запрашивает список альбомов или альбом по id
- **THEN** ответ содержит число фото и число участников альбома
#### Scenario: Фото в корзине не учитывается
- **WHEN** фото альбома помещается в корзину
- **THEN** `photos_count` этого альбома уменьшается на единицу
#### Scenario: Фото восстановлено из корзины
- **WHEN** фото восстанавливается из корзины в альбом
- **THEN** `photos_count` этого альбома увеличивается на единицу
+100 -1
View File
@@ -28,12 +28,17 @@ comment.created, like.added, like.removed, member.joined, member.left, album.upd
- **THEN** подписчики получают событие photo.updated с этим фото
### Requirement: Персональный поток
Клиент SHALL иметь возможность подписаться на персональный поток (приглашения, уведомления).
Клиент SHALL иметь возможность подписаться на персональный поток (приглашения, уведомления,
изменения его альбомов).
#### Scenario: Подписка на персональный поток
- **WHEN** пользователь подключается к персональному потоку
- **THEN** система отправляет ему персональные события
#### Scenario: Изменение списка альбомов
- **WHEN** альбом, доступный пользователю, создан, изменён или удалён
- **THEN** пользователь получает соответствующее событие в персональном потоке
### Requirement: Авторизация и область доступа
Клиент SHALL подписываться только на доступные ему альбомы; токен передаётся в query-параметре.
@@ -66,3 +71,97 @@ comment.created, like.added, like.removed, member.joined, member.left, album.upd
#### Scenario: Обновление отсутствующего фото
- **WHEN** приходит событие обновления для фото, которого нет в текущем списке
- **THEN** клиент не добавляет его в сетку
### Requirement: События жизненного цикла альбома
Система SHALL публиковать в персональные потоки события `album.created` и `album.updated`
с объектом альбома и `album.deleted` с идентификатором альбома.
#### Scenario: Создание альбома
- **WHEN** пользователь создаёт альбом
- **THEN** владелец получает событие `album.created` с объектом альбома
#### Scenario: Изменение метаданных альбома
- **WHEN** участник с правом редактирования меняет название, описание или обложку
- **THEN** владелец и участники получают событие `album.updated` с актуальным объектом
#### Scenario: Удаление альбома
- **WHEN** владелец удаляет альбом
- **THEN** владелец и участники получают событие `album.deleted` с идентификатором
### Requirement: Получатели событий об альбоме
Система SHALL доставлять события жизненного цикла альбома владельцу и всем участникам
альбома, для которых он доступен.
#### Scenario: Веер по участникам
- **WHEN** альбом изменён
- **THEN** событие получает владелец и каждый участник альбома, включая инициатора изменения
#### Scenario: Принятие приглашения
- **WHEN** пользователь принимает приглашение в альбом
- **THEN** приглашённый получает событие о появлении альбома в своём списке, а владелец —
обновлённый объект альбома с новым числом участников
### Requirement: Единая форма объекта альбома в событиях
Объект альбома в событиях SHALL совпадать по форме с элементом ответа списка альбомов,
включая URL обложки и счётчики, чтобы клиент применял событие без дополнительных запросов.
#### Scenario: Объект события совпадает со списком
- **WHEN** клиент получает `album.created` или `album.updated`
- **THEN** объект содержит те же поля, что элемент ответа `GET /api/albums`
### Requirement: Применение события без повторного запроса
Клиент SHALL обновлять локальный список альбомов из payload'а события: создавать или
заменять альбом по полученному объекту и удалять его по идентификатору, не выполняя
дополнительный запрос списка.
#### Scenario: Обновление альбома из списка
- **WHEN** приходит событие обновления для альбома, который уже есть в списке клиента
- **THEN** клиент заменяет его на месте, не меняя порядок списка
#### Scenario: Удаление альбома из списка
- **WHEN** приходит событие удаления для альбома, который есть в списке клиента
- **THEN** клиент убирает альбом из списка
### Requirement: Догон состояния альбомов при переподключении
Клиент SHALL после восстановления персонального потока синхронизировать список альбомов
через REST, чтобы отразить изменения, пропущенные во время разрыва соединения.
#### Scenario: Переподключение персонального потока
- **WHEN** персональный поток восстанавливается после разрыва
- **THEN** клиент перезапрашивает список альбомов и приводит локальное состояние
к серверному
### Requirement: Потеря доступа к альбому
Клиент SHALL переставать отображать альбом, который удалён или к которому потерян доступ,
при получении соответствующего персонального события, в том числе на открытой странице
альбома.
#### Scenario: Альбом удалён во время просмотра
- **WHEN** владелец удаляет альбом, пока участник просматривает его страницу
- **THEN** участник получает событие и страница перестаёт отображать удалённый альбом
#### Scenario: Участник исключён из альбома
- **WHEN** участника исключают из альбома
- **THEN** исключённый получает событие, и альбом убирается из его списка
### Requirement: Обновление альбома при изменении состава фото
Система SHALL публиковать `album.updated` с актуальным объектом альбома в персональные потоки
владельца и участников, когда состав фото альбома меняется: загрузка, копирование, перемещение,
восстановление, перевод в корзину и окончательное удаление. При загрузке система также SHALL
публиковать `photo.created` в поток альбома, чтобы открытая страница добавляла новое фото.
#### Scenario: Загрузка фото
- **WHEN** пользователь загружает фото в альбом
- **THEN** владелец и участники получают `album.updated` с увеличенным `photos_count`
#### Scenario: Перемещение фото
- **WHEN** фото перемещается из одного альбома в другой
- **THEN** владелец и участники обоих альбомов получают `album.updated` с актуальными счётчиками
#### Scenario: Фото в корзине
- **WHEN** фото переводится в корзину или восстанавливается
- **THEN** владелец и участники получают `album.updated` с обновлённым `photos_count`
#### Scenario: Окончательное удаление фото
- **WHEN** фото удаляется окончательно
- **THEN** владелец и участники получают `album.updated` с уменьшенным `photos_count`