Backup and restore

Reading time 5 min

Generated HTML is a release artifact, not the whole installation. Losing Markdown loses editable source. Losing accounts loses authentication state. Losing custom templates or configuration can make a clean rebuild different even when prose survives. Keep recoverable inputs, a known reader artifact and the recipe that connects them.

V2 has no general backup scheduler, remote backup service, point-in-time recovery or restore wizard. The operator chooses and rehearses storage, encryption, retention, access and recovery. Browser drafts and editor publication backups do not replace that process.

Inventory the selected paths

Layer Preserve
Source Full content tree, section metadata and media
Identity Site config and safe runtime settings
Customization Reviewed template, CSS, static changes
Accounts Selected users file
Header links Links file and cached icons
History Current audit file and retained archives
Publication Marker plus known output and release evidence
Engine Selected commit, package and lockfile
Operations Sanitized path, service, host procedure

The editor’s runtime files live beside the selected users file. Build runtime selection can differ. Record actual selections rather than assuming .markstack everywhere. --content does not select templates/config/static. Site settings and Build workflow explain precedence.

Runtime item Meaning in recovery
Accounts Names, roles, sections, hashes, auth versions and account timestamps
Links Validated header destinations/order/visibility
Icons Local cached icons for links
Settings Safe runtime branding overrides
Current history Current bounded operational records
Audit archives Up to three retained numbered files
Publish marker Last publication source fingerprint/time/count

Default runtime filenames are users.json, links.json, favicons/, site-settings.json, audit.jsonl and publish-state.json. Numbered audit archives use .1, .2 and .3 suffixes.

The users filename can be customized; users.json names the default. The account-write lock and process temp files are operational artifacts, not a durable session database. Do not restore a running process’s lock blindly. First establish that no writer owns it; the users store has its own dead-process/stale-lock rules. A malformed account file fails loading rather than safely reconstructing identities.

Account hashes and private operational history are sensitive even without plaintext passwords. Protect backups at least as carefully as live data. Keep them outside source, static folders, generated output and public repositories. Exclude credentials/private keys from support bundles and use your organization’s secret-recovery controls separately.

What V2 preserves and what it does not

Mechanism Limit
User write Owner-only temp file and rename; not a full-site snapshot
Settings, links write Separate file operations; not a cross-file transaction
Audit rotation Size-capped local history, not tamper-proof archive
Browser draft Device, site-local recovery, not another-host backup
Publisher previous output One prior reader, not source, accounts
Git history Only committed, tracked bytes, not all runtime, media
Session state In-memory; ends with restart

Audit rotation is checked before append when the current file is at least 1 MiB. Retention is current file plus at most three archives. One append can take current file beyond the threshold before the next rotation. Oldest records eventually disappear. Save required evidence before it rotates; the current account/file cannot reconstruct old events.

Source deletion has no editor undo. Recover from reviewed history/backups. A dist.previous reader can serve as a prior public artifact, but cannot recover Markdown syntax, account history or uncommitted edits reliably. It may not exist on a first publish or may have a different reported name after backup-rotation failure.

Consistent backup procedure

  1. Record engine, content, config, static, template, data and output paths and intended restore target.
  2. Confirm no publication is running. Saved source and generated output are different states.
  3. Coordinate writers and service processes for one consistent snapshot, using your installed maintenance process.
  4. Capture source and protected runtime together with selected engine/configuration and reviewed customization.
  5. Record capture time, included/excluded paths, permissions/ownership and hashes from the completed archive.
  6. Store a restricted copy away from the same machine/disk; encrypt and retain under your policy.
  7. Restore into a separate rehearsal environment and verify. Listing an archive is not recovery proof.

The editor’s publication snapshot coordinates its own staged operation, not arbitrary external writers or multi-instance backups. File-by-file copy during live changes can mix new Markdown, old grants and unrelated publication state. Do not claim consistency simply because the copy command returned success.

Disposable source-only example

This Unix example captures only a chosen content/config pair. It does not contain production accounts, whole customization, service configuration or secrets, and is not a complete installation backup. Replace paths only after a read-only inspection. Do not extract an untrusted archive or overwrite live folders.

# Inspect the intended inputs and a private destination first.
ls -ld /srv/field-guide/app/content /private-backups
ls -l /srv/field-guide/app/siteconfig.json

# Run only after coordinating writes and verifying these paths.
tar -czf /private-backups/field-guide-inputs.tar.gz \
  -C /srv/field-guide app/content app/siteconfig.json

# Inspect member paths before extraction.
tar -tzf /private-backups/field-guide-inputs.tar.gz

# This must be a new empty rehearsal folder, not live output.
mkdir /tmp/field-guide-restore
tar -xzf /private-backups/field-guide-inputs.tar.gz \
  -C /tmp/field-guide-restore

If archive creation fails, do not label the file usable merely because it exists. Check exit status and restore/compare the completed result. Choose a unique protected destination for real backups rather than repeatedly overwriting the only copy. OS ownership, ACLs, encrypted storage and restore semantics need your own tools/platform review.

Restore rehearsal

Check Evidence
Inputs Expected paths, bytes and complete customization
Engine Selected revision and locked dependencies
Build Isolated output, expected routes, index, resources
Audience No private runtime, server files served
Editor Correct protected users path; intended accounts, grants
Operations Save, publication and history on disposable data
Host Deep reload, real 404, cache, TLS, auth boundaries
Recovery Recorded missing pieces and cutover, return steps

Use a separate host/folder with no public access to private data. Restore reviewed paths and permissions before starting the editor. Install selected locked dependencies with Node 24+. Select restored accounts/runtime explicitly, build a new output, inspect reader behavior and verify section access with synthetic/rehearsal users.

A restarted editor requires fresh sign-in. Stored account auth versions are not session cookies or a portable CSRF store. Password reset/re-enablement is an account decision, not a routine restore shortcut. Do not reset every user just because old sessions ended.

Production recovery decision

Before replacing live state, name the failed layer: reader output, source, engine, runtime accounts or host. Restore the smallest coherent state, preserve failure evidence and stop conflicting writers. Rolling back only account bytes while newer sessions or writes run can restore stale permissions or credentials. Review compatibility of the selected engine and data.

Symptom Do not do this
Missing reader Delete protected runtime to force rebuild
Bad account JSON Replace it with empty users and lose records
Missing history Repeat completed actions to create new records
Wrong branding Copy all old engine, static files over new code
Old index Treat browser refresh as deployment verification

Confirm the actual live route/artifact after recovery. Document data lost, retained history and any changed expectations. The handbook’s tested archive rehearsal used synthetic starter content/config and compared rebuilt output. It did not restore production accounts, private service state, ownership or TLS/DNS. Validation limits keeps that distinction explicit.