Add backup/restore, daily auto-backup and history CSV/JSON export (Phase E3)

- create_backup writes a zip (manifest with sha256 per file, a VACUUM INTO database snapshot, assets, archive, fonts) atomically. restore_backup validates the manifest, rejects tampered files, path traversal, symlinks and newer schemas, checks the staged DB with integrity_check, then stages a pending restore. The swap runs on the next start before the database opens, moves the current data to backups/pre-restore-<ts>/ and rolls back on any failure.
- Daily automatic backup (migration M9 auto_backup, default on) keeps the newest 14 and never blocks startup.
- Settings Data tab: back up now, restore with confirmation and restart, auto-backup toggle, last backup time.
- History exports the filtered rows as CSV (UTF-8 BOM, CRLF, formula-injection guard) or JSON (voiced.history.v1) with CA-friendly tax columns from a new list_invoice_ledger command.
- Rust round-trip, rejection, swap-rollback and retention tests; vitest for the export and backup helpers.

Adds the zip 8.6.0 and typed-path 0.12.3 crates (pure Rust); package builds must vendor them. PDF output and fingerprint goldens are unchanged. The new UI has not been run in a webview yet.
This commit is contained in:
2026-10-04 18:13:57 +05:30
parent 9fdff4f263
commit 4cf019988d
16 changed files with 2513 additions and 7 deletions
+28
View File
@@ -541,6 +541,26 @@ body {
font-size: 0.75rem;
}
/* ---------- Settings: Data tab ---------- */
.voiced-section-title {
font-size: 1.25rem;
font-weight: 400;
margin-bottom: 0.5rem;
}
.voiced-actions {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.75rem;
margin-top: 1rem;
}
.voiced-list {
margin-left: 1.25rem;
list-style: disc;
}
/* ---------- Invoice history and detail ---------- */
.voiced-num {
text-align: right;
@@ -578,6 +598,14 @@ body {
margin-bottom: 1rem;
}
.voiced-history__export {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.5rem;
margin-bottom: 1rem;
}
.voiced-history__row {
cursor: pointer;
}