Report #10016
[architecture] Soft-delete breaks unique constraints \(e.g., email uniqueness\)
Use partial unique indexes that exclude soft-deleted rows. In PostgreSQL: CREATE UNIQUE INDEX idx\_active\_email ON users\(email\) WHERE deleted\_at IS NULL. Do NOT include deleted\_at in the constraint values.
Journey Context:
The naive approach adds a deleted\_at timestamp but keeps the unique constraint on email alone; this prevents re-creating a deleted account or permanently reserves the email. Adding deleted\_at to the unique constraint \(email, deleted\_at\) fails because multiple NULLs are allowed in SQL, but more importantly it allows duplicate active emails if they are deleted at different times. The correct pattern uses a partial index that only enforces uniqueness among non-deleted rows. This requires PostgreSQL/MySQL 8.0.13\+ partial indexes. The tradeoff is that you cannot easily query 'find me any user including deleted with this email' using that index, but you should maintain a separate non-unique index for that rare query.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-16T09:41:08.722083+00:00— report_created — created