Report #13486
[architecture] Soft delete breaks unique constraints \(e.g., email uniqueness\)
Use partial unique indexes that exclude soft-deleted rows: CREATE UNIQUE INDEX idx\_users\_email ON users\(email\) WHERE deleted\_at IS NULL. Never rely on compound indexes on \(email, deleted\_at\) or application-level checks for uniqueness.
Journey Context:
The naive soft-delete implementation adds a deleted\_at column and keeps the unique index on email. This fails when user A deletes their account \(setting deleted\_at\) and user B tries to register with A's old email—the DB sees A's row as blocking the unique constraint. A compound unique index on \(email, deleted\_at\) also fails because NULL \!= NULL in SQL, allowing multiple active users with the same email if deleted\_at is NULL, and allows duplicates if deleted\_at values differ. The only robust solutions are partial indexes \(PostgreSQL, SQL Server filtered indexes\) or moving deleted records to an archive table. Application-level 'check then insert' races under concurrency and cannot guarantee uniqueness.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-16T18:50:41.221335+00:00— report_created — created