15 KiB
user-profile Specification
Purpose
Управление аккаунтом пользователя: просмотр и изменение профиля, смена пароля с отзывом сессий, добавление второго идентификатора входа и удаление аккаунта со всем содержимым — единообразно в веб-интерфейсе и Android-клиенте.
Requirements
Requirement: Просмотр собственного профиля
Пользователь SHALL получать свой профиль с именем, email, телефоном и аватаром. Телефон SHALL быть виден только владельцу и SHALL NOT попадать в публичные представления пользователя (участники альбома, загрузчики, комментарии).
Scenario: Получение профиля
- WHEN аутентифицированный пользователь запрашивает свой профиль
- THEN ответ содержит его имя, email (если задан), телефон (если задан) и аватар
Scenario: Телефон не утекает
- WHEN пользователь просматривает участников альбома
- THEN представления других пользователей не содержат телефон
Requirement: Изменение имени
Пользователь SHALL изменять своё имя. Пустое имя SHALL отклоняться. Смена имени SHALL применяться немедленно и отражаться при следующем чтении профиля.
Scenario: Успешное изменение
- WHEN пользователь отправляет непустое имя
- THEN система сохраняет его и возвращает обновлённый профиль
Scenario: Пустое имя
- WHEN пользователь отправляет пустое имя
- THEN система отклоняет запрос и не меняет профиль
Requirement: Смена пароля с отзывом сессий
Пользователь SHALL менять пароль, подтвердив текущий пароль. Система SHALL отклонять неверный текущий пароль и новый пароль короче 8 символов. Успешная смена SHALL отзывать все refresh-токены пользователя на всех устройствах.
Scenario: Успешная смена
- WHEN пользователь вводит верный текущий пароль и новый пароль допустимой длины
- THEN система сохраняет новый хэш и отзывает все refresh-токены пользователя
Scenario: Неверный текущий пароль
- WHEN пользователь вводит неверный текущий пароль
- THEN система возвращает ошибку и не меняет пароль
Scenario: Слабый новый пароль
- WHEN новый пароль короче 8 символов
- THEN система отклоняет запрос и сохраняет старый пароль
Requirement: Добавление недостающего идентификатора
Пользователь с одним заданным идентификатором (email или телефон) SHALL добавить недостающий один раз после проверки уникальности. Система SHALL отклонять добавление, когда оба идентификатора уже заданы, а также изменение или удаление заданного. После добавления оба идентификатора SHALL работать для входа.
Scenario: Добавление телефона
- WHEN пользователь без телефона добавляет свободный номер в формате E.164
- THEN система сохраняет номер, и вход по нему становится возможен
Scenario: Занятый идентификатор
- WHEN добавляемый email или телефон уже принадлежит другому пользователю
- THEN система возвращает ошибку конфликта и не меняет профиль
Scenario: Оба уже заданы
- WHEN у пользователя уже заданы и email, и телефон, и он пытается добавить третий
- THEN система отклоняет запрос
Requirement: Удаление аккаунта со всем содержимым
Пользователь SHALL удалять свой аккаунт, подтвердив текущий пароль. Неверный пароль SHALL отклоняться. Успешное удаление SHALL быть немедленным и необратимым: SHALL каскадно удаляться альбомы пользователя (вместе с доступом других участников), его фото, комментарии, лайки, метки, уведомления, share-ссылки и приглашения. Блобы SHALL освобождаться фоновой сверкой хранилища, а не в транзакции удаления.
Scenario: Успешное удаление
- WHEN пользователь подтверждает удаление верным текущим паролем
- THEN учётная запись и связанное содержимое удаляются, и вход больше невозможен
Scenario: Общие альбомы
- WHEN удаляемый пользователь владеет альбомом, в котором есть другие участники
- THEN альбом удаляется вместе с ними
Scenario: Неверный пароль
- WHEN пользователь подтверждает удаление неверным паролем
- THEN система возвращает ошибку и не удаляет аккаунт
Requirement: Страница профиля в веб-интерфейсе
Веб-приложение SHALL предоставлять отдельную страницу профиля, доступную из шапки, с показом идентификаторов и формами изменения имени, смены пароля и удаления аккаунта.
Scenario: Открытие страницы
- WHEN аутентифицированный пользователь открывает профиль из шапки
- THEN отображаются его идентификаторы и формы редактирования
Scenario: Выход после смены пароля
- WHEN смена пароля завершилась успешно
- THEN клиент очищает токены и перенаправляет на страницу входа
Scenario: Выход после удаления
- WHEN удаление аккаунта завершилось успешно
- THEN клиент очищает токены и перенаправляет на страницу входа
Requirement: Экран профиля в Android-клиенте
Android-приложение SHALL предоставлять отдельный экран профиля, доступный из списка альбомов, с теми же возможностями, что и веб-страница.
Scenario: Открытие экрана
- WHEN пользователь открывает профиль из списка альбомов
- THEN отображаются идентификаторы и формы редактирования
Scenario: Возврат после смены пароля
- WHEN смена пароля завершилась успешно
- THEN приложение очищает токены и возвращает на экран входа
Scenario: Возврат после удаления
- WHEN удаление аккаунта завершилось успешно
- THEN приложение очищает токены и возвращает на экран входа
Requirement: Загрузка фото профиля с выбором области
Пользователь SHALL загружать собственное фото в профиль, выбирая видимую квадратную область. Сохранённый аватар SHALL соответствовать выбранной области. Загрузка SHALL быть доступна только владельцу профиля.
Scenario: Успешная загрузка
- WHEN пользователь выбирает изображение и подтверждает квадратную область
- THEN аватар обновляется и возвращается в профиле
Scenario: Выбранная область учтена
- WHEN пользователь сдвигает или масштабирует область перед подтверждением
- THEN сохранённый аватар показывает именно выбранную область
Scenario: Не изображение
- WHEN загруженный файл не является декодируемым изображением
- THEN система отклоняет запрос и не меняет аватар
Requirement: Нормализация аватара и снятие метаданных
Система SHALL сохранять аватар в виде квадратных изображений фиксированных размеров и SHALL NOT сохранять EXIF-метаданные загруженного файла.
Scenario: Метаданные не сохраняются
- WHEN загружено изображение с EXIF, включая GPS-координаты
- THEN сохранённый аватар не содержит EXIF и GPS
Scenario: Слишком большой файл
- WHEN размер загруженного файла превышает допустимый предел
- THEN система отклоняет запрос и не меняет аватар
Requirement: Отдача аватара по стабильному URL
Профиль и публичные представления пользователя SHALL содержать URL аватара, когда он задан. URL SHALL быть стабильным и SHALL изменяться при обновлении аватара, чтобы клиентские кэши инвалидировались. Изображение SHALL отдаваться по публичной ссылке без аутентификации, чтобы его могли загружать теги изображений и клиентские загрузчики.
Scenario: Ссылка в представлениях пользователя
- WHEN аутентифицированный клиент запрашивает профиль, участников альбома, комментарии или автора фото
- THEN представления содержат URL аватара, если он задан
Scenario: Кэш инвалидируется при замене
- WHEN пользователь заменяет аватар
- THEN URL аватара изменяется
Scenario: Загрузка изображения без заголовка авторизации
- WHEN браузер или клиентский загрузчик изображений запрашивает изображение аватара по URL без заголовка авторизации
- THEN система отдаёт изображение
Requirement: Круглое отображение аватара в веб-интерфейсе
Веб-приложение SHALL отображать аватар пользователя круглым в шапке, на странице профиля, у участников альбома, в комментариях и у автора фото.
Scenario: Аватар в шапке
- WHEN аутентифицированный пользователь открывает любое место приложения
- THEN в шапке отображается его круглый аватар
Scenario: Аватар рядом с другими пользователями
- WHEN пользователь просматривает участников, комментарии или автора фото
- THEN аватары этих пользователей отображаются круглыми
Requirement: Круглое отображение аватара в Android-клиенте
Android-приложение SHALL отображать аватар пользователя круглым на экране профиля и в шапке списка альбомов.
Scenario: Аватар на экране профиля
- WHEN пользователь открывает экран профиля
- THEN отображается его круглый аватар
Scenario: Аватар в шапке списка альбомов
- WHEN пользователь открывает список альбомов
- THEN в шапке отображается его круглый аватар
Requirement: Заглушка при отсутствии аватара
Когда аватар не задан, система SHALL показывать нейтральную заглушку-силуэт вместо изображения.
Scenario: Аватар не задан
- WHEN у пользователя нет аватара и его представление отображается в вебе или Android
- THEN вместо изображения показывается нейтральная круглая заглушка-силуэт
Requirement: Удаление аватара
Пользователь SHALL удалять свой аватар; после удаления SHALL показываться заглушка, а связанные объекты хранилища SHALL освобождаться.
Scenario: Сброс аватара
- WHEN пользователь удаляет аватар
- THEN представления возвращаются к заглушке, а объекты старого аватара освобождаются