Config versioning & backups
Path: /admin-settings → Backups tab, and the per-row History action on each config table.
Once a SuperAdmin saves a change to a config row, the previous state is normally gone. Config versioning adds three recovery capabilities on top of the live editors, all scoped to the platform-wide config domains:
- Per-row version history — snapshot any single config row on demand, list prior versions, and restore one as the live state.
- Whole-platform backups — one-click snapshot of every config domain into a timestamped row, restorable per-domain or all-at-once.
- JSON export / import — bundle the current config into a single JSON document to hand to an OpCo or attach to a ticket, and re-apply it (optionally a subset of domains).
Covered domains
| Domain | Per-row history | In backup | Notes |
|---|---|---|---|
| SIP trunks | ✅ | ✅ | History action on the table; Save snapshot in the editor. |
| Egress trunks | ✅ | ✅ | Includes base-number join state. |
| Base numbers | ✅ | ✅ | Includes team / header-manipulation / egress-trunk join state. |
| Cron schedules | ✅ | ✅ | History action on the table. |
| Platform settings | ✅ (per key) | ✅ | All nine setting keys are captured — unset keys resolve to their schema default, not omitted. |
| Platform secrets | ❌ | ✅ | Registry only (see below). |
A platform backup and an export produce the same JSON shape. A backup persists it as a ConfigBackup row; an export hands the same document straight to the browser as a download.
Per-row version history
Each of the four config tables — SIP trunks, egress trunks, base numbers, and cron schedules — has a History action on its rows that opens a slide-over sidebar. Platform settings expose a per-key Save snapshot button instead.
| Action | Description |
|---|---|
| Save snapshot | Captures the current live row and increments its version number. Optional note (≤ 500 chars) labels the checkpoint. |
| Restore | Re-applies a chosen snapshot to the live row through the same write path the editor uses. The pre-restore state is auto-captured as a new version, so the rollback itself is auditable. |
| Diff with current | Compares a snapshot against the current live row (or another version) and lists added / removed / changed fields. |
Versions are listed newest-first with the version number, optional note, the capturing user, and a relative timestamp.
Restore overwrites the live row. The previous live state is preserved as a new version entry — recover it with another restore if needed.
Whole-platform backups
The Backups tab lists timestamped ConfigBackup rows. Each row bundles all six domains into a single JSONB payload.
| Action | Description |
|---|---|
| Create backup | Snapshots every config domain into a new ConfigBackup row. Optional note. |
| Download | Exports the backup payload as a JSON file. |
| Restore all | Re-applies every domain from the backup to the live platform. Each modified row produces a new version entry (except platform secrets, which have no per-row history). |
| Restore domain | Re-applies a single chosen category from the backup. |
Atomicity and concurrency
Restore all runs inside a single serializable transaction that takes ACCESS EXCLUSIVE locks on all six config tables in a fixed order before any per-row work. This means:
- A concurrent backup or a parallel restore queues behind the lock — it sees either the full pre-restore or the full post-restore state, never a mix.
- An editor save running while a restore is in flight blocks briefly (typically 1–3 s for tens of rows) until the restore commits, then proceeds.
- The lock order is deterministic, so two concurrent restores cannot deadlock.
Rows that fail during a full restore are not re-thrown: each is reported as failed in the result (with the error message) and skipped, while the remaining rows still commit together inside the one transaction.
Platform secrets in backups
The Platform secrets registry is included in backups and full restores for completeness, but individual secret slots have no per-row history (no History action, no per-row version entries).
- Only registry metadata is captured — key, purpose, description, timestamps.
- Secret values live in AWS Secrets Manager and are intentionally never part of the bundle.
- During a full restore, the secrets registry is restored before SIP and egress trunks, because trunks reference secret slots by id (
tlsCaCertMaterialId,tlsClientCertMaterialId,tlsClientKeyMaterialId). Recreated slots keep their original ids so those foreign keys stay valid.
JSON export / import
| Action | Description |
|---|---|
| Export | Downloads the current platform config as a schema-versioned JSON document — the same shape a backup stores, but without writing a ConfigBackup row. |
| Import | Two-step: Preview validates the payload and returns a per-domain diff summary (live count, bundle count, only-in-live, only-in-bundle); Apply re-applies a chosen subset of categories. |
Import applies only the categories you select; unselected domains are left untouched. Each modified row produces a new version entry, except platform secrets.
deleteMissing is wired through the import input but is a no-op today — rows present in live config but absent from the bundle are not deleted. This is deliberate: import is additive/restorative, not destructive.
Audit trail
Every versioning and restore operation writes to the Access logs:
| Operation | Audit category | Action | Notable details fields |
|---|---|---|---|
| Save snapshot | CONFIG_VERSION | UPDATE | captured: true, version, configCategory |
| Restore a version | the row's domain | UPDATE | restoredFrom, restoredFromVersion, old, new |
| Restore all / domain | the row's domain | CREATE / UPDATE | restoredFromBackup, recreated (when the live row was missing), old, new |
| Row failed during restore | CONFIG_RESTORE_FAILURE | UPDATE | error, configCategory, backupId |
A row whose live counterpart was deleted before a restore is recreated from the snapshot (audit action CREATE, recreated: true) rather than skipped — "restore from backup" brings back what was lost.
See also
- Platform settings — the nine keyed settings captured by backup.
- Platform secrets — the registry included in backups.
- Access logs — where restore failures surface for investigation.
- Configuration model — where this UI's settings ultimately live.