---
title: "Show Me What You Deleted (So I Can Undo It)"
canonical: https://dxdev.com/blog/2026-06-23_visible-deleted-state-recovery/
datePublished: 2026-06-23
---
At 6:44 PM on June 23, I stopped treating a removed domain as if it had never existed.

That sounds like a small UI decision. It is not. When a domain expires, the wrong screen can make a recoverable account state look like permanent data loss. The customer sees no domain. Staff search sees no domain. The detail page offers no explanation and no recovery path. Everyone is left asking the same bad question: where did it go?

The answer was not that the record was gone. The product had made it invisible, and the product that made it invisible was one I had a hand in building. Every customer who hit this before June 23 got told, in effect, that their domain had disappeared, by a design choice that treated a filter on a query as the same thing as the truth about what still existed.

## A missing row is not a clean state

The diagnostic path started with the two surfaces that matter when something leaves an account: the account detail page and staff search. If an expired domain disappears from both, the product has erased the evidence that the account ever had it. That is clean only from the perspective of a current-state query. It is terrible from the perspective of a customer who needs to understand a change or a staff member trying to fix one.

What it looked like was an account with no domain. What it actually was was an account with a domain record in an expired state.

Those are not equivalent states. The first one invites a new setup flow. The second one needs an explicit recovery action.

So we kept the removed domain on the detail page. It stays visible, struck through, instead of being silently filtered out. We kept it in staff search too. Next to it, we put one action that states exactly what will happen: re-activate.

The important implementation detail is that re-activation reuses the same record. We are not creating a replacement record that happens to contain the same domain. We are restoring the record the account already had.

That choice preserves a coherent history. It also keeps the workflow honest. A customer is not starting over. They are recovering something the system can still see.

## The alternatives all hide a different problem

Hard deletion was the simplest option to explain in code. When a domain expires, delete the row and let the account read as empty. It loses immediately because there is nothing left to recover. The system would have to reconstruct an identity it just threw away.

Keeping the record but hiding it from every customer-facing surface is better for internal retention, but not for the person looking at the account. That design turns an ordinary account state into a support investigation. Staff can find an archived record somewhere, while the customer has no indication that a reactivation is possible.

Creating a new record on reactivation avoids an explicit state transition, but it produces the wrong model. An expired domain is not a different domain. The existing record is the object whose state changed. Reusing it is both simpler and more accurate.

The struck-through presentation is deliberate. It distinguishes expired from active without making the record disappear. It is an interface-level claim that the domain is no longer active, not that it has been erased from the account's history.

## The report became the cleanup queue

The customer and staff views solve the immediate recovery problem. The staff Domain Report needed a different change. We converted it into a renewal and cleanup view that defaults to expired sites.

Defaulting to expired changes the report from a broad inventory screen into a queue for the work that needs attention. It also flags Rookie and Pro accounts that are still carrying a platform-managed domain. That combination matters because expiration is not the only condition worth finding. A lower-tier account with an active managed domain is a separate cleanup decision, and it should not be buried in a report built around active sites.

The sequence now has a shape we can reason about:

1. A domain expires, but its record remains available.
2. The account detail page and staff search show that record as inactive.
3. Re-activate restores the same record instead of creating another one.
4. The staff report defaults to the expired work and identifies tier mismatches that need review.

The remaining work is deliberately separate. We still need domain-aware expiration emails, then a careful bulk catch-up for existing records. Neither belongs in the first change. The first change makes the current state visible and reversible. That gives us a safe base for communicating expiration and repairing the backlog without asking staff or customers to infer what disappeared.

Deleted is a data operation. Expired is an account state. The product should not confuse the two.
