Skip to content

Implement the backup command (full account export via the CouchDB sync DB)#8

Open
byerun wants to merge 1 commit into
amazingmarvin:masterfrom
byerun:feat/backup-command
Open

Implement the backup command (full account export via the CouchDB sync DB)#8
byerun wants to merge 1 commit into
amazingmarvin:masterfrom
byerun:feat/backup-command

Conversation

@byerun

@byerun byerun commented Jun 27, 2026

Copy link
Copy Markdown

Implements the previously-stubbed backup command.

Approach. The public API has no bulk-export endpoint, so this reads every document directly from the CouchDB/Cloudant sync database (_all_docs?include_docs=true&conflicts=true, paginated). New syncServer/syncDatabase/syncUser/syncPassword config keys (and --sync-* flags) supply the credentials from the API strategy page.

Output. A JSON array of records → MarvinBackup-<YYYYMMDD>.json by default (-o <file>, or -o - for stdout). It matches Marvin's GUI backup format: _rev is stripped except on conflicted records (kept as Marvin's marker), and a conflict warning is printed. Equivalent to a GUI backup with "Device Local Settings/Data" unchecked — everything in the sync DB, minus non-synced device-local data (LocalStorageItems).

Notes for reviewers:

  • backup is intentionally not desktop-gated (it talks to CouchDB directly), so it moved from DESKTOP COMMANDS to general COMMANDS.
  • It's a full DB dump by design — more complete than the GUI backup (which prunes older completed tasks). Deliberate, not a bug.
  • FYI, while comparing outputs I found the GUI backup double-encodes non-ASCII text (mojibake); the CLI preserves correct UTF-8. Happy to file separately.
  • New CouchDB logic is in backup_couch.ts with deno test coverage. The repo's pre-existing err.message-on-unknown type errors are untouched; new code uses a small typed helper. Glad to promote it repo-wide if wanted.
  • Unknown-flag rejection is not added — left as the existing CLI behavior.

Testing done: read-only command (cannot modify an account); unit tests; run live against a ~1,550-record account and structurally compared to a GUI backup.

⚠️ Please verify before considering this production-ready: I did not test a full backup→restore round-trip (the only restore path is the GUI and I didn't want to risk personal data). Could a maintainer confirm, against a test account, that a marvin backup file restores cleanly via the GUI (including the _rev/conflict-marker handling)? This PR implements backup only; restore remains the existing stub.

Back up the entire account by dumping the CouchDB/Cloudant sync database
directly, since the public API has no bulk-export endpoint. Output matches
Marvin's GUI backup format (a JSON array of docs, with the internal _rev
omitted except on conflicted records) and is written to
MarvinBackup-<YYYYMMDD>.json by default.

- Read all docs via _all_docs?include_docs=true&conflicts=true, paginated,
  with a per-request timeout and cross-page dedupe (live read, not a snapshot)
- Strip _rev to match the GUI format; keep it on conflicted records as Marvin's
  marker and print a conflict warning
- Add syncServer/syncDatabase/syncUser/syncPassword config keys and matching
  --sync-* flags (per-run alternative that keeps syncPassword out of config)
- Move backup out of the desktop-only set: it talks to CouchDB directly, not
  the desktop or public API
- Extract the CouchDB logic into backup_couch.ts with unit tests covering
  pagination, _design exclusion, _rev/_conflicts handling, dedupe, and grouping

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants