Dentolize · Send Template in Expired Conversation Walkthrough
On this pageDomain termsDuplicated Code

Glossary

Domain terms

24-hour window — WhatsApp Business Platform rule: a business can only send free-form messages to a contact within 24 hours of that contact's last message. Outside that window, only approved templates go through. Enforced elsewhere in Dentolize (the normal send path) via lastMessage vs. dayjs().subtract(24, 'hour') (packages/server/src/resolvers/mutations/actions/officialWhatsApp/handleSendWhatsappMessage.js:43-44); this PR's new mutation deliberately does not apply that check, since sending into an expired window is its purpose.

Approved template — a WhatsApp message template that Meta has reviewed and approved for a business to use. Tracked in Dentolize as ConversationTemplate.status === 'APPROVED'. Approval happens outside this feature; this feature only uses templates that are already approved.

Expired conversation — an OnlineConversation whose last message is more than 24 hours old. Computed on the fly wherever needed (there's no stored "expired" flag), both server-side (to block/allow the normal send mutation) and client-side (to show the countdown and the "Conversation Expired" banner).

Message — Dentolize's general-purpose automated/canned message model (packages/prisma/schema.prisma, model Message), used across SMS, WhatsApp, and email reminders. Can optionally have a one-to-one ConversationTemplate attached, which is what makes it usable as a WhatsApp template.

ConversationTemplate — the WhatsApp-specific template metadata attached to a Message: its Meta template name, language, status (APPROVED | PENDING | REJECTED), and whatsAppID.

Communication — the shared outbound-message log/audit table used by every messaging channel (SMS, WhatsApp, email) and every sender (automated crons and, as of this PR, manual template sends). Records what was sent, to whom, and whether it succeeded — the place to look to answer "did this message actually go out."

Embedded variable / @VARIABLE — a placeholder like @PATIENT_NAME or @DATE inside a Message's text, filled in with real data before sending. The full list of 25 recognized variables lives in packages/server/src/cronJobs/messages/embeddedValues.js. This feature can only fill two of them — @PATIENT_NAME and @FIRST_NAME — because it runs outside the automated-reminder context that supplies the rest.

generatedID — a client-generated UUID passed through to the server and used as the new ConversationMessage's id, so the sending client can optimistically render the message immediately without waiting for a refetch.

SEND_WA — the permission that gates both normal WhatsApp sending and this feature's sendWhatsappTemplate mutation (packages/server/src/permissions/permissions.js:4051).

Duplicated Code

The eligibility logic (NAME_VARIABLES, unfillableVariables, fillNameVariables/conversationTemplateName) is implemented three times: once per app's templateHelpers.js (mobile and web — byte-identical files) and again, independently, inline in the server resolver. This is consistent with how this codebase already duplicates rather than shares code between clinic-mobile and clinic-web (the web app already imports several GraphQL documents directly from @dentolize/clinic-mobile, but not this new helper file) — worth knowing if a future change to the variable list needs to touch three files in lockstep rather than one.