Skip to content

fix(contacts): stop incoming messages from reverting manually set contact names - #508

Open
bambinounos wants to merge 1 commit into
shridarpatil:mainfrom
bambinounos:fix/preserve-manually-set-contact-name
Open

fix(contacts): stop incoming messages from reverting manually set contact names#508
bambinounos wants to merge 1 commit into
shridarpatil:mainfrom
bambinounos:fix/preserve-manually-set-contact-name

Conversation

@bambinounos

Copy link
Copy Markdown
Contributor

Problem

Renaming a contact in the UI does not stick. The new name survives until that contact sends their next message, then silently reverts to the name from their WhatsApp profile. Reproduced repeatedly on a live deployment.

Contact.ProfileName serves double duty: it is both the name WhatsApp reports and the name users edit. GetOrCreateContact runs on every inbound message and refreshes it:

// Update profile name if changed
if profileName != "" && contact.ProfileName != profileName {
    db.Model(&contact).Update("profile_name", profileName)
}

The condition contact.ProfileName != profileName is true exactly when someone has renamed the contact, so the rename is what triggers its own reversion. The same path is reached from incoming messages (chatbot_processor.go), reactions, coexistence contact sync (webhook.go) and campaign jobs (worker.go), so a single emoji reaction is enough to undo an edit.

This also quietly affects CSV imports: names imported from a CRM are overwritten as soon as each contact writes in.

Fix

Add Contact.NameManuallySet and use it to distinguish a name WhatsApp supplied from one a user chose:

  • set to true where a name is written deliberately — UpdateContact, CreateContact, and CSV import when the row carries profile_name;
  • GetOrCreateContact skips the refresh when it is true.

Contacts that were never renamed keep syncing their name from WhatsApp exactly as before. Clearing the name field in the UI sets the flag back to false, handing control to WhatsApp again — an intentional escape hatch rather than a one-way door.

The refresh logic was copy-pasted across the normalized and +prefix lookup branches; it is now a single refreshProfileName helper, so the guard cannot drift between the two.

The importer gained a small NormalizeRecord hook, called for both the create and update-on-duplicate paths, since the existing BeforeCreate hook only runs on create.

Tests

internal/contactutil/contactutil_test.go:

  • TestGetOrCreateContact_PreservesManuallySetName — a renamed contact keeps its name when a message arrives under a different WhatsApp profile name.
  • TestGetOrCreateContact_PreservesManuallySetNamePlusPrefix — same guard on the +prefix branch.

The existing TestGetOrCreateContact_UpdatesProfileName is unchanged and still passes, pinning the auto-sync behaviour for contacts nobody has renamed.

The new column is additive with a false default, so existing rows keep the current behaviour until a name is edited. Deployments that already imported names from a CRM can opt those rows in with a one-off UPDATE contacts SET name_manually_set = true WHERE ... if they want the imported names protected retroactively.

Contact.ProfileName is both the name WhatsApp reports and the name users
edit in the UI. GetOrCreateContact runs on every inbound message and
overwrote it whenever it differed from the WhatsApp profile name -- which
is precisely the case after a user renames a contact. The rename survived
until the contact's next message, then silently reverted. Reactions,
coexistence contact sync and campaign jobs hit the same path.

Add Contact.NameManuallySet, set it when a name is written deliberately
(UpdateContact, CreateContact, CSV import) and skip the webhook refresh
when it is true. Contacts that were never renamed keep syncing their name
from WhatsApp as before; clearing the name in the UI hands control back.

Also de-duplicate the refresh logic, which was copy-pasted across the
normalized and +prefix lookup branches.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant