chore(openspec): archive shared-album and sync main specs

Move the completed shared-album change to
openspec/changes/archive/2026-10-10-shared-album/ and create the 8 main
specs (albums, auth, members, notifications, photos, realtime, share-links,
social) from the delta ADDED requirements.
This commit is contained in:
iu
2026-10-10 12:58:34 +03:00
parent 2b2b342492
commit 84ce4d1930
20 changed files with 373 additions and 0 deletions
+42
View File
@@ -0,0 +1,42 @@
# albums Specification
## Purpose
Управление фотоальбомами: создание, просмотр, редактирование, удаление и владение.
## Requirements
### Requirement: Создание альбома
Зарегистрированный пользователь SHALL иметь возможность создать альбом и стать его владельцем.
#### Scenario: Создание альбома
- **WHEN** пользователь создаёт альбом с названием
- **THEN** система создаёт альбом и назначает пользователя владельцем
### Requirement: Список альбомов пользователя
Пользователь SHALL иметь возможность получить список альбомов, к которым у него есть доступ.
#### Scenario: Список альбомов
- **WHEN** пользователь запрашивает список альбомов
- **THEN** система возвращает альбомы, где он владелец или участник
### Requirement: Получение альбома
Участник SHALL иметь возможность получить данные альбома по id.
#### Scenario: Просмотр альбома
- **WHEN** участник запрашивает альбом по id
- **THEN** система возвращает данные альбома
### Requirement: Редактирование альбома
Владелец и админ SHALL иметь возможность редактировать название, описание и обложку альбома.
#### Scenario: Редактирование альбома
- **WHEN** админ изменяет описание альбома
- **THEN** система сохраняет изменения
### Requirement: Удаление альбома
Владелец SHALL иметь возможность удалить альбом вместе с содержимым.
#### Scenario: Удаление альбома
- **WHEN** владелец удаляет альбом
- **THEN** система удаляет альбом, его фото, участников и share-ссылки
+47
View File
@@ -0,0 +1,47 @@
# auth Specification
## Purpose
Регистрация и аутентификация пользователей по email и паролю с выдачей краткоживущих и долгоживущих JWT-токенов.
## Requirements
### Requirement: Регистрация пользователя
Пользователь SHALL иметь возможность зарегистрироваться, указав email, пароль и имя. Пароль SHALL храниться в виде bcrypt-хэша.
#### Scenario: Успешная регистрация
- **WHEN** пользователь отправляет уникальный email, пароль и имя
- **THEN** система создаёт учётную запись и возвращает access- и refresh-токены
#### Scenario: Повторный email
- **WHEN** пользователь регистрируется с уже занятым email
- **THEN** система возвращает ошибку конфликта и не создаёт вторую запись
### Requirement: Вход по email и паролю
Пользователь SHALL иметь возможность войти, указав email и пароль.
#### Scenario: Успешный вход
- **WHEN** пользователь вводит верные email и пароль
- **THEN** система возвращает access- и refresh-токены
#### Scenario: Неверные учётные данные
- **WHEN** пользователь вводит неверный email или пароль
- **THEN** система возвращает 401, не раскрывая, какое именно поле неверно
### Requirement: Обновление access-токена
Пользователь SHALL иметь возможность обменять refresh-токен на новую пару токенов. Access-токен живёт 15 минут, refresh-токен — 30 дней.
#### Scenario: Валидный refresh-токен
- **WHEN** пользователь предоставляет действующий refresh-токен
- **THEN** система выдаёт новый access-токен и ротирует refresh-токен
#### Scenario: Недействительный refresh-токен
- **WHEN** пользователь предоставляет истёкший или отозванный refresh-токен
- **THEN** система возвращает 401
### Requirement: Выход из системы
Пользователь SHALL иметь возможность выйти, отозвав refresh-токен.
#### Scenario: Выход
- **WHEN** пользователь вызывает logout с действующим refresh-токеном
- **THEN** система отзывает refresh-токен, и его дальнейшее использование отклоняется
+65
View File
@@ -0,0 +1,65 @@
# members Specification
## Purpose
Управление составом альбома, ролями и правами доступа, включая приглашения по токену.
## Requirements
### Requirement: Роли участников
Участник альбома SHALL иметь одну из ролей: admin, editor, member, viewer. Владелец выводится из albums.owner_id и не хранится как роль участника.
#### Scenario: Создатель становится владельцем
- **WHEN** пользователь создаёт альбом
- **THEN** система делает его владельцем альбома
### Requirement: Матрица прав
Система SHALL ограничивать действия по ролям: загружать фото могут owner/admin/editor/member; удалять чужие фото — owner/admin; удалять свои — owner/admin/editor/member; комментировать — owner/admin/editor/member; скачивать одиночное фото и просматривать — все участники, включая viewer.
#### Scenario: Наблюдатель не может загружать
- **WHEN** участник с ролью viewer пытается загрузить фото
- **THEN** система отклоняет запрос
#### Scenario: Участник не может удалять чужие фото
- **WHEN** участник с ролью member пытается удалить фото другого автора
- **THEN** система отклоняет запрос
### Requirement: Приглашение участников
Владелец и админ SHALL иметь возможность создавать инвайт-ссылку с токеном. Редактор SHALL иметь возможность приглашать только на роли member и viewer. Никто не может приглашать на роль выше своей.
#### Scenario: Админ приглашает участника
- **WHEN** админ создаёт инвайт на роль member
- **THEN** система создаёт инвайт с токеном и сроком действия
#### Scenario: Редактор не может приглашать админа
- **WHEN** редактор пытается создать инвайт на роль admin или editor
- **THEN** система отклоняет запрос
### Requirement: Принятие инвайта
Пользователь SHALL иметь возможность стать участником, перейдя по токену инвайта.
#### Scenario: Принятие действующего инвайта
- **WHEN** пользователь принимает неистёкший инвайт с неисчерпанным лимитом использования
- **THEN** система добавляет его в состав альбома с ролью из инвайта
#### Scenario: Принятие истёкшего инвайта
- **WHEN** пользователь принимает истёкший инвайт
- **THEN** система отклоняет запрос
### Requirement: Смена ролей
Админ SHALL иметь возможность менять роли editor/member/viewer. Владелец SHALL управлять ролями админов. Никто не может менять роль выше своей и не может трогать владельца.
#### Scenario: Админ меняет роль участника
- **WHEN** админ повышает участника до editor
- **THEN** система обновляет роль
#### Scenario: Админ не может назначить админа
- **WHEN** админ пытается назначить другому участнику роль admin
- **THEN** система отклоняет запрос
### Requirement: Удаление участника
Владелец и админ SHALL иметь возможность удалять участников, кроме владельца и других админов.
#### Scenario: Удаление участника
- **WHEN** админ удаляет участника с ролью member/viewer/editor
- **THEN** система убирает его из состава альбома
+28
View File
@@ -0,0 +1,28 @@
# notifications Specification
## Purpose
Персональные уведомления пользователя о событиях (комментарии, лайки, участники) и их статус прочитано.
## Requirements
### Requirement: Создание уведомления
Система SHALL создавать уведомление пользователю при наступлении события (комментарий к его фото, лайк, добавление в альбом).
#### Scenario: Комментарий к моему фото
- **WHEN** другой пользователь комментирует фото пользователя
- **THEN** система создаёт уведомление этому пользователю
### Requirement: Список уведомлений
Пользователь SHALL иметь возможность получить свои уведомления.
#### Scenario: Получение уведомлений
- **WHEN** пользователь запрашивает уведомления
- **THEN** система возвращает список с признаком прочитано
### Requirement: Отметка прочитанным
Пользователь SHALL иметь возможность отметить уведомление прочитанным.
#### Scenario: Отметить прочитанным
- **WHEN** пользователь отмечает уведомление прочитанным
- **THEN** система фиксирует время прочтения
+57
View File
@@ -0,0 +1,57 @@
# photos Specification
## Purpose
Загрузка, хранение в S3 и просмотр фотографий с генерацией вариантов и извлечением EXIF.
## Requirements
### Requirement: Загрузка фото
Пользователь с правом загрузки SHALL иметь возможность загружать фото по одному и массово.
#### Scenario: Успешная загрузка
- **WHEN** участник с правом загрузки отправляет файл изображения
- **THEN** система сохраняет оригинал и создаёт запись фото с метаданными
#### Scenario: Загрузка без права
- **WHEN** наблюдатель пытается загрузить фото
- **THEN** система отклоняет запрос
### Requirement: Варианты изображений
Система SHALL генерировать три варианта: thumb (200px), preview (1200px) и оригинал, с WebP для превью, и извлекать EXIF (дата, координаты, размеры).
#### Scenario: Генерация вариантов
- **WHEN** фото загружено
- **THEN** система асинхронно генерирует thumb и preview и заполняет EXIF-поля
### Requirement: Листинг фото с пагинацией
Система SHALL возвращать фото альбома с cursor-пагинацией.
#### Scenario: Пагинация по курсору
- **WHEN** клиент запрашивает список с курсором и лимитом
- **THEN** система возвращает не более лимита фото и курсор следующей страницы
### Requirement: Получение фото по требованию
Клиент SHALL иметь возможность получить актуальные данные фото с presigned URL.
#### Scenario: Выдача свежего URL
- **WHEN** клиент запрашивает фото по id
- **THEN** система возвращает свежий presigned URL (срок до 1 часа) для просмотра
### Requirement: Скачивание одиночного фото
Любой участник, включая viewer, SHALL иметь возможность скачать одиночное фото.
#### Scenario: Скачивание фото
- **WHEN** участник запрашивает скачивание фото
- **THEN** система возвращает presigned URL оригинала
### Requirement: Удаление фото
Автор SHALL иметь возможность удалить своё фото; владелец и админ SHALL иметь возможность удалить любое фото.
#### Scenario: Удаление своего фото
- **WHEN** автор удаляет своё фото
- **THEN** система удаляет запись и файлы в S3
#### Scenario: Удаление чужого фото участником
- **WHEN** участник с ролью member пытается удалить чужое фото
- **THEN** система отклоняет запрос
+49
View File
@@ -0,0 +1,49 @@
# realtime Specification
## Purpose
Поток событий альбома и персональный поток через Server-Sent Events.
## Requirements
### Requirement: Подписка на события альбома
Клиент SHALL иметь возможность подписаться на события конкретного альбома через SSE.
#### Scenario: Подписка на альбом
- **WHEN** участник подключается к SSE-потоку альбома
- **THEN** система устанавливает text/event-stream и отправляет heartbeat
### Requirement: События альбома
Система SHALL публиковать события photo.created, photo.deleted, comment.created, like.added, like.removed, member.joined, member.left, album.updated.
#### Scenario: Новое фото
- **WHEN** в альбоме появляется фото
- **THEN** подписчики получают событие photo.created с метаданными и URL превью
### Requirement: Персональный поток
Клиент SHALL иметь возможность подписаться на персональный поток (приглашения, уведомления).
#### Scenario: Подписка на персональный поток
- **WHEN** пользователь подключается к персональному потоку
- **THEN** система отправляет ему персональные события
### Requirement: Авторизация и область доступа
Клиент SHALL подписываться только на доступные ему альбомы; токен передаётся в query-параметре.
#### Scenario: Подписка на недоступный альбом
- **WHEN** пользователь подписывается на альбом, к которому нет доступа
- **THEN** система отклоняет подключение
### Requirement: Устойчивость соединения
Система SHALL отправлять heartbeat каждые 25 секунд и отключать медленных клиентов при переполнении буфера.
#### Scenario: Переполнение буфера клиента
- **WHEN** буфер клиента переполняется
- **THEN** система отключает клиента
### Requirement: Догон пропущенного
Клиент SHALL иметь возможность догнать пропущенные события через REST.
#### Scenario: Переподключение
- **WHEN** клиент переподключается после разрыва
- **THEN** клиент догоняет события через запрос фото с параметром since
+46
View File
@@ -0,0 +1,46 @@
# share-links Specification
## Purpose
View-only доступ к альбому по ссылке без авторизации, с несколькими ссылками, сроком действия и отзывом.
## Requirements
### Requirement: Создание ссылки для просмотра
Владелец и админ SHALL иметь возможность создать ссылку для просмотра альбома с заданным сроком действия.
#### Scenario: Создание ссылки
- **WHEN** админ создаёт share-ссылку со сроком действия
- **THEN** система создаёт токен и возвращает URL для просмотра
### Requirement: Несколько ссылок
Альбом SHALL поддерживать несколько независимых share-ссылок.
#### Scenario: Отзыв одной ссылки не затрагивает другие
- **WHEN** владелец отзывает одну ссылку
- **THEN** остальные ссылки остаются действующими
### Requirement: Просмотр альбома по ссылке
Пользователь без авторизации SHALL иметь возможность просматривать альбом по действующему токену (сетка, лайтбокс, скачивание одиночного фото).
#### Scenario: Просмотр по действующей ссылке
- **WHEN** аноним открывает ссылку с действующим токеном
- **THEN** система возвращает фото альбома со свежими presigned URL
#### Scenario: Истёкшая или отозванная ссылка
- **WHEN** аноним открывает ссылку с истёкшим или отозванным токеном
- **THEN** система отклоняет доступ
### Requirement: Ограничения по ссылке
Доступ по ссылке SHALL быть только на просмотр: без комментариев, лайков, загрузки и управления участниками.
#### Scenario: Аноним не может комментировать
- **WHEN** аноним по ссылке пытается добавить комментарий
- **THEN** система отклоняет запрос
### Requirement: Отзыв ссылки
Владелец и админ SHALL иметь возможность отозвать ссылку.
#### Scenario: Отзыв ссылки
- **WHEN** владелец отзывает share-ссылку
- **THEN** система прекращает доступ по этому токену
+39
View File
@@ -0,0 +1,39 @@
# social Specification
## Purpose
Лайки и комментарии к фотографиям.
## Requirements
### Requirement: Лайк фото
Пользователь с правом комментирования SHALL иметь возможность поставить и убрать лайк.
#### Scenario: Поставить лайк
- **WHEN** участник ставит лайк фото
- **THEN** система фиксирует лайк и публикует событие like.added
#### Scenario: Убрать лайк
- **WHEN** участник убирает лайк
- **THEN** система удаляет лайк и публикует событие like.removed
### Requirement: Комментарий к фото
Пользователь с правом комментирования SHALL иметь возможность добавить комментарий.
#### Scenario: Добавить комментарий
- **WHEN** участник добавляет комментарий
- **THEN** система сохраняет комментарий и публикует событие comment.created
### Requirement: Список комментариев
Система SHALL возвращать комментарии фото.
#### Scenario: Получение комментариев
- **WHEN** клиент запрашивает комментарии фото
- **THEN** система возвращает список комментариев с авторами
### Requirement: Удаление комментария
Автор комментария (или владелец/админ) SHALL иметь возможность удалить комментарий.
#### Scenario: Удаление своего комментария
- **WHEN** автор удаляет свой комментарий
- **THEN** система удаляет комментарий