v-va*

VA.2026.014 · Floor -1 · vault · hall 16

va-backup

collection Exnest VA Collection
accession VA.2026.014
classification Infrastructure Engine · Queue + Async Worker · Neon + Mongo → R2 → GitHub · Elysia + Bun
floor Floor -1 · vault
status in development
condition beta · 7 phases · 151 tests · 2 CI workflows
acquired 2026
revision Rev. A
drawing DWG-014
room 01 curator sheet 01 / 09 · rev Rev. A

“a backup is not a file — it is a promise that can be checked.”

va-backup is the collection's insurance policy. It reads two live databases — Neon PostgreSQL and MongoDB — dumps both read-only, compresses them with zstd, hashes each with SHA-256, uploads to Cloudflare R2, verifies the upload, then writes a manifest back to GitHub. Nothing here writes to production. That single rule shapes every other decision in the machine: the primary database is chosen by a config flag, not a connection string guess, and consistency is checked before a single byte is dumped.

The engine is split by responsibility, not by feature. An external scheduler — cron-job.org — POSTs a trigger and leaves; the API only enqueues, never dumps; a separate worker process claims jobs with an atomic lock, holds a 30-second heartbeat, and executes the pipeline. A duplicate trigger with the same idempotency key returns 200 instead of enqueuing a second copy, and a worker that dies mid-job leaves a stale heartbeat that the next worker requeues. The API can live on Vercel with a 60-second budget; the worker cannot, so it runs on a container. The split is the design.

Before the backup, a consistency gate decides whether the backup is worth taking: PostgreSQL schema and index compared structurally against an expected-state snapshot, Mongo index inspected, both reduced to hashes, drift reported as PASS, WARNING, or FAIL. Only PASS and WARNING proceed — a FAIL stops the pipeline rather than preserving a broken picture. Restore is the same instinct reversed: it refuses to touch production by default, targets staging, then re-verifies schema hash, index hash, table counts, collection counts, and sample records before anyone calls the recovery finished. Every provider has a local filesystem mode, so the whole vault runs on a laptop with no credentials at all.

VA.2026.014

va-backup

Infrastructure Engine · Queue + Async Worker · Neon + Mongo → R2 → GitHub · Elysia + Bun


artist / curator
v-va
date
2026 — present (private engine, built on the Exnest convention)
status
in development
condition
beta · 7 phases · 151 tests · 2 CI workflows
medium
1,855-line implementation plan · Neon PostgreSQL + MongoDB sources · Cloudflare R2 artifact store · GitHub manifest repository · zstd compression + SHA-256 · Prisma queue store · OData V4 envelope · exponential backoff + heartbeat
phases
7
design rules
31
internal endpoints
6
tests
151
artifacts per run
2 (Neon · Mongo)
default retention
30 days
acquired
2026
revision
Rev. A
origin
drawn as a 1,855-line plan before a line of code, 2026
room 02 evolution of this work sheet 02 / 09
2026

The Plan

1,855 lines and 100 numbered sections written before implementation: five providers, one queue, one worker, and 31 closing design rules. Phases 1 through 7 drawn up front — infrastructure, core engine, backup, consistency, reliability, metadata, recovery.

2026

The Gate

consistency engine built before the dump logic it guards. schema hash, index hash, and drift detection decide whether a backup is allowed to exist; FAIL stops the pipeline rather than archiving a broken picture.

2026

The Pipeline

Neon and Mongo dumped read-only, primary first; zstd compression, SHA-256 checksum, R2 upload, then a four-step verification — object exists, size matches, metadata matches, checksum verified.

2026

The Separation

rule 88 enforced in deployment: the API ships to Vercel under a 60-second function budget, the worker runs on its own host. Restore, needing minutes and a zstd binary, moved out of serverless entirely.

2026

The Template

the repository became a master template — one clone per project, each with its own BACKUP_PLATFORM slug and its own expected-state snapshot. A new deployment is a copy and a .env, not a new build.

2026

Proof

151 tests across 38 spec files, with live suites against real Neon, Mongo, R2, and GitHub gated behind flags so the default suite stays green offline. Two CI workflows: verify on every push, live on manual dispatch.

concepts — kept & discarded

kept — one trigger, one queue entry, one worker; nobody waits on a backup

kept — consistency as a gate rather than a report

held — one clone per project over multi-tenant configuration

discarded — internal scheduler; cron-job.org stays the source of truth

archive ref — VA.2026.014/CON

cross ref — timeline fig. 01

room 03 original sketches sheet 03 / 09

curator annotations

on scheduling

no internal cron. the schedule lives in cron-job.org and in BACKUP_SCHEDULE, and if they disagree the manifest says so — two sources of truth beat one silent lie.

on local mode

every provider has a filesystem twin behind STORAGE_DRIVER=local. the vault runs end to end on a laptop with zero credentials — the most useful test harness ever written.

on deletion

retention may never remove the latest successful backup, a referenced backup, or one in use by a running restore. an expiry policy that can delete the only good copy is not a policy, it is a countdown.

fig. 01 — VA.2026.014.a the plan document· 100 sections · 31 rules · authoritative 1,855 lines, written in full before implementation. the definition of done lists 26 conditions the engine had to satisfy to call itself finished.
fig. 02 — VA.2026.014.b the queue data structure· BackupJob · atomic claim · live idempotencyKey and backupId both unique. status, attempt, maxAttempt, heartbeatAt, nextRunAt — a job is a record, not a thread.
fig. 03 — VA.2026.014.c the gate protocol· PASS · WARNING · FAIL · enforced schema hash and index hash compared against expected-state. only PASS and WARNING let the pipeline continue; a FAIL is a refusal, not a warning.
fig. 04 — VA.2026.014.d the artifact object· zstd · SHA-256 · immutable one dump, one checksum, one object key. uploaded, then verified four ways before the manifest is allowed to mention it.
room 04 interface reviews sheet 04 / 09
fig. 05 — VA.2026.014.e the knock render POST /internal/backup/trigger — 202 job created, 200 duplicate, 401 wrong secret. the scheduler never waits for a backup.
fig. 06 — VA.2026.014.f the answer render GET /internal/backup/status — queue depth, current job, last success, and freshness: age against interval, stale or not.
fig. 07 — VA.2026.014.g the ledger render manifest committed to platforms/<slug>/ in GitHub — metadata and recovery tooling beside the code, artifacts themselves living in R2.
room 05 catalog record sheet 05 / 09
materials1,855-line implementation plan · Neon PostgreSQL + MongoDB sources · Cloudflare R2 artifact store · GitHub manifest repository · zstd compression + SHA-256 · Prisma queue store · OData V4 envelope · exponential backoff + heartbeatdimensionsphases — 7 · design rules — 31 · internal endpoints — 6 · tests — 151 · artifacts per run — 2 (Neon · Mongo) · default retention — 30 days
conditionbeta · 7 phases · 151 tests · 2 CI workflowsacquired2026
revisionRev. Aarchive locationDWG-014 · floor Floor -1 · vault
internal referenceVA.2026.014/Morigindrawn as a 1,855-line plan before a line of code, 2026
room 06 the archive sheet 06 / 09

failed experiments

✕ 2026

the serverless restore

the first deployment put /internal/restore on Vercel. it needs minutes and a zstd binary and lost the race against the function timeout. restore moved to the worker host; only fast queries stayed serverless.

✕ 2026

one engine, one project

the single-platform model started as a limitation and became the design. no multi-tenancy on the engine; instead, one clone per project with its own platform slug and its own expected-state snapshot.

✕ 2026

backup before verification

dumping first and checking later wastes storage on a picture already known to be wrong. the gate was moved in front of the pipeline, where it can still refuse.

draft concepts

  • 100-section implementation plan
  • failure matrix
  • disaster recovery runbook
  • retention safety rules
  • expected-state snapshot format

research notes

— the API that schedules and the process that executes must be able to fail independently — coupling them couples their timeouts.

— verifying an upload after it succeeds is the difference between 'we sent it' and 'it is there'.

— restoring into staging by default removes the most dangerous operation in the system from the path of least resistance.

— a snapshot of expected schema and indexes turns drift detection into a diff, and diffs are reviewable.

room 07 architecture · technical drawing DWG-014 · rev Rev. A
DWG-014 · Rev. A · floor plan — va-backup curator annotation — zones 03–05 are load-bearing; the presence layer must remain unshaded.
room 08 design statement sheet 08 / 09

I. Never touch the source

The backup path is read-only by construction, not by discipline. Production databases are never written to, never locked, never used as a scratch space — the engine observes a running system and leaves it exactly as it found it.

II. Asynchronous or it is not a backup

A request that waits for a dump is a request that times out, and a timeout is indistinguishable from data loss. The API enqueues and returns 202; the worker owns the work, the heartbeat, and the retries.

III. Verify, then believe

A successful upload is a claim, not a fact. Objects are checked for existence, size, metadata, and checksum; restored data is checked for schema hash, index hash, counts, and samples. Nothing in this engine is trusted because it reported success.

room 09 related works & future vision sheet 09 / 09

future vision

The vault widens: incremental dumps beside full ones, per-table restore, retention tiers for daily, weekly, and monthly artifacts, and alert routing that treats a stale backup as an incident rather than a metric. The direction never changes — the copy that exists is worthless until someone has proven they can bring it back.