Single-tenant recovery for pooled Postgres SaaS

Undo one tenant. Leave everyone else live.

TenantUndo maps tenant-owned rows, object storage links, and live-data conflicts so your team can restore, erase, export, or prove legal hold for one customer with signed evidence.

0
production row values leave the customer VPC
7
job types: analyze, report, extract, diff, plan, merge, erase
4-eyes
approval before restore or erase writes
tenantundo / acme-prod
plan awaiting approval
tenant orders files events shared refs
Tenant closure 18,204 rows / 1,942 objects
Postgres S3-compatible storage Outbound runner Signed evidence Control-plane dashboard pg_tenantundo CLI

The failure mode

Your backup restores the database. It does not restore a customer.

The tenant is not one table

Rows spread through foreign keys, composite keys, join tables, UUID tenant keys, denormalized columns, and app-enforced relationships that a simple WHERE tenant_id = ? misses.

Files are outside Postgres

Invoices, uploads, exports, and attachments live in object storage with conventions the database cannot enforce.

Live merge-back is dangerous

Primary keys, sequences, unique indexes, current writes, triggers, and cascades can corrupt other customers unless the plan is verified first.

Feature set

Everything needed to rehearse and execute tenant-level data surgery.

The current app combines a Go recovery engine, standalone drill CLI, customer-side runner, control-plane API, dashboard, billing gates, RBAC, scheduler, audit log, and signed evidence archive.

Schema introspection

Reads tables, columns, primary keys, foreign keys, identity columns, generated columns, and tenant-root metadata before any tenant operation.

Tenant graph resolver

Classifies tables as root, tenant-owned, shared, ambiguous, or excluded, then refuses unsafe extraction until manifest rules resolve gaps.

Readiness report

Generates an HTML recovery report with graph safety, blockers, ambiguous tables, inferred relationships, and recommended fixes.

Tenant extract bundle

Extracts a complete tenant closure to customer-side files with a manifest and deterministic hashes for replay and verification.

Diff and conflict engine

Compares live data against the bundle and reports missing, changed, and extra rows per table before a merge plan exists.

Plan-hash restore

Computes a merge plan, pins it to a hash, requires matching human approval, then verifies other-tenant checksums inside the transaction.

Provable erase

Plans tenant deletion, counts affected rows and object keys, executes only with approval, and emits signed proof after blast-radius verification.

Object storage linkage

Tracks blob columns and S3-compatible object keys alongside database rows so restores, exports, holds, and erasures cover files too.

Migration and export

Uses the same extract bundle and graph rules to move, copy, or preserve one tenant without forcing a full architecture migration first.

Job state machine

Enforces pending, dispatched, running, awaiting_approval, approved, done, and failed transitions so illegal jumps are refused.

RBAC, audit, billing

Admin, operator, and auditor capabilities are scoped by org, recorded in audit, and gated by Assess, Guard, or Control plans.

Scheduled drills and drift

Runs recurring report or analyze jobs and raises drift when a fresh tenant graph no longer matches the last known-good manifest.

Workflow

From 3am incident to rehearsed runbook.

  1. 01

    Analyze

    The runner introspects the schema with a read-only role and sends only metadata: graph counts, table names, hashes, and status.

  2. 02

    Report

    The app turns the graph into a readiness report with blockers such as ambiguous relationships, unsafe triggers, missing keys, or FDW tables.

  3. 03

    Extract and diff

    Restore your PITR snapshot to scratch, extract the tenant bundle, then diff it against live data to identify conflicts.

  4. 04

    Plan

    TenantUndo computes a merge or erase plan and returns the hash. The plan itself remains on the runner side.

  5. 05

    Approve

    A second authorized user approves the exact plan hash. Auditor accounts can read evidence but cannot create or approve mutations.

  6. 06

    Merge or erase

    The write role is used only for approved restore or erase jobs, then TenantUndo verifies that non-target tenants stayed unchanged.

What ships

A full product surface, not a one-off script.

TenantUndo has a standalone drill path for early customers and a control-plane path for recurring operations.

CLI

pg_tenantundo

Analyzer and drill tool for local execution: report, extract, diff, plan, execute restore, plan erasure, and execute erasure.

  • -report readiness HTML
  • -extract-tenant bundle creation
  • -diff live-vs-bundle counts
  • -execute approved merge plan
  • -erase-plan and -erase-execute

Control plane API

Jobs, approval, evidence, audit

GET /v1/jobs POST /v1/jobs GET /v1/jobs/{id} POST /v1/jobs/{id}/approve GET /v1/jobs/{id}/evidence GET /v1/audit

Runner

Customer-side agent

Runs in the customer VPC, connects outbound over WebSocket, reads DSNs from env or secret storage, verifies signed jobs, and reports metadata only.

  • Read-only DSN for analyze, report, extract, diff, plan
  • Separate write DSN for approved merge or erase
  • One-time registration token
  • Signed job protocol

Dashboard

Operations console

IDTypeState
j-1082analyzedone
j-1083mergeawaiting
j-1084eraseapproved

Create jobs, inspect state, approve plan hashes, and view the audit log from the embedded web UI.

Security posture

Designed for the review you already know is coming.

TenantUndo is built around a narrow wire protocol: the control plane gets metadata and signed evidence, not customer records. Every write is gated by a hash-pinned plan and a second human approval.

  • Runner connects outbound only; no inbound database access from the control plane.
  • No customer DB credentials are stored in the control-plane schema.
  • Introspection refuses write-capable connections for read-only jobs.
  • Org scoping, RBAC, audit log, body limits, HSTS, CSP, and Stripe webhook signature verification are enforced in the API.
$ tenantundo verify acme-q3-drill.tu
OK signature valid
OK tenant rows recovered: 18,204
OK object keys recovered: 1,942
OK non-target tenants unchanged
! 3 ambiguous relationships require manifest rules

Deployment

Fits the way SaaS teams already operate Postgres.

Supported v1 scope

Pooled multi-tenant Postgres with one primary database and S3-compatible object storage. Works with existing PITR or snapshot workflows.

Install paths

Dockerfile, Compose for the control plane, Helm chart for the runner, systemd runner unit, and a standalone Go CLI for drills.

Explicitly out of scope

MySQL, MongoDB, DB-per-tenant architectures, sharded/event-sourced recovery, and multi-database tenant graphs are not positioned as v1.

Pricing

Start with a paid drill. Productize only after it proves useful.

Readiness Drill

$3k+

Two-week, read-only recovery assessment for one app and one representative tenant.

  • Schema dependency map
  • Object storage coverage review
  • Recovery runbook and signed report
Book the drill

Control

$2k+/mo

Full control plane for restore, export, deletion proof, approvals, runner management, billing, and audit.

  • Outbound-only customer runner
  • Plan-hash approvals
  • Merge and erase job execution
Talk to founder

Questions

Hard questions first.

Why not just use pg_dump or PITR?

PITR gets you a whole database at a point in time. TenantUndo handles the application boundary: which rows belong to one customer, which files belong with them, and how to merge back safely into live production.

Do customer rows leave our environment?

No by design. The customer runner performs analysis and recovery work in the customer environment. The control plane receives metadata, counts, hashes, status, and signed evidence references.

What if our schema has no foreign keys?

TenantUndo treats that as a normal case. It can infer likely relationships from conventions, but inferred or ambiguous relationships must be resolved with explicit manifest rules before unsafe operations proceed.

Is this only for restore?

Restore is the wedge. The same tenant graph supports extract/export, deletion proof, legal hold, and pooled-to-dedicated migration workflows.

First step

Find out if you can recover one customer before an incident proves you cannot.

Send a schema, a backup description, and one representative tenant. TenantUndo returns a recovery map, failure points, and the first signed drill report.