Backup and restore
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
- Record engine, content, config, static, template, data and output paths and intended restore target.
- Confirm no publication is running. Saved source and generated output are different states.
- Coordinate writers and service processes for one consistent snapshot, using your installed maintenance process.
- Capture source and protected runtime together with selected engine/configuration and reviewed customization.
- Record capture time, included/excluded paths, permissions/ownership and hashes from the completed archive.
- Store a restricted copy away from the same machine/disk; encrypt and retain under your policy.
- 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.