Skip to content
  • I switched to QuickBooks Online (QBO), from QB Desktop 2017. Now my important company accounting information is stored online.
  • Since this information is very important, it is wise to have a local backup of it, just in case.
  • ChatGPT generated this plan for developing a QBO backup.
    • was D:\FSS\KB\QBO-Backup-Plan.md → moved 2026-07-28 to Core/IT/Projects/archive/QBO-Backup-Plan-chatgpt-2026-07-28.md
  • Review the dev plan (now Core/IT/Projects/archive/QBO-Backup-Plan-chatgpt-2026-07-28.md).
  • Add your upgrades, per your Better understanding of my business and my_backup utility. → ~/utils/acct-qbo/PLAN.md
    • Can then delete the initial plan, assuming that yours includes everything useful. — coverage verified item-by-item in PLAN.md Appendix, then moved aside (not deleted) per AGENTS.md.
  • I am about to do my first Qbo transactions, with AI workflows, so this is timely. I am not sure how to rewind transactions online. And my own backups are good for peace of mind.
  • Plan thoroughly, with Opus, then hand off to Sonnet for implementation?

SSOT: D:\FSS\Software\Utils\PythonUtils\my_backup\docs\QBO-Backup-Plan.md (moved 2026-07-29 from ~/utils/acct-qbo/PLAN.md — that directory is Accounting dept’s active posting-script workspace, not my_backup’s; the plan now lives beside my_backup’s own code, per my_backup/’s existing docs/ convention). QBO code home (unchanged): ~/utils/acct-qbo/. Portal: my_backup


The plan is written and lives at ~/utils/acct-qbo/PLAN.md (Windows: \\wsl$\Ubuntu-24.04\home\ta\utils\acct-qbo\PLAN.md). It’s a dev plan for a WSL-side utility, so it belongs beside the code, not at KB root.

The one thing that changes the shape of this project

Section titled “The one thing that changes the shape of this project”

ChatGPT designed a state archive — “what did my books look like yesterday.” Your actual worry is an undo path — “what did the AI just write, and how do I reverse exactly that.” A nightly JSON dump does not answer that, for three reasons: your Kopia snapshot runs at 2 AM (an agent that goes wrong at 3 PM has no pre-write snapshot), diffing two 50 MB dumps can’t tell agent writes from your own web-UI edits, and QBO deletes need the entity’s current SyncToken, which yesterday’s archive doesn’t have.

So the plan builds two artifacts. The new one is a change journal — the posting code appends one line per write (entity, Id, SyncToken, request, response, prior state, and a run_id grouping one agent run), plus a rewind.py that replays a run_id in reverse. It’s small, and it’s the piece that’s timely this week. Phase 1, ahead of any archive work.

  • Reviewed the ChatGPT plan — its archive design is broadly sound and mostly adopted (read-everything, preserve raw fields, stable ordering, deterministic output, single uncompressed JSON, no custom viewer). Appendix in PLAN.md dispositions every item in it, one by one.
  • Added the change journal + rewind.py — the missing undo path, §2.
  • Rejected the separate qbo-archive/ repo. ChatGPT’s plan says “reuse the existing OAuth” then specs a duplicate auth.py. The archive goes in ~/utils/acct-qbo/ and imports the existing qbo_client.py. Also dropped httpx/pydantic/orjson/loguru — four new deps for a once-a-day script, and pydantic validation actively contradicts “don’t drop unknown fields.”
  • Flagged attachments as the real DR gap. ChatGPT archives Attachable metadata. Metadata is not the receipt — the scans are the one thing that exists only in QBO. Plan downloads the binaries; if the API won’t allow it, that’s a stated limitation with a manual quarter-close export fallback.
  • Deleted records — the query API returns only active objects, so a nightly full pull silently loses deletions. Captured explicitly via the CDC API.
  • Verified the API constants rather than recalling them: 1000 max per page (default 100), 500 req/min + 10 concurrent per realm, CDC 30-day lookback and it does return deletes. Three items I could not verify (the full-file attachment download field; CDC’s unsupported-entity list — Intuit’s docs don’t render to fetch; name-list delete-vs-deactivate) are marked ⚠️ UNVERIFIED with doc links, not guessed.
  • Confirmed the archive path is actually backed up — my_backup/config.yaml:86-90 snapshots all of D:/FSS to the active repo → B2 + local. ChatGPT assumed this; now it’s checked, so “Kopia retains history” is load-bearing.
  • Specced the sandbox→live cutover. qbo_client.py:10 hardcodes the sandbox base URL and load_tokens() hard-exits unless environment == "sandbox". That guard is currently the only thing between an AI workflow and your live books — it must not be defeated by editing one string in one JSON. Plan: separate token file per environment, QBO_ENVIRONMENT selecting both, and an additional explicit --production flag for any write. Reads stay unrestricted.
  • Set honest restore expectations — QBO has no bulk-restore API. You cannot push the archive back in. Real DR = rewind.py for bad runs, the archive as record-of-truth for reconstruction, QBO’s native exports as belt-and-suspenders, and a Phase 4 restore drill reconciling to Trial Balance.
  • Reused my_backup’s existing staleness alarm instead of building a new one. config.yaml:321-329 already has a health_checks → “Critical Files” group (max_days_old: 2) guarding Main.bk1, dynalist-backup.zip, twenty-postgres.sql.gz. Adding QBO-archive.json to that list is one line — and since my_backup runs at 2 AM, a different hour than the archive job, it is the independent verifier the reliability standard asks for. Only the checks it can’t see (entity-count drops, unchanged sha256) stay in the archive job.
  • Flagged the name-list rewind trap. Customer / Vendor / Item / Account likely support only deactivation, not delete — and a bill-posting run can create a Vendor as a side effect. A rewind.py that blindly deletes would fail mid-replay. Marked ⚠️ UNVERIFIED (§4.6) with a branch specced in §2.4.
  • Moved the ChatGPT plan aside (not deleted) to Core/IT/Projects/archive/QBO-Backup-Plan-chatgpt-2026-07-28.md, after verifying the appendix covers every substantive item.
  • ~/utils/acct-qbo/ is not a git repo — no .git. It holds live financial posting logic with zero history or rollback. git init should happen before Phase 1. (Its .gitignore does correctly exclude .env and .tokens.json.)
  • The [my_backup](/core/it/projects/my_backup/) portal note is stale and self-duplicated — it says Google Drive (you’re on B2), and the whole document repeats from ~line 151 with ChatGPT conversational fragments spliced in around lines 142–149. Out of scope here; worth its own small task.
  • Read PLAN.md and approve Phase 1 (change journal + rewind) — it’s the piece that should land before your first live AI posting run. *
  • Decide the Opus→Sonnet handoff you asked about. My read: yes for Phase 2–3 (mechanical entity pulls, well-specced), but Phase 1’s rewind.py touches financial writes and the sandbox/live guard — worth keeping on Opus. *
  • Approve git init in ~/utils/acct-qbo/ — financial posting code with no version history.
    • of course
  • Confirm the sandbox→live cutover design (§5) — production access is a CEO escalation under the IT charter; nothing touches live books without this.
    • We can test everything on sandbox
  • Optional: want a follow-up task to fix the duplicated/stale [my_backup](/core/it/projects/my_backup/) portal note?
    • always want a clean KB
  • I will ask Qbo Ai if there are ways to roll back to a previous state of the company data. For example, if I discover that I have entered a series of transactions incorrectly, it might be more efficient to roll back to a state several hours earlier. Will also ask what offline local backup strategies exist for those on the lowest cost easy start subscription. In other words, we might not need a restore capability in this backup. The absolute minimum needed is a local instance of the accounting data, in the worst case that QuickBooks, or much worse, it becomes corrupted. This is where a series of data snapshots, which Kopia provides, becomes invaluable.