Files
ds-galo/openspec/changes/archive/2026-10-12-add-user-avatar/tasks.md
T

7.1 KiB
Raw Blame History

Tasks

1. Модель данных и сборка мусора

  • 1.1 Добавить миграцию Postgres 000014_user_avatar_objects.up.sql/.down.sql и SQLite 000006_user_avatar_objects.up.sql/.down.sql: таблица user_avatar_objects(user_id, object_id, role) с FK на users и objects и уникальностью (user_id, role); проверить, что тесты миграций (go test ./internal/db/...) проходят и make migrate применяет и откатывает.
  • 1.2 Расширить ClaimGarbage в Postgres-сторе (internal/photos/objects.go): не считать мусором объекты, на которые ссылается user_avatar_objects; проверить тестом, что привязанный объект аватара переживает сборку, а после снятия привязки освобождается.
  • 1.3 Расширить ClaimGarbage в SQLite-сторе (internal/photos/sqlite_objects.go) тем же исключением; проверить аналогичным тестом на SQLite.
  • 1.4 Добавить методы стора для аватара (привязать/заменить/снять по ролям avatar/avatar_small, получить текущие объекты) на обоих бэкендах; проверить контрактным тестом, покрывающим оба бэкенда.

2. Backend: нормализация и жизненный цикл объекта аватара

  • 2.1 Реализовать нормализацию аватара: декодировать, отклонить не-изображение, imaging.Fill в 512 и 128, перекодировать в WebP (снятие EXIF/GPS); проверить юнит-тестом на JPEG с EXIF/GPS — результат квадратный 512 и 128 без EXIF.
  • 2.2 Реализовать сервис установки/замены/удаления аватара через журнал объектов (pending → Put → ready → привязка, откат при ошибке); проверить тестом, что сбой не оставляет объектов, а успех привязывает обе роли.
  • 2.3 Применить предел размера файла (10 MB) и отклонение не-изображений на границе сервиса; проверить тестами на превышение размера и на не-изображение.

3. Backend: API и отдача

  • 3.1 Добавить хендлеры POST /api/auth/me/avatar (multipart file) и DELETE /api/auth/me/avatar, возвращающие обновлённый self-профиль; проверить тестами: без аутентификации — отказ, после загрузки avatar_url задан, после удаления — пуст.
  • 3.2 Добавить отдачу GET /api/avatars/:userID/:version (малая нарезка, ?size=large — крупная) под авторизацией; проверить тестами: без аутентификации — отказ, версия меняется при замене, отсутствующий пользователь/аватар — корректная ошибка.
  • 3.3 Зарегистрировать маршруты в internal/app/app.go; проверить тестом маршрутизации, что новые пути доступны и защищены middleware.

4. Аватар в представлениях пользователей

  • 4.1 Убедиться, что auth/me, участники, комментарии и автор фото отдают заполненный avatar_url (запросы уже выбирают колонку) и что PublicUser/SelfUser сериализуют поле; проверить тестами: у пользователя с аватаром avatar_url присутствует, без аватара — пуст.

5. Веб-интерфейс

  • 5.1 Добавить в lib/api.ts методы загрузки и удаления аватара и сохранять avatar_url в auth-стор; проверить npm run check (типы) без ошибок.
  • 5.2 Добавить иконку person в lib/icons/registry.ts и компонент круглого аватара с заглушкой-силуэтом; проверить, что компонент показывает изображение при заданном URL и силуэт при пустом.
  • 5.3 На странице routes/(app)/profile добавить выбор файла, канвас-кроппер и кнопки загрузки/удаления; проверить вручную: загрузка меняет аватар, удаление возвращает заглушку.
  • 5.4 Показывать круглый аватар в AppShell (шапка), у участников, в Comments.svelte и у автора в PhotoPanel.svelte; проверить визуально, что заглушка и реальный аватар отображаются круглыми.

6. Android-клиент

  • 6.1 Добавить в ProfileApi/GaloApi загрузку (multipart) и удаление аватара, а ProfileViewModel — avatarUrl и действия; проверить юнит-тестами ViewModel (успех, ошибка, обновление состояния).
  • 6.2 На ProfileScreen показать круглый аватар, выбор изображения и Compose-кроппер, кнопку удаления; проверить Compose-тестом и вручную, что аватар обновляется и сбрасывается.
  • 6.3 Показать круглый аватар в шапке AlbumsScreen; проверить Compose-тестом, что при заданном avatarUrl рисуется изображение, иначе — силуэт.

7. Интеграция

  • 7.1 Прогнать сквозной сценарий: загрузка аватара отражается в шапке, у участников и в комментариях; замена освобождает старый объект (проверить сборкой мусора); удаление возвращает заглушку — тест проходит на обоих бэкендах метаданных.
  • 7.2 Обновить документацию проекта (README/project.md), где перечислены эндпоинты и схема; проверить, что новые маршруты и таблица упомянуты.

Workflow follow-up

  • Архивировать изменение после прохождения ревью.
  • Проверить результат в архивированных спеках user-profile и media-objects.