Skip to main content

Sync chat_data back to CDP for CDP-originated contacts (Qontak One)

Jira Story: TF-3552 · Task: TF-3526 (linked via "Work item split", corrected direction verified) · Epic: TF-3500 (bucket item A7, CDP 26Q3 Engineering Initiatives — re-homed from TF-3477 on 2026-07-21) · Sibling: TF-3517 (crm_data_id, same root cause → prd)

Product Bugs found by QA automation: TF-3562 (phone after consent) · TF-3566 (username on BSUID lookup) · TF-3567 (changed username propagation). All three are parented to TF-3500 and split from owning Story TF-3552; verified 2026-07-26. The discovery work is QA BAU, but these are product defects in A7's chat-sync behavior.

Overview

When a contact is created from CDP, CDP pushes to the chat domain to create its chat customer, but the chat side never publishes anything back — so CDP's contact.chat_data[] stays null/empty for CDP-originated contacts. Real client impact: contacts with empty chat_data are excluded from chat-dependent surfaces, most visibly the direct-select recipient list / segment recipients (filter requires chat_data.id to exist, contact-service/internal/app/payload/segmented_filter_request.go:183) — the client cannot select manually/bulk-created customers as campaign recipients.

Root cause is confirmed in code end-to-end: hub_core's Kafka consumer path unconditionally sets skip_deliver_contact_360_webhook = true (centralized_contacts/repositories/contacts/find_or_initialize.rb:27), so the existing outbound ack webhook never fires.

Fix (per TF-3526, revised): no new Kafka topic. Conditionally re-enable the existing /contacts/create sync webhook in hub_core, gated by a new org flag (sync_contact_360_inbound_ack_to_cdp) AND unified_app == true; add qontak_customer_id to the ack payload; on the CDP side, give qontak_customer_id top lookup priority in MergeDataService.DefineTarget so the ack updates the originating contact instead of inserting a duplicate (correctness-critical — must land before the webhook is re-enabled). Redis loop-guard collapses duplicate redeliveries.

Scope Changes

  • Backendhub_core conditional webhook re-enable + payload fix; contact-service ContactSyncRequest/DefineTarget lookup fix; hub-worker gem bump/redeploy only. Qontak One tenants only; chat-originated contacts unchanged.

8. User Stories + Acceptance Criteria

User StoryImportanceMockup / Technical NotesAcceptance Criteria
[CHATSYNC-S01] — CDP-created contacts become selectable chat recipients

As a Qontak One user, I want a customer I create manually or via bulk add in CDP to receive its chat_data link back from the chat domain, so that the customer appears in the direct-select recipient list and can receive campaigns.
Must HaveReuse existing webhook chain (deliver_contact_360_webhook → … → POST {CONTACT_SERVICE_URL}/contacts/create); flag + unified_app gate; qontak_customer_id added to Apis#contact_params (apis.rb:384-415); CDP DefineTarget (merge_data.go:542-629) matches qontak_customer_id before chat_data.id/bsuid.— Happy Path —
• AC-1: Given a Qontak One tenant with the flag enabled, when a contact is created from CDP, then the chat domain acks via the existing webhook and CDP merges chat_data onto the originating contact, which then appears in the direct-select recipient list / segment recipients.
• AC-2: Given the first-ever ack for a CDP-originated contact, when CDP processes it, then it updates the existing record via qontak_customer_id lookup — it does not insert a duplicate contact.
— Guard-rail —
• NEG-1: Given a non-Qontak-One tenant or the flag disabled, when a contact is created from CDP, then no ack is sent and behaviour is unchanged.
• NEG-2: Given replay/duplicate redelivery of the same ack, when it arrives, then the Redis loop-guard + UniqueChatObject dedupe (by stable chat_data.id) prevent duplicate chat_data entries.

Verification

In progress — TF-3526 is In Progress, assignee Ghozi Humama, as of 2026-07-21. Cross-team: chat squad owns the webhook re-enable + payload fix; CDP owns the DefineTarget/DTO fix. Open: confirm hub-worker Sidekiq queue config covers CreateWebhookWorker/CreateSingleWebhookWorker.