About Professional
How I Build How I Build Meet the Team
Technology Homelab App Showcase Case Studies
Maverick & Luke Say Hello

Case study

Retiring Apps Safely: A Repeatable Runbook, and the Query That Stopped a Wrong-App Data Drop

Turning app retirement from an ad-hoc, error-prone act into a repeatable nine-phase runbook applied across a dozen-plus apps. The standout moment was querying a database's own foreign keys to prove the docs had mislabeled a table's owner, preventing a live app's data from being deleted.

The challenge

An app fleet grows faster than it retires, and many apps were deployed onto a shared database schema rather than their own namespace, so one app's tables sit table-by-table alongside its siblings'. Generic table names, the kind every app creates, collide across apps, so a naive "drop this app's tables" can destroy a different live app's data. Compounding the risk, the development server had no backups: no safety net if a destructive operation went wrong.

The core problem: retire apps completely and safely, without breaking siblings and without leaving orphaned ports, firewall rules, secrets, monitors, or routes behind.

Approach: a nine-phase runbook, written from real teardowns

I formalized the procedure from an actual teardown rather than in the abstract, and every later execution that hit a new failure mode fed a new rule back into it. The nine phases:

  1. Pre-flight: confirm the last backup ran, confirm no live session touches the schema, dependency-check, optional dump.
  2. Service teardown: stop and remove the systemd unit.
  3. Network teardown: firewall rules deleted highest-number-first, both IP families; mesh-VPN routes revoked.
  4. Schema teardown: drop, update the API schema list, recreate the containers (a restart doesn't reload the env), verify.
  5. Monitoring cleanup.
  6. Sudoers cleanup.
  7. File archive: move, never delete.
  8. Source archive: repo archived read-only, never deleted.
  9. Docs + references update.

Plus a cross-cutting credential rotation: retirement is the trigger to revoke every external key the app used.

Two hard sub-rules were born from real incidents. For apps on the shared schema, run three sanity queries before any drop (list the shared tables, read the app's own schema for its exact table list, and grep every app's schema for those table names to catch collisions). And, since the development server had no backups, every destructive op there required an explicit "this data is disposable" confirmation in place of a backup check.

Consolidation, not just deletion. Many teardowns fired because a successor superseded the app: two apps folded into a single successor, a purpose-built service replacing an adopted tool, a docs system replacing a dashboard. That makes the runbook a deliberate architectural-upgrade tool, not attrition.

Results

What this demonstrates