feat(reactions): frequency-ranked one-tap quick-react bar (LC-477) #482

Merged
longjacksonle merged 3 commits from feat/LC-477-frequent-reactions into main 2026-06-28 16:53:14 +02:00

LC-477 - One-tap re-react + frequently-used emoji in reaction bar

Surfaces the caller's most-used emoji in the one-tap quick-react bar so reacting reflects real habits, cross-device and frequency-ranked, not just this device's recency.

Context

LC-302 already gives a hover quick-react bar, but it seeds only from device-local MRU (localStorage) with a hardcoded default fallback. This change adds a server-side frequency source so the bar is accurate on a fresh device and ranks by how often a glyph is actually used.

Changes

  • db::chat::top_reaction_emojis(user_id, limit) - a single grouped query over message_reactions, most-frequent first (ties break toward most-recent), Unicode-only. Custom :shortcode: reactions are excluded, matching the existing LC-288/LC-302 quick-react/recents posture (enclave-scoped, not reusable across rooms).
  • GET /api/reactions/frequent - auth'd, returns the caller's most-used glyphs as a JSON array. No room scope (it is the caller's own aggregate across every room they have reacted in).
  • Quick-react bar JS (layout.html): merges server frequents then device MRU then defaults (deduped, custom shortcodes skipped, capped at the existing QCAP=5). The bar fetches frequents once on load and rebuilds idempotently keyed on a signature, so frequents apply after the async fetch (and after a react updates the MRU) without duplicating buttons or freezing the first computed set.

Tests

db_reactions::test_top_reaction_emojis_ranks_by_frequency_unicode_only asserts frequency ordering, custom :shortcode: exclusion, per-user isolation, and limit capping. just check, just test, and just test-saas all pass.

Not operator-visible: no new env var, config, or integration contract change.

🤖 Generated with Claude Code

## LC-477 - One-tap re-react + frequently-used emoji in reaction bar Surfaces the caller's most-used emoji in the one-tap quick-react bar so reacting reflects real habits, cross-device and frequency-ranked, not just this device's recency. ### Context LC-302 already gives a hover quick-react bar, but it seeds only from device-local MRU (localStorage) with a hardcoded default fallback. This change adds a server-side frequency source so the bar is accurate on a fresh device and ranks by how often a glyph is actually used. ### Changes - `db::chat::top_reaction_emojis(user_id, limit)` - a single grouped query over `message_reactions`, most-frequent first (ties break toward most-recent), Unicode-only. Custom `:shortcode:` reactions are excluded, matching the existing LC-288/LC-302 quick-react/recents posture (enclave-scoped, not reusable across rooms). - `GET /api/reactions/frequent` - auth'd, returns the caller's most-used glyphs as a JSON array. No room scope (it is the caller's own aggregate across every room they have reacted in). - Quick-react bar JS (`layout.html`): merges server frequents then device MRU then defaults (deduped, custom shortcodes skipped, capped at the existing QCAP=5). The bar fetches frequents once on load and rebuilds idempotently keyed on a signature, so frequents apply after the async fetch (and after a react updates the MRU) without duplicating buttons or freezing the first computed set. ### Tests `db_reactions::test_top_reaction_emojis_ranks_by_frequency_unicode_only` asserts frequency ordering, custom `:shortcode:` exclusion, per-user isolation, and `limit` capping. `just check`, `just test`, and `just test-saas` all pass. Not operator-visible: no new env var, config, or integration contract change. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Add db::chat::top_reaction_emojis (frequency-ranked over message_reactions, Unicode-only, custom :shortcode: excluded) and GET /api/reactions/frequent returning the caller's most-used glyphs as JSON. Seeds the one-tap quick-react bar from real cross-device habits instead of only device-local MRU.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Quick-react hover bar now merges server frequents -> device MRU -> defaults (deduped, custom shortcodes skipped) and rebuilds idempotently on a signature so frequents apply after their async fetch without a reload.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
test(reactions): top_reaction_emojis frequency ranking (LC-477)
All checks were successful
check-secrets / Nosey parker (push) Successful in 3s
check-secrets / TruffleHog (pull_request) Successful in 9s
check-secrets / Kingfisher (pull_request) Successful in 9s
Check / clippy + fmt + tests (pull_request) Successful in 5m38s
Create release / Create release from merged PR (pull_request) Has been skipped
check-secrets / Nosey parker (pull_request) Successful in 5s
check-secrets / Kingfisher (push) Successful in 5s
check-secrets / TruffleHog (push) Successful in 5s
f3f5b7d674
Asserts frequency order, custom :shortcode: exclusion, per-user isolation, and limit capping.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
longjacksonle scheduled this pull request to auto merge when all checks succeed 2026-06-28 16:48:29 +02:00
longjacksonle deleted branch feat/LC-477-frequent-reactions 2026-06-28 16:53:14 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/lets-chat!482
No description provided.