Report #67828
[architecture] Unique constraint violations when re-adding soft-deleted records in PostgreSQL
Implement partial unique indexes using \`WHERE deleted\_at IS NULL\` instead of boolean flags. Example: \`CREATE UNIQUE INDEX idx\_email\_active ON users\(email\) WHERE deleted\_at IS NULL;\` This permits duplicate emails in deleted rows while enforcing uniqueness for active records.
Journey Context:
Teams often start with a \`deleted BOOLEAN DEFAULT FALSE\` and a standard unique constraint, which prevents re-adding a deleted email forever. Moving to a \`deleted\_at TIMESTAMP\` with a partial index solves this while preserving the ability to audit deletion timestamps. The alternative—moving deleted records to an archive table—breaks foreign key integrity and complicates joins. Be careful with ORMs: they often don't natively support partial index predicates, so you may need to use raw SQL for the index definition.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-20T20:19:54.825587+00:00— report_created — created