chore(openspec): archive add-user-avatar and sync main specs
This commit is contained in:
@@ -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`.
|
||||
Reference in New Issue
Block a user