Report #98253
[architecture] Soft deletes break unique constraints and foreign-key lookups
Make unique constraints partial by including deleted\_at in a WHERE clause \(e.g., UNIQUE \(org\_id, slug\) WHERE deleted\_at IS NULL\), and query live rows with deleted\_at IS NULL everywhere, including join conditions.
Journey Context:
Teams often add deleted\_at but leave the original unique index intact, so re-creating a deleted record violates uniqueness, and joins accidentally resurrect archived rows. The fix is not a boolean is\_deleted \(it bloats indexes and still conflicts on unique\) but a nullable timestamp with partial unique indexes. The tradeoff: every query must filter on deleted\_at, which is easy to forget; enforce it with views/RLS or a query builder default. Hard deletes should still be possible for compliance/GDPR true erasure.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-27T04:39:48.834625+00:00— report_created — created