Can CeylanVienna-based, globally curious.
Learn/Architecture

Soft deletes aren't just for audit trails — they're your sales pipeline

When you hard-delete a record, you lose the sales lead. Inactive records in a marketplace platform are your best prospects — enforce soft delete at the database role level, not in application code.

2026-04-18·2 min read·beginner

Why marketplaces shouldn't hard-delete listings

When a listing goes inactive on a marketplace — a seller closes their account, a venue cancels, a product is removed — the naive response is to delete the record. It's gone, it's irrelevant.

But that record contains exactly the information you need to win them back:

  • Contact details
  • What they listed and at what price
  • When they were last active
  • Why they stopped

A hard delete destroys all of this. A soft delete — setting isActive = false — preserves it. Your inactive records become your CRM.

Enforce it at the database level, not in application code

Application-level soft delete is fragile. Any developer, any migration script, any admin panel with a "Delete" button can bypass it. Six months later someone writes a cleanup script that issues DELETE WHERE isActive = false and you lose your entire lapsed-user pipeline.

The reliable approach is to remove DELETE permission from the application database role entirely:

-- Application role: can read, insert, update — cannot delete
REVOKE DELETE ON TABLE listings FROM app_role;

-- Admin role: can delete, but only with explicit confirmation
GRANT DELETE ON TABLE listings TO admin_role;

Now isActive = false is not a convention — it's the only option the application has. Hard deletes require admin credentials and an explicit action.

What to build on top of inactive records

Once you've preserved the data, build the re-engagement workflow:

  • Filter inactive records by time since last activity (30 days, 90 days, 6 months)
  • Segment by what they listed — different outreach for high-value vs casual sellers
  • Track re-activation rate as a metric separate from new user acquisition

The conversion rate on re-engaging inactive users is almost always higher than acquiring new ones. They already know your platform. Something caused them to stop — a direct outreach with a specific reason to return is often enough.

The naming convention matters

Don't name the column deleted or is_deleted. Name it isActive or status. The framing shapes how developers think about the data.

A column called deleted invites deletion-by-update thinking — "we're pretending it's deleted." A column called isActive frames it correctly — this is an active/inactive lifecycle state, not a tombstone.

When soft delete is the wrong pattern

Soft delete adds complexity. It means every query needs a WHERE isActive = true clause, or you risk surfacing inactive records in user-facing views.

It's worth the overhead when:

  • Inactive records have re-engagement value (marketplaces, SaaS)
  • You need audit history for compliance
  • Users expect to be able to reactivate ("I want my old account back")

It's not worth it for truly ephemeral data — log entries, session records, temporary tokens. Hard delete those.

The rule of thumb: if a business person would want to contact the entity represented by that record, soft delete it.

More like this, straight to your inbox.

I write about Architecture and a handful of other things I actually care about. No schedule, no filler — just when I have something worth saying.

More on Architecture

Catch data conflicts before code review, not after

Two features touching the same database table is a conflict waiting to happen. A feature registry and a mandatory conflict check forces the conversation before the code is written.

Sequential vs Parallel Execution: when faster is the wrong answer

The instinct is always to run things in parallel. Here's why that instinct can get you banned, blocked, or with corrupted data.

If this raised a question, I'd be happy to talk about it.

Find me →
← Back to Learn