From 1249cc49e5b7fe09bb325e7112d39f8cb1b7b5ef Mon Sep 17 00:00:00 2001 From: Till JS Date: Tue, 14 Apr 2026 15:49:47 +0200 Subject: [PATCH] feat(sync): backup as .mana zip with manifest + sha256 (M3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the raw JSONL response with a zip container: events.jsonl — one SyncChange per line, as before manifest.json — formatVersion, schemaVersion, userId, eventCount, eventsSha256, apps, timestamps, schemaVersionMin/Max Single DB pass: events.jsonl is written while a sha256 hasher tees every byte of the uncompressed JSONL. The manifest lands as a second zip entry after the stream closes, so eventsSha256 is filled without rescanning. Integrity-check on the restore side becomes trivial (re-hash the decompressed events.jsonl and compare). Signature over manifest.json is deferred to a later phase; sha256 already catches corruption. Client-side: default filename + UI label updated to .mana. Fetch flow is unchanged — browser gets a zip blob and triggers a download. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../apps/web/src/lib/api/services/backup.ts | 25 +++++++++++-------- .../(app)/settings/my-data/+page.svelte | 10 ++++---- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/apps/mana/apps/web/src/lib/api/services/backup.ts b/apps/mana/apps/web/src/lib/api/services/backup.ts index 1fcb2a16e..7e7dd1270 100644 --- a/apps/mana/apps/web/src/lib/api/services/backup.ts +++ b/apps/mana/apps/web/src/lib/api/services/backup.ts @@ -1,15 +1,20 @@ /** - * Backup / Restore API — M1 thin slice. + * Backup / Restore API. * - * Talks directly to mana-sync's /backup/export endpoint, which streams every - * sync_changes row owned by the current user as JSONL (one event per line). - * The file is immediately usable as input for a future import flow: replaying - * the events through applyServerChanges() reconstructs the user's entire - * dataset in a fresh IndexedDB. + * Talks directly to mana-sync's /backup/export endpoint, which streams a + * .mana archive (zip container) with two entries: * - * Field-level encrypted fields stay ciphertext throughout — the file is safe - * at rest for those fields. Plaintext fields (IDs, timestamps, sort keys) are - * visible as-is, which matches the GDPR data-portability expectation. + * events.jsonl — every sync_changes row, one per line, chronological + * manifest.json — formatVersion, schemaVersion, userId, eventCount, + * eventsSha256, app list, timestamps + * + * The file is immediately usable as input for the future import flow: + * replaying events through applyServerChanges() reconstructs the user's + * entire dataset in a fresh IndexedDB. + * + * Field-level encrypted fields stay ciphertext throughout — the file is + * safe at rest for those fields. Plaintext fields (IDs, timestamps, sort + * keys) are visible as-is, matching the GDPR data-portability expectation. */ import { authStore } from '$lib/stores/auth.svelte'; @@ -45,7 +50,7 @@ export const backupService = { const blob = await response.blob(); const filename = response.headers.get('Content-Disposition')?.match(/filename="(.+)"/)?.[1] || - `mana-backup-${new Date().toISOString().slice(0, 10)}.jsonl`; + `mana-backup-${new Date().toISOString().slice(0, 10)}.mana`; const url = URL.createObjectURL(blob); const a = document.createElement('a'); diff --git a/apps/mana/apps/web/src/routes/(app)/settings/my-data/+page.svelte b/apps/mana/apps/web/src/routes/(app)/settings/my-data/+page.svelte index 3e224fa30..00b5f65e5 100644 --- a/apps/mana/apps/web/src/routes/(app)/settings/my-data/+page.svelte +++ b/apps/mana/apps/web/src/routes/(app)/settings/my-data/+page.svelte @@ -391,10 +391,10 @@ Backup & Wiederherstellung

- Lade eine vollstandige Kopie deiner synchronisierten Daten als JSONL-Datei herunter. Die - Datei enthalt den kompletten Sync-Event-Stream deines Accounts — geeignet fur - Account-Migration, Backups oder DSGVO-Datenportabilitat. Sensible Felder bleiben dabei - verschlusselt. + Lade eine vollstandige Kopie deiner synchronisierten Daten als .mana-Archiv + (ZIP) herunter. Enthalt den kompletten Sync-Event-Stream plus Manifest mit + Integritats-Hash — geeignet fur Account-Migration, Backups oder DSGVO-Datenportabilitat. + Sensible Felder bleiben dabei verschlusselt.

Experimentell — Import folgt in Kurze.