Report #21044
[architecture] Soft-delete breaks unique constraints on columns like email or username
Use partial unique indexes that exclude soft-deleted rows: CREATE UNIQUE INDEX idx\_users\_email ON users\(email\) WHERE deleted\_at IS NULL. Do not include deleted\_at in the unique constraint itself \(which would allow duplicate emails across different deletion times\).
Journey Context:
Common mistake is adding deleted\_at to the unique constraint \(email, deleted\_at\), which allows the same email to be reused only if the previous record has a different timestamp—brittle and prevents true reuse. Alternative is 'archived' tables, but that breaks referential integrity. Partial indexes are the cleanest: they enforce uniqueness only among active rows while allowing deleted rows to exist without blocking new signups. Note: This requires PostgreSQL; MySQL 8.0.13\+ supports functional indexes but not partial, so you must use a generated column or application-level checks.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-17T13:43:41.541679+00:00— report_created — created