Backups, recovery and continuity
Backups
- Every night. The whole service is backed up at 02:30 UTC to a separate storage bucket at our hosting provider. Each backup is kept for 14 days. The newest complete backup is never deleted, however old it is.
- Every hour. The database that holds accounts, sign-ins, workspaces and billing is also copied every hour. The newest 48 copies are kept. We are alerted when the newest copy is more than two hours old or when two copies in a row fail.
- Consistent copies. Databases are copied while the service runs, with a method that keeps each copy consistent even while the app writes. Every backup lists each object it holds with its size and a SHA-256 hash, so a damaged or incomplete backup is detected.
- Reports twice. As each report is saved, its files are also mirrored to separate object storage at Cloudflare, in its EU jurisdiction, so a report survives the loss of the main volume. The mirror is best effort: a copy that fails is logged and the report is still saved, and a later backfill pass uploads the files the bucket lacks. They are in the nightly backup as well.
What a backup holds
The databases (accounts, workspaces, runs, decisions on findings, settings, scorecards and the audit logs), report files, the originals kept for the review editor or under a workspace's agreed longer keep, Learn records, checklists, workspace logos and the service's job records.
What a backup does not hold
Uploaded files, by design. An upload lives at most 24 hours. A workspace can agree a longer keep for its uploaded files with us; we set it per workspace. An uploaded file is not in a backup, except an original kept for the review editor or under a workspace's agreed longer keep, which is in the nightly backup for 14 days like a report. Spelling dictionaries and caches are not in a backup either; the service fetches them again.
A report a customer deleted is still inside the backups taken before the delete until they rotate out, within 14 days. If we ever restore one of those backups, every deletion made after it is applied again before the service opens, so a deleted report or account does not come back.
Recovery
The restore drill
A drill restores a backup into a temporary place, never over the live data. It checks that every database passes an integrity check, that the row counts match the backup's own list, that every file's hash matches and that the database export can be read. A restore follows the same checks before the service opens on the restored data.
Recovery point
How much recent work a restore could lose. These are the targets when the scheduled copies succeed: the real recovery point is the time of the last copy that did succeed. A failed or late hourly copy alerts us after two hours, a failed nightly backup alerts us the same night.
| Data | Recovery point (target) |
|---|---|
| Accounts, sign-ins, workspaces and billing | 1 hour (the hourly copy) |
| Runs, decisions on findings, settings, scorecards and the audit logs | 24 hours (the nightly backup) |
| Report files | The last successful copy to the report mirror, usually seconds after the report is saved; a report whose copy failed is covered by the nightly backup, so 24 hours |
| Uploaded files | Not recovered; upload the file again |
| Originals kept for the review editor or under a workspace's agreed longer keep | Restored with the nightly backup, so 24 hours |
Recovery time
The time to bring the service back from a backup has not been timed on a full drill yet. Measured on request: we run the drill with a clock and send you the number.
Continuity
- One region, one instance. The service runs as one instance in one region, with its own data volume. A deploy stops the old instance before the new one starts, so each deploy brings about 40 seconds of downtime.
- Health check. The service answers at
/healthwith whether its database and profiles are ready, and a deploy goes live only once this check answers. A deeper check, for our own uptime monitor only, also reads the free disk space and the age of the last backup. - Shared background work. Background work is shared across workspaces, so a very large job can slow other workspaces' queued work. Large platform-wide scans are capped and labelled partial.