Files
ds-galo/openspec/changes/add-user-avatar/specs/user-profile/spec.md
T
iu 04617d1cdb feat(profile): add round avatar with upload and cropping
- backend: user_avatar_objects binding (PG+SQLite), GC preserves avatar blobs,
  avatar service (EXIF-stripping WebP 128/512), public avatar read route
- web: avatar upload/crop on profile, round avatar in header/members/comments/author
- android: avatar upload/crop, round avatar on profile and albums header
- openspec: add-user-avatar proposal/design/specs/tasks
2026-10-12 16:16:47 +03:00

6.5 KiB

Spec Delta

ADDED Requirements

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 представления возвращаются к заглушке, а объекты старого аватара освобождаются