chore(openspec): archive add-user-avatar and sync main specs

This commit is contained in:
iu
2026-10-12 16:17:40 +03:00
parent 04617d1cdb
commit 43f5520236
8 changed files with 109 additions and 2 deletions
@@ -0,0 +1,58 @@
# Proposal
## Why
Аватар профиля задуман, но не реализован: колонка `users.avatar_url`, поля
`PublicUser.AvatarURL`/`SelfUser.AvatarURL` и `avatarUrl` в клиентах существуют, однако
никто их не пишет, изображение никто не отдаёт, а интерфейс везде показывает только имена.
Пользователи не могут выделить себя визуально. Нужно замкнуть эту заготовку в рабочую
круглую фотографию профиля с загрузкой и кадрированием на обеих платформах.
## What Changes
- Загрузка и удаление аватара: `POST /api/auth/me/avatar` (клиент присылает уже готовый
квадрат после кадрирования) и `DELETE /api/auth/me/avatar` (сброс к дефолту).
- Серверная нормализация загруженного изображения: отклонение не-изображений, снятие
EXIF/GPS повторным энкодом, две квадратные WebP-нарезки — `avatar_small` (128) и
`avatar` (512).
- Аватар хранится как объект журнала, привязанный к пользователю; сборка мусора учитывает
эту привязку, поэтому замена и сброс аватара сами освобождают старый блоб.
- Стабильная отдача под авторизацией: `GET /api/avatars/:userID/:version` (версия в пути,
чтобы клиентские и браузерные кэши инвалидировались при замене), `?size=large` отдаёт
крупную нарезку.
- `users.avatar_url` заполняется стабильной ссылкой, поэтому существующие публичные
представления пользователя (участники альбома, комментарии, авторы) начинают отдавать
аватар без изменения своих запросов.
- Веб-интерфейс: круглый аватар и загрузка с кадрированием на странице профиля; круглый
аватар в шапке, у участников, в комментариях и у автора фото.
- Android-клиент: круглый аватар и загрузка с кадрированием на экране профиля; круглый
аватар в шапке списка альбомов.
- Дефолт при отсутствии аватара — нейтральная иконка-силуэт; в веб-спрайт добавляется иконка
`person`.
## Capabilities
### New Capabilities
<!-- None: аватар относится к существующей способности профиля пользователя. -->
### Modified Capabilities
- `user-profile`: добавляются требования к аватару — загрузка с кадрированием на клиенте,
круглое отображение в вебе (шапка, страница профиля, участники, комментарии, автор) и в
Android (экран профиля, шапка списка альбомов), дефолтная заглушка и удаление аватара.
- `media-objects`: пользовательский аватар становится объектом журнала, привязанным к
пользователю, и учитывается сборкой мусора наряду с привязками к фото.
## Impact
- Backend: `internal/auth` (хендлеры/сервис/сторы), новая привязка объектов аватара и её учёт
в сборке мусора (`internal/photos/objects.go`, `sqlite_objects.go` или выделенный слой),
маршрутизация и отдача (`internal/app`), миграции Postgres и SQLite, журнал объектов.
- Frontend: `lib/api.ts`, `lib/stores/auth.svelte.ts`, `lib/icons/registry.ts`, страница
`routes/(app)/profile`, `AppShell.svelte`, `Comments.svelte`, `PhotoPanel.svelte`, экран
участников.
- Android: `ProfileScreen`/`ProfileViewModel`/`ProfileApi`/`GaloApi`, `AlbumsScreen`,
экран(ы) кадрирования; `UserDto.avatarUrl` уже есть.
- API: новые маршруты `/auth/me/avatar` и `/avatars/:userID/:version`.
- Спеки: `user-profile`, `media-objects`.