feat(emoji): user-level (personal) custom emoji (LC-482) #486
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/LC-482-user-custom-emoji"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
LC-482 - User-level (personal) custom emoji
Adds personal custom emoji alongside enclave emoji, reusing the existing upload/serve pipeline and
:shortcode:resolver.Model + schema
Migration
0075_user_custom_emojis.sqlrebuildscustom_emojis:enclave_idbecomes nullable, auser_idcolumn is added, and aCHECK ((enclave_id IS NOT NULL) <> (user_id IS NOT NULL))enforces exactly one scope per row. Existing rows copy in as enclave-scoped. Shortcode uniqueness is now per-scope (two partial unique indexes). Keeping one id space means/api/emojis/{id}and the:shortcode:-><img>render path are unchanged.Resolution + precedence
refs_for_room_and_user(room_id, user_id)layers the viewer's personal emoji additively under the room set (own enclave > globally-shared). The room/enclave set wins shortcode collisions, so a shared:code:renders identically for everyone; personal emoji only fill in shortcodes the room does not define. Personal emoji are otherwise per-viewer: they resolve only in the owner's own renders, and the serve route authorizes a personal row to its owner (+ site admin) only. This call replacesrefs_for_roomat the render/pick sites that have a viewer (message list + single-message renders, WS per-recipient renders, reaction bar + picker, emoji autocomplete, DM page, composer preview). Room wiki/description rendering stays enclave-only (shared docs; documented).Management
A new "Custom emoji" tab in user Settings uploads/lists/deletes personal emoji (
POST /settings/emojis,POST /settings/emojis/{id}/delete), mirroring the enclave emoji card. The multipart ingest (stream, size cap, magic-byte sniff, content-address) is extracted into a shared helper used by both the enclave and personal upload handlers. Account deletion already removes a user's emoji via the existinguploaded_bycleanup.Tests
db_custom_emojis: user-scoped insert + per-user uniqueness + enclave/personal shortcode coexistence,refs_for_room_and_userprecedence (enclave wins, other viewers don't see your personal emoji), owner-scoped delete. The existing enclave-emoji + cascade tests were updated for the now-Optionenclave_idand still pass.just check,just test,just test-saasall green (i18n parity covers the new en/es keys); Tailwind rebuilt.Not operator-visible (no env/config/contract change; the migration is additive and self-applying).
🤖 Generated with Claude Code
Migration 0075 rebuilds custom_emojis: enclave_id nullable, add user_id, CHECK exactly one scope, per-scope partial unique indexes (single id space, so /api/emojis/{id} is unchanged). db gains insert_for_user / list_for_user / delete_for_user / refs_for_user and refs_for_room_and_user, which layers a viewer's personal emoji additively under the room set (room/enclave wins collisions). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>Extract the multipart ingest into a shared helper; reuse it for the enclave upload and a new POST /settings/emojis (personal) + /settings/emojis/{id}/delete (owner-scoped). get_emoji authorizes by scope: enclave rows keep the share/membership rule, personal rows are private to their owner (+ site admin). Fix the data-export query for nullable enclave_id. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>