Commit Graph

1 Commits

Author SHA1 Message Date
Arnas Donauskas
3dce1b56cd
feat(contacts): prevent duplicate phone numbers on create/import (#212)
The same phone could become multiple contacts: only the WhatsApp
webhook de-duped, while manual create and CSV import inserted raw
un-normalized phones, and the DB had no uniqueness. That fragmented
conversations, deals, and tags across duplicates.

- Migration 022: generated `contacts.phone_normalized` (digits-only),
  a one-shot `merge_duplicate_contacts()` that collapses existing
  dupes into the oldest row (re-pointing conversations, deals, notes,
  tags, custom values, broadcast recipients — no data loss), then a
  UNIQUE (account_id, phone_normalized) index as the authoritative
  guarantee for every write path.
- Shared `src/lib/contacts/dedupe.ts`: findExistingContact (suffix
  prefilter + phonesMatch), isExactMatch, isUniqueViolation,
  dedupeByPhone. The webhook now reuses findExistingContact (and
  recovers from a unique-violation race instead of dropping the
  message).
- Contact form: on-blur duplicate check — hard-block + "view existing"
  link on an exact match, soft warning on a trunk-variant near-match;
  unique-violation backstop on submit.
- CSV import: de-dupes within the file and against existing contacts,
  reports "imported / skipped / failed", treats 23505 as skipped.
- Contact type gains account_id (was missing) + phone_normalized.
- Unit tests for the dedupe helpers.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 15:52:38 +03:00