chore(openspec): archive add-user-avatar and sync main specs
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
# Tasks
|
||||
|
||||
## 1. Модель данных и сборка мусора
|
||||
|
||||
- [x] 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` применяет и откатывает.
|
||||
- [x] 1.2 Расширить `ClaimGarbage` в Postgres-сторе (`internal/photos/objects.go`): не считать мусором объекты, на которые ссылается `user_avatar_objects`; проверить тестом, что привязанный объект аватара переживает сборку, а после снятия привязки освобождается.
|
||||
- [x] 1.3 Расширить `ClaimGarbage` в SQLite-сторе (`internal/photos/sqlite_objects.go`) тем же исключением; проверить аналогичным тестом на SQLite.
|
||||
- [x] 1.4 Добавить методы стора для аватара (привязать/заменить/снять по ролям `avatar`/`avatar_small`, получить текущие объекты) на обоих бэкендах; проверить контрактным тестом, покрывающим оба бэкенда.
|
||||
|
||||
## 2. Backend: нормализация и жизненный цикл объекта аватара
|
||||
|
||||
- [x] 2.1 Реализовать нормализацию аватара: декодировать, отклонить не-изображение, `imaging.Fill` в 512 и 128, перекодировать в WebP (снятие EXIF/GPS); проверить юнит-тестом на JPEG с EXIF/GPS — результат квадратный 512 и 128 без EXIF.
|
||||
- [x] 2.2 Реализовать сервис установки/замены/удаления аватара через журнал объектов (pending → Put → ready → привязка, откат при ошибке); проверить тестом, что сбой не оставляет объектов, а успех привязывает обе роли.
|
||||
- [x] 2.3 Применить предел размера файла (10 MB) и отклонение не-изображений на границе сервиса; проверить тестами на превышение размера и на не-изображение.
|
||||
|
||||
## 3. Backend: API и отдача
|
||||
|
||||
- [x] 3.1 Добавить хендлеры `POST /api/auth/me/avatar` (multipart `file`) и `DELETE /api/auth/me/avatar`, возвращающие обновлённый self-профиль; проверить тестами: без аутентификации — отказ, после загрузки `avatar_url` задан, после удаления — пуст.
|
||||
- [x] 3.2 Добавить отдачу `GET /api/avatars/:userID/:version` (малая нарезка, `?size=large` — крупная) под авторизацией; проверить тестами: без аутентификации — отказ, версия меняется при замене, отсутствующий пользователь/аватар — корректная ошибка.
|
||||
- [x] 3.3 Зарегистрировать маршруты в `internal/app/app.go`; проверить тестом маршрутизации, что новые пути доступны и защищены middleware.
|
||||
|
||||
## 4. Аватар в представлениях пользователей
|
||||
|
||||
- [x] 4.1 Убедиться, что `auth/me`, участники, комментарии и автор фото отдают заполненный `avatar_url` (запросы уже выбирают колонку) и что `PublicUser`/`SelfUser` сериализуют поле; проверить тестами: у пользователя с аватаром `avatar_url` присутствует, без аватара — пуст.
|
||||
|
||||
## 5. Веб-интерфейс
|
||||
|
||||
- [x] 5.1 Добавить в `lib/api.ts` методы загрузки и удаления аватара и сохранять `avatar_url` в auth-стор; проверить `npm run check` (типы) без ошибок.
|
||||
- [x] 5.2 Добавить иконку `person` в `lib/icons/registry.ts` и компонент круглого аватара с заглушкой-силуэтом; проверить, что компонент показывает изображение при заданном URL и силуэт при пустом.
|
||||
- [x] 5.3 На странице `routes/(app)/profile` добавить выбор файла, канвас-кроппер и кнопки загрузки/удаления; проверить вручную: загрузка меняет аватар, удаление возвращает заглушку.
|
||||
- [x] 5.4 Показывать круглый аватар в `AppShell` (шапка), у участников, в `Comments.svelte` и у автора в `PhotoPanel.svelte`; проверить визуально, что заглушка и реальный аватар отображаются круглыми.
|
||||
|
||||
## 6. Android-клиент
|
||||
|
||||
- [x] 6.1 Добавить в `ProfileApi`/`GaloApi` загрузку (multipart) и удаление аватара, а `ProfileViewModel` — `avatarUrl` и действия; проверить юнит-тестами ViewModel (успех, ошибка, обновление состояния).
|
||||
- [x] 6.2 На `ProfileScreen` показать круглый аватар, выбор изображения и Compose-кроппер, кнопку удаления; проверить Compose-тестом и вручную, что аватар обновляется и сбрасывается.
|
||||
- [x] 6.3 Показать круглый аватар в шапке `AlbumsScreen`; проверить Compose-тестом, что при заданном `avatarUrl` рисуется изображение, иначе — силуэт.
|
||||
|
||||
## 7. Интеграция
|
||||
|
||||
- [x] 7.1 Прогнать сквозной сценарий: загрузка аватара отражается в шапке, у участников и в комментариях; замена освобождает старый объект (проверить сборкой мусора); удаление возвращает заглушку — тест проходит на обоих бэкендах метаданных.
|
||||
- [x] 7.2 Обновить документацию проекта (README/project.md), где перечислены эндпоинты и схема; проверить, что новые маршруты и таблица упомянуты.
|
||||
|
||||
## Workflow follow-up
|
||||
|
||||
- Архивировать изменение после прохождения ревью.
|
||||
- Проверить результат в архивированных спеках `user-profile` и `media-objects`.
|
||||
Reference in New Issue
Block a user