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
This commit is contained in:
+15
-3
@@ -341,6 +341,7 @@ colors: {
|
||||
taken_at, latitude, longitude, caption, exif, deleted_at, created_at)
|
||||
- **objects** (id, storage_key, mime_type, size, width, height, checksum, state, created_at)
|
||||
- **photo_objects** (photo_id, object_id, role)
|
||||
- **user_avatar_objects** (user_id, object_id, role)
|
||||
- **variant_jobs** (photo_id, attempts, next_attempt_at, last_error)
|
||||
- **comments** (id, photo_id, user_id, text, created_at, updated_at)
|
||||
- **likes** (photo_id, user_id, created_at)
|
||||
@@ -372,15 +373,17 @@ colors: {
|
||||
**Postgres — журнал истины.** Таблица `objects` описывает каждый блоб (ключ, mime,
|
||||
размер, габариты, checksum, состояние `pending|ready|deleting`), таблица
|
||||
`photo_objects` связывает фото с объектами по ролям (`original|thumb|preview`),
|
||||
таблица `variant_jobs` — очередь генерации вариантов. Альбом, принадлежность и
|
||||
представление живут только в `photos`/`albums`.
|
||||
таблица `user_avatar_objects` — аватар пользователя с его нарезками
|
||||
(`avatar|avatar_small`), таблица `variant_jobs` — очередь генерации вариантов.
|
||||
Альбом, принадлежность и представление живут только в `photos`/`albums`.
|
||||
|
||||
Следствия:
|
||||
- **Копирование** между альбомами — только новые строки `photos`+`photo_objects`,
|
||||
ссылающиеся на те же объекты; операции с хранилищем не выполняются.
|
||||
- **Перенос** — только `UPDATE photos.album_id`; объекты не трогаются.
|
||||
- **Удаление** фото удаляет строки; фоновый воркер удаляет блоб лишь когда на
|
||||
объект не осталось ни одной ссылки (сборка мусора по ledger-состояниям).
|
||||
объект не осталось ни одной ссылки (фото или аватар) — сборка мусора по
|
||||
ledger-состояниям.
|
||||
|
||||
Доступ: **только через бэкенд** — подписанный URL со сроком 1 час на
|
||||
`/api/objects/<key>`, независимо от бэкенда хранилища. Для S3 (Garage) байты
|
||||
@@ -402,6 +405,15 @@ colors: {
|
||||
- `POST /api/auth/refresh`
|
||||
- `POST /api/auth/logout`
|
||||
|
||||
### Profile
|
||||
- `GET|PATCH|DELETE /api/auth/me`
|
||||
- `POST /api/auth/me/password`
|
||||
- `POST /api/auth/me/identifiers`
|
||||
- `PATCH /api/auth/me/preferences`
|
||||
- `POST /api/auth/me/avatar` — загрузка готового квадрата (multipart `file`)
|
||||
- `DELETE /api/auth/me/avatar` — сброс к заглушке
|
||||
- `GET /api/avatars/:userID/:version?size=large` — публичная отдача аватара (без авторизации)
|
||||
|
||||
### Albums
|
||||
- `GET /api/albums`
|
||||
- `POST /api/albums`
|
||||
|
||||
Reference in New Issue
Block a user