Report #102466
[architecture] Unique constraint violations after soft-deleting records
Use a nullable deleted\_at timestamp and make unique indexes partial: WHERE deleted\_at IS NULL. This lets you delete and later recreate the same natural key while keeping history and avoiding boolean-based uniqueness collisions.
Journey Context:
A boolean is\_deleted plus a unique index on \(org\_id, email\) fails when a user is deleted and a new user with the same email is created, because the deleted row still occupies the unique slot. A partial unique index ignores deleted rows, so the natural key becomes reusable, and deleted\_at supports retention/undelete semantics. The risks are that every SELECT must still filter deleted\_at IS NULL or you leak soft-deleted data, and soft deletion weakens foreign-key cascade behavior and complicates GDPR hard deletes. Some teams prefer archiving deleted rows to a separate table instead. Partial unique indexes require a database that supports them, such as PostgreSQL or SQLite.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-07-09T04:55:11.449815+00:00— report_created — created