Skip to content

Move your books between servers: restore a full export into empty books - #185

Merged
chandralegend merged 3 commits into
mainfrom
feat/export-restore
Oct 26, 2026
Merged

chandralegend merged 3 commits into
mainfrom
feat/export-restore

Conversation

@chandralegend

Copy link
Copy Markdown
Contributor

A person can now move their books from one Salli server to another (the hosted server to their own, or between self-hosted ones).

  • Export: gains export_version (2) and rows, the person's stored rows table by table (adapters/db/portable.py, tables in domain/export/restore.TABLES). GET /v1/onboarding/export/archive (salli profile export --archive) zips it with the uploaded files.
  • Restore: POST /v1/onboarding/restore (salli restore <file>), JSON or archive. First-party sign-ins only (no PAT, no AI connector), the step-up and two-step code. Refused unless the books are empty: no entries, no lock date, and no row in any other restored table except the starter chart, seeded tags, digest preferences and onboarding memories, which are replaced.
  • Integrity: the version is checked, then the exported hash chain (the first break refuses it). Everything is written in one transaction under the person's RLS (no SYSTEM path added, no trigger relaxed: the lock date is set last). Rows are moved to the person: their id, their files under their folder, entries re-chained (a return's chain_head_hash mapped), every other hash kept. Rows pointing at records the export doesn't hold, or already on the server, are refused (409).
  • Audit: the old server's audit rows are kept in the new restores table (core_0053), outside this chain, which records books.restore with the export hash and both chain heads.
  • Fix: core_0053 widens cma_packs.content_hash (64 chars could not hold sha256:…, so CMA import failed on Postgres).
  • Tests: a round trip on the golden household and Remitland's filed household (export → restore into a fresh person on a fresh database → export again): equal except person id, entry hashes, profile times and the audit trail. The ledger verifies, and the balance sheet, FI score and safe-to-spend match. Also covered: empty-books refusal, a broken chain, version 1 and newer versions, missing files, collisions and stray references, plus API and CLI tests.
  • Docs: docs/self-host.md "Moving your books", privacy, security, CLAUDE.md, CHANGELOG.

No console pages changed.

🤖 Generated with Claude Code

chandralegend and others added 3 commits October 27, 2026 01:25
A person can now move their books from one Salli server to another. The
export gains export_version (2) and rows, the person's stored rows table
by table, and an archive form (GET /v1/onboarding/export/archive, salli
profile export --archive) that zips it with the uploaded files.
POST /v1/onboarding/restore (salli restore <file>) takes either into the
person's books, first-party sign-ins only, behind the step-up and the
two-step code, and only while those books are empty: no entries, no lock
date, nothing but the starter chart, seeded tags, digest preferences and
onboarding memories, which it replaces.

The restore checks the version and the exported ledger's hash chain (the
first break refuses it), then writes everything in one transaction under
the person's row-level security: their id in place of the exported one,
their files under their folder, their entries chained again (a return's
chain_head_hash mapped), every other hash kept, the lock date last so no
trigger needs relaxing. Rows pointing at records the export doesn't hold,
or already on the server, are refused. The old server's audit rows are
kept apart in the new restores table, outside this server's chain, which
records books.restore with the export's hash and both chain heads.

core_0053 adds restores and widens cma_packs.content_hash, which at 64
characters could not hold the "sha256:" hash it is given, so no CMA pack
could be imported on Postgres. A round-trip test on the golden households
exports, restores into a fresh person on a fresh database and exports
again: equal but for the person's id, the entry hashes, profile times and
the audit trail; the ledger verifies and the balance sheet, FI score and
safe-to-spend agree. Docs: docs/self-host.md "Moving your books".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chandralegend
chandralegend merged commit c65a620 into main Oct 26, 2026
17 checks passed
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.

1 participant