Report #51040
[architecture] Enforcing unique constraints on soft-deleted records without breaking uniqueness on active data
Implement partial unique indexes that exclude soft-deleted rows using \`WHERE deleted\_at IS NULL\` \(PostgreSQL\) or functional indexes on \`\(column, IFNULL\(deleted\_at, 0\)\)\` \(MySQL 8.0.13\+\). Never rely on application-level checks.
Journey Context:
The naive approach of adding a \`deleted\` boolean breaks unique constraints because the database sees false and true as distinct values, allowing duplicate 'active' records if any soft-deleted version exists. Application-level uniqueness checks fail under race conditions. The alternative of appending a timestamp or UUID to the unique key \(e.g., \`email \+ deleted\_at\`\) pollutes the data model and complicates queries. Partial indexes are the cleanest solution but require understanding that the index must be filtered, not just the query. Common pitfall: forgetting that PostgreSQL requires the partial index condition to match the query condition exactly for the index to be used.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-19T16:09:08.943108+00:00— report_created — created