> ## Documentation Index
> Fetch the complete documentation index at: https://docs.casebender.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Storage Backup and Restore

> Protect PostgreSQL and exact object versions as one consistency set

A CaseBender recovery point is PostgreSQL plus every referenced exact object
version, configuration, and cryptographic key. A database dump or bucket copy
alone is not a valid recovery set.

## Recovery-set contents

* a PostgreSQL snapshot/dump and migration identifier;
* every non-deleted finalized `StoredObject` at its recorded `profileKey`,
  `objectKey`, and `providerVersion`;
* SHA-256 and size for each object;
* backup profile, backup object key, and exact backup version;
* storage/identity/CA configuration versions;
* field, credential, audit-integrity, authentication, and signing keys;
* immutable CaseBender image digests and release manifest; and
* timestamp, approvals, tool versions, measured RPO/RTO, and evidence digest.

Encrypt the set, restrict access, and store it independently of the primary
failure domain. Do not write credentials or object contents to backup logs.

## Capture a consistency point

Quiesce user/integration writes or use a provider/database snapshot method that
guarantees an equivalent consistency boundary. Drain or durably pause workers.
Record the PostgreSQL snapshot/LSN and exact object versions before resuming.

Generate the object inventory:

```bash theme={null}
pnpm storage:backup-verify inventory \
  --output '<protected-manifest.json>'
chmod 600 '<protected-manifest.json>'
```

The command runs a serializable database transaction and refuses objects
without exact version, SHA-256, or size metadata. It does not copy the bytes;
the approved backup process must populate `backupProfileKey`,
`backupObjectKey`, and `backupVersionId` for every manifest entry.

Hash and protect the completed manifest:

```bash theme={null}
sha256sum '<protected-manifest.json>' \
  > '<protected-manifest.json>.sha256'
```

## Copy policy

Copy first and retain the primary. Never use a destructive synchronization
operation as the first backup or migration step. Verify bytes by downloading
and calculating SHA-256; do not rely on ETags.

Preserve all required historical versions and retention/hold state. Ordinary
object copy may not preserve provider-specific ACL, CMEK, Object Lock,
immutability, legal hold, event-based hold, metadata, or version history.
Attest and reproduce those controls at the destination.

## Isolated restore verification

Restore PostgreSQL to an isolated environment using the same compatible
CaseBender release. Ensure the manifest's database migration and stored-object
metadata match, then restore objects to a dedicated verification prefix:

```bash theme={null}
pnpm storage:backup-verify verify-restore \
  --manifest '<protected-manifest.json>' \
  --target-profile '<isolated-restore-profile>' \
  --isolated-prefix 'tenants/<test-tenant>/restore-verification/<exercise-id>' \
  --evidence-output '<sanitized-restore-evidence.json>'
```

The script reads each exact backup version, verifies size and SHA-256, uploads
to the isolated target, downloads it, and verifies SHA-256 again. It writes the
evidence file with mode `0600`. Clean up the isolated prefix through the
approved retention-aware process after evidence review.

Then verify login, organizations, cases, evidence, attachments, exports,
scanner state, retention, legal hold, audit-chain integrity, and authorization.
Never connect a rehearsal to production integrations.

## Provider caveats

### S3 and Ceph RGW

Capture version IDs and all delete markers. Object Lock must exist when the
bucket is created and cannot be inferred from an adapter. A copied object may
receive a new version and retention state. Use the exact certified product
version and private CA during restore.

### Google Cloud Storage

Capture numeric generations. Validate retention-policy lock, object retention,
event-based holds, CMEK access, uniform bucket access, and public-access
prevention. Generation numbers change when copied to another bucket.

### Azure Blob Storage

Capture blob version IDs. Validate secure transfer, account/container
versioning, encryption keys, immutability policy, and legal holds. Restored
versions receive destination-specific IDs.

### Local or legacy MinIO

Local storage is not a production target. Preserve both legacy MinIO volume
snapshots and API-level exact-object exports during migration; never import
MinIO's internal layout as ordinary files.

## RPO and RTO evidence

Record:

* last included database transaction and object version;
* first excluded transaction;
* backup duration, restore duration, validation duration, and service resume
  time;
* actual data-loss interval (RPO) and recovery duration (RTO);
* missing, changed, unreadable, held, or policy-blocked objects; and
* rollback exercise outcome.

A policy target is not evidence. Retain measured results for every supported
release train and after material storage changes.

See [Storage Migration](/en/deployment/storage-migration-runbook) for cutover
and rollback and [Backup and Recovery](/en/deployment/recovery) for the wider
installation recovery set.
