feat(canned): per-user canned responses / saved replies (LC-487) #487
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/LC-487-canned-responses"
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-487 - Canned responses / saved replies
Per-user reusable message snippets, invoked from the composer as personal slash commands and expanded through the existing slash dispatch + autocomplete (as the ticket suggested).
Data
Migration
0076_canned_responses.sqladds a user-scopedcanned_responsestable (UNIQUE(user_id, name)). It is intentionally a separate table rather thanslash_commands_custom: that table'sscope_idis an INTEGER and itsUNIQUE(scope_kind, scope_id, name)would force names to be globally unique across users. Here names are unique per user.Reuse
db::slashgainsinsert_canned/list_canned_for_user/get_canned_for_user/delete_canned, returningStaticTextCustomCommands so the existing machinery treats a saved reply exactly like a personal static-text command:custom_for_userunions global admin commands with the caller's canned responses (a global name wins a collision, so the list shows one row).try_dispatchchecks canned responses after built-ins and global commands (neither can be shadowed).{args}is substituted with whatever the user typed after the name, then posted as a normal message, identical to a global static_text command.Management
A new "Saved replies" tab in Settings creates/lists/deletes canned responses (name + optional description + body). Name validation mirrors the admin custom-command rule (lowercase
[a-z0-9_-], no built-in shadowing); the body is capped at the message length limit since it is posted as a message. Account deletion is unaffected (canned rows are keyed byuser_id; a follow-up could add them to the delete sweep, but they are private and harmless).Tests
db_canned: insert/get/list scoping, per-user (not global) name uniqueness, owner-scoped delete. Existingroutes_slashHTTP tests still pass (global behavior unchanged).just check,just test,just test-saasall green (i18n parity covers the new en/es keys); Tailwind rebuilt.Not operator-visible (additive migration, no env/config/contract change).
🤖 Generated with Claude Code
custom_for_user unions global commands with the caller's canned responses (global wins name collisions) for the autocomplete/help list; try_dispatch checks canned after built-ins and global commands, expanding {args} the same way as a global static_text command. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>