feat(avatars): image upload for users and bots#98
Merged
Conversation
Add avatar image upload backed by object storage:
- POST /api/v1/users/me/avatar (self) and POST /api/v1/bots/:bot_id/avatar
(owner/admin) accept raw image bytes, store to avatars/{kind}/{id}/{uuid}.{ext},
and write the serving URL into the existing avatar_url column.
- Public GET /api/v1/{users,bots}/:id/avatar/:file serves the bytes with an
inline content-disposition and 1-day cache (an <img src> can't send a Bearer
token, and the path is validated to stay inside the avatars/ prefix).
- Only raster images (png/jpeg/webp/gif) up to 5 MiB; SVG is rejected because
file_response forces it to download.
Frontend: AvatarUpload component (hover camera + file picker + optimistic
preview) wired into the profile editor and the bot status editor.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Full avatar image upload for users and bots (optimization #1). Users set their own avatar; a bot's is owner/admin-only. Images are stored in object storage and served over a public URL.
Backend
POST /api/v1/users/me/avatar(self) andPOST /api/v1/bots/:bot_id/avatar(owner/admin) — body is raw image bytes. Stores toavatars/{kind}/{id}/{uuid}.{ext}and writes the serving URL into the existingavatar_urlcolumn.GET /api/v1/{users,bots}/:id/avatar/:file— serves the bytesinlinewith a 1-day cache. Public because an<img src>can't attach a Bearer token and an avatar isn't sensitive; the path is validated (owner = uuid, file ={hex-uuid}.{known-ext}) so a crafted key can't escape theavatars/prefix.file_responseforces SVG to download, so it'd never render).Frontend
AvatarUploadcomponent: hover camera overlay → file picker → optimistic object-URL preview while the upload runs, then persists.Verification
Tested end-to-end against the local kind stack:
200, byte-perfect round-trip (198 → 198)200 image/png,content-disposition: inline,cache-control: max-age=86400GET /users/mereturns the newavatar_url200400400401🤖 Generated with Claude Code