Report #4124
[architecture] Unique constraint violations when soft-deleting records with unique fields \(e.g., user email\)
Use partial unique indexes \(PostgreSQL: CREATE UNIQUE INDEX ... WHERE deleted\_at IS NULL\) instead of including deleted\_at in the index key. This enforces uniqueness only on active rows while allowing multiple soft-deleted entries.
Journey Context:
Developers often add deleted\_at to a composite unique key \(email, deleted\_at\), which fails because SQL treats NULL \!= NULL, allowing duplicate NULLs, or requires sentinel values that complicate queries. Partial indexes are optimal because the query planner can use them for non-deleted row lookups, and they strictly enforce uniqueness only on the active set. This avoids the 'resurrection' collision where restoring a soft-deleted user conflicts with an active user using that email.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-15T18:51:27.484288+00:00— report_created — created