FIELD NOTE·20 JAN 2026·4 MIN READ

Softdeletebydefault,orhowtostopfearingthedeletebutton

Hard deletes are a foot-gun. Soft deletes plus a `.active()` query helper give you reversibility without polluting every query.

#backend#mongodb#mongoose#patterns

Why every model in the ClearedMind backend carries `archived_at` and `deleted_at` — and why `findOneAndDelete` is banned.

The rule

Nothing in the ClearedMind backend is ever hard-deleted. Every Mongoose model carries two timestamps:

{
  archived_at: { type: Date, default: null },
  deleted_at:  { type: Date, default: null },
}

A "delete" is just:

user.deleted_at = new Date();
await user.save();

The query helper

schema.query.active = function () {
  return this.where({ deleted_at: null, archived_at: null });
};

const users = await User.find().active();

Why it matters

  • Reversibility. Wellness data is sensitive.
  • Audit trails stay intact. Foreign references to a "deleted" user still resolve.
  • GDPR-style erasure is still possible via a separate, audited workflow that scrubs PII.

The anti-pattern

Calling Model.findOneAndDelete() in this codebase is a code-review failure.