SCOPE: everything in progressdocs/compliance/bc-dr-plan.md · build 40bb41bdb460

Business continuity and disaster recovery plan (draft)

Sign-off: approved by [Kyle] on [date], second reader [Dan] on [date]; recorded in approvals.md. Review yearly.

Draft for AV-3 and ORG-24, with the restore test for AV-1, AV-2 and ORG-23. 27 Oct 2026. Owners: Kyle (plan), Dan (restore test). Review yearly, after the tabletop.

What matters most

Drivers must be able to file a DVIR every morning. The offline DVIR already keeps inspections on the tablet until the server confirms them, so a short outage of Supabase or Vercel loses no inspections: they wait in the outbox and upload when the service returns. Dashboards and reports can wait longer.

Targets (to confirm by measurement, then put in the contract)

Target How it is met Status
RPO (data we could lose) 5 minutes with point-in-time recovery; up to 24 hours today Supabase point-in-time recovery if bought; the daily backup today PITR off (read 28 Oct): RPO up to 24 hours today; AV-2 decides
RTO (time to be back) 4 hours Restore into a new project, repoint Vercel Never measured (AV-1)
Capture during an outage No inspection lost The offline outbox Built; device test pending

Do not put these numbers in a contract until the restore test below has met them.

Scenarios

Scenario What we do Who
Supabase down (their outage) Watch status.supabase.com; tell customers capture continues offline; nothing to restore Kyle tells customers, Dan watches
Vercel down Watch vercel-status.com; the installed app still opens from its cache for DVIR capture; dashboards are down Same
Data deleted or corrupted (a bad migration, a mistaken reset) Stop writes; restore the last daily backup before the damage (or a point before it, if PITR is bought) into a new project; check; repoint Dan
Supabase project lost or account locked Restore the latest backup into a new project in the Lucent Axis org; rotate keys; repoint Vercel Dan
GitHub unavailable Every laptop holds a full clone; Vercel keeps serving the last deployment Dan
A person unavailable Two owners on every account (OW-6); this plan and the vault let the other act Kyle, Dan

A lesson from the first copy (28 Oct)

The company database began as a copy of the demo database, and the copy did not keep the database's permissions: 83 tables and 26 column grants came back with Supabase's defaults, so signed-in users could write tables the migrations had made read-only. Row-level security still held, but the grants were a second wall that had gone. Every restore or copy therefore ends with scripts/db/verify_*.sql (they fail on exactly this) and a comparison of grants against the source; a pg_dump taken for a restore keeps privileges (no --no-privileges).

Restore test record

A full timed restore once before the Type I, then once a year; a quarterly spot check in between (the control calendar). One copy of this table per test, kept in docs/compliance/evidence/<year>/ and logged in the control calendar (or in the compliance platform, if one is chosen).

Field Value
Date and who ran it
Source: project and the point in time restored to
Target: new project name (never the live one)
Started / data available / app working against it
Measured RTO (start to app working)
Measured RPO (restored point vs the last write before it)
Checks: row counts of incident, inspection, action, person match; a persona signs in; a photo opens
Problems found and what changed
Target project deleted afterwards (date)

Note for whoever runs it: never point load.sh --reset, demo_reset() or any reset at the live database during a test. Restore into a NEW project.

On-call

Two people, Kyle and Dan, each the other's backup. Severity 2 and 3: a response within business hours. Out of hours: best effort, until a client contract says otherwise. Phone numbers and other contact details are kept in the vault, not in the repository. Severity is defined in the incident response plan.

Tabletop (ORG-24)

Once a year: one hour, one scenario from the table above, walked through end to end. First suggestion: a migration drops a column on a Tuesday morning and is noticed at noon. Record who attended, what was found and what changed.

Back to top