Admin ticket view: SMS card with auto phone, template draft and Moira button
Imported from GitHub issue El-SaMa/oma#237 by @El-SaMa.
Why
On 15 Oct 2026 a paying client (#LH-1077) never saw our ticket replies and threatened a consumer complaint. Her own replies were dropped by a bad @gmail.com blocklist entry, which is now fixed. One short SMS saying "we replied, here is the link" would have saved it. Staff need a fast way to send that SMS from the ticket itself.
What to build
A SMS card in the right sidebar of the admin ticket view (/admin/tickets/[id]).
- To: filled from the client's contact phone (
client_billing_profiles.phone, added in f636862f) and editable. If the client has no phone, show an empty field and a hint to add one (staff:oma.admin_manage_clientupdatephone). - Message textarea with a live character and SMS-part counter. Reuse
smsSegments()fromservices/core-api/src/agent-tools/tools-twilio.ts(GSM-7 160/153, Unicode 70/67, max 459 chars / 3 parts). - Default draft is a free template, no AI call. Use the client's language, fi or en:
- fi:
Lanetti: Vastasimme tukipyyntöösi #LH-1077, lue vastaus: https://oma.lanetti.fi/support/<ticketId> - en:
Lanetti: We replied to your ticket #LH-1077, read it here: https://oma.lanetti.fi/support/<ticketId> - The link is always the customer-side URL
/support/<id>, never/admin/....
- fi:
- ✨ Moira button (AI icon, tooltip "Draft with Moira" / "Luonnostele Moiralla" / "Utkast med Moira"). It rewrites the draft as a short SMS summary of the latest staff reply. It must stay within 3 parts and keep the ticket ref and the customer link. Same path as
oma.admin_ticket_draft, plus a short-SMS mode. - Send SMS button with a confirm step showing the exact text. It sends through the same code as
oma.admin_twilioactionsend(support Messaging Service, so replies land in the desk). - After sending, add an internal note on the ticket:
SMS sent to +358… (N parts): <text>, written by the staff member who sent it. Twilio errors go to the error log and show inline.
Rules to follow
- Product DoD (
.cursor/rules/product-dod.mdc): staff MCP covers it.oma.admin_twiliosendexists; add an optionalticketIdso the MCP send also writes the internal note. Addoma.admin_ticket_draftmode: "sms"for the Moira short draft. - en/fi/sv native strings, no em/en dashes. Customer copy names no vendors or hosts.
- UI style: card in the existing right sidebar, shadow card, no new tab row.
- Moira no credit burn: the template is the default. Test Moira with one live call at most.
- No auto-SMS on every reply. This is manual, per ticket.
- Handbook: add a line to
apps/web/content/admin-docs/support/support.md(Twilio section).
Later (not in this issue)
Auto SMS for urgent tickets on staff reply, a one-time reminder SMS when the customer has not opened a staff reply in 24 h, and a customer opt-in toggle "SMS me when support replies".
Done when
- The card shows on a live ticket with the phone filled in. The template draft is correct for a fi and an en client.
- One real SMS is sent from the card, the internal note appears, and the MCP
sendwithticketIdworks live. - Tests for the template builder and the note. Typecheck and i18n checks pass, and the deploy plus public smoke pass.