Skip to content

Fix: partial unique indexes so soft-deleted records can be recreated - #491

Open
bamdadd wants to merge 4 commits into
shridarpatil:mainfrom
bamdadd:fix/soft-delete-partial-unique-indexes
Open

Fix: partial unique indexes so soft-deleted records can be recreated#491
bamdadd wants to merge 4 commits into
shridarpatil:mainfrom
bamdadd:fix/soft-delete-partial-unique-indexes

Conversation

@bamdadd

@bamdadd bamdadd commented Jul 2, 2026

Copy link
Copy Markdown

Problem

Deleting a record and re-creating one with the same unique key fails with a duplicate-key error. Example: delete a WhatsApp account in the UI, try to add the same phone number again →

ERROR: duplicate key value violates unique constraint "idx_whatsapp_accounts_org_phone" (SQLSTATE 23505)

Cause

These models use GORM soft deletes (BaseModel.DeletedAt), but several unique indexes in getIndexes() were created without a WHERE deleted_at IS NULL predicate. A soft delete only sets deleted_at, so the deleted row still participates in the unique index and blocks recreation.

Affected (all soft-deleted tables):

  • idx_contacts_org_phone (contacts)
  • idx_whatsapp_accounts_org_phone + idx_wa_org_name (whatsapp_accounts)
  • idx_templates_account_name_lang (templates)
  • idx_sso_providers_org_provider (sso_providers)

The pattern is already applied correctly for team_members, user_organizations and ivr_flows — this just makes it consistent.

Fix

Recreate each as a partial unique index (WHERE deleted_at IS NULL). The old index is DROPped first so existing installs migrate, and the new index uses a distinct _active name with IF NOT EXISTS so it isn't rebuilt on every boot. idx_wa_org_name was created via a GORM struct tag, so the tag is removed and replaced with an equivalent partial raw index.

No data changes; indexes only.

bamdadd and others added 4 commits July 2, 2026 09:41
Several unique indexes were created without a deleted_at predicate on tables
that use GORM soft deletes (contacts, whatsapp_accounts, templates,
sso_providers). Because a soft delete only sets deleted_at, the deleted row
still participates in the unique index, so recreating a record with the same
key fails with a duplicate-key violation (idx_whatsapp_accounts_org_phone,
etc.) — e.g. deleting a WhatsApp account and re-adding the same number.

Recreate these as partial unique indexes (WHERE deleted_at IS NULL), matching
the pattern already used for team_members, user_organizations and ivr_flows.
Old indexes are dropped first so existing installs migrate. The GORM-tag index
idx_wa_org_name is replaced by a partial raw index for the same reason.
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.

2 participants