On this page
What changed, and why it's hard to test end-to-endWhere to focus manual/exploratory testingEdges called out directly in the code (verify these are actually true, not just intended)For Quality
What changed, and why it's hard to test end-to-end
This fix depends entirely on Meta's webhook payload shape — there is no way to trigger a genuine hidden-number contact from inside Dentolize's UI or a normal test account, because the privacy behavior is enforced by WhatsApp itself based on real contact history. Realistic testing means either a live WhatsApp Business test contact configured with username privacy against a number the test WABA hasn't recently exchanged with, or constructing webhook payloads by hand and posting them to the whatsapp-official endpoint that handles onMessage. This sandbox has no seeded WhatsApp conversations at all (whatsapp=false), so the screenshots in this walkthrough show real, current, empty screens rather than a demonstrated hidden-number conversation — see Walkthrough.
Where to focus manual/exploratory testing
- First message from a BSUID-only contact. Confirm a new
OnlineConversationrow is created withbsuidset andphonenull, no server error, and the conversation appears in/whatsapp/chats. - First message from a BSUID-only contact where the same phone number already has a conversation from before this migration. This is the conflict/
backfill: falsepath (online-conversation.service.ts:19-38) — confirm the existing phone-keyed row is used and unmodified, and that the message doesn't crash or create a duplicate second row that then also fails. - A contact who later reveals their number (or messages the same clinic again after being seen by phone before). Confirm the same conversation is updated (not duplicated) — check
messagesCount/lastMessagecontinuity and that a previously blankphonegets backfilled. - Replying to a BSUID-only conversation from clinic-web/clinic-mobile as a staff member, and via the auto-responder (
officialWhatsAppConfig.waConfig.autoAnswer). Confirm the outbound Graph API call usesrecipient, notto(this can only really be verified by confirming actual delivery, or by inspectingwhatsapp-officiallogs/outbound request if there's a way to capture it in the test environment). - Patient/lead auto-matching for a BSUID-only first contact. Expected: no patient match attempted, no lead created — confirm this is what actually happens rather than an error or a mismatched lead.
- A hidden-number contact requesting an online payment link (
ACTION.PAYMENT_OPTION). Expected:handleOnlinePayment.ts:67-70throwsCannot create a payment link without a phone number— confirm this is caught gracefully upstream (the outertry/catchinMessagesService.onMessage) rather than surfacing to the contact or crashing the webhook handler. - Editing a patient linked to a phone-less
OnlineConversation. Change the patient's phone number and confirm the conversation link is not disconnected (editPatient.js:211-218— there's nothing to compare against, so it should be a no-op on the link). - Regression on the ordinary (phone-visible) path. Every touched file has a phone-first branch — worth a quick pass confirming normal contacts still show phone numbers, still link to patients/leads, and still receive replies via
to, unchanged from before this PR.
Edges called out directly in the code (verify these are actually true, not just intended)
findConversationByAddressprefers the phone-matched row over the BSUID-matched row when both exist and disagree (online-conversation.service.ts:34) — worth confirming which row "wins" in an actual conflicting-data scenario, since this determines which conversation history staff continue to see.usernameis written unconditionally on every message (not gated by thebackfillflag that guardsphone/bsuid) — confirm a contact's displayed@usernameupdates if they change their WhatsApp username, including for a conversation that also has a phone number on file.- The GraphQL server's
isBsuid(official-whats-app.utils.js:9, a regex) andwhatsapp-official'sisBsuid(messages.service.ts:95, "did Meta omitwa_id") are independently implemented — there's no shared test coverage forcing them to agree. If Meta ever changes the BSUID format, only one of the two would need updating, and nothing would flag the other falling out of sync. handleSendWhatsappMessage's GraphQLphoneargument is now optional and effectively unused by the resolver (schema.graphql:1242,handleSendWhatsappMessage.js:37-40) — confirm no caller still depends on it being required or being echoed back anywhere.