mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 22:21:10 +02:00
feat(sync): backup as .mana zip with manifest + sha256 (M3)
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) <noreply@anthropic.com>
This commit is contained in:
parent
53b3746b98
commit
1249cc49e5
2 changed files with 20 additions and 15 deletions
|
|
@ -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');
|
||||
|
|
|
|||
|
|
@ -391,10 +391,10 @@
|
|||
Backup & Wiederherstellung
|
||||
</h3>
|
||||
<p class="text-sm text-muted-foreground mb-4">
|
||||
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 <code>.mana</code>-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.
|
||||
</p>
|
||||
<div class="flex items-center gap-3">
|
||||
<button
|
||||
|
|
@ -403,7 +403,7 @@
|
|||
class="flex items-center gap-2 px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 disabled:opacity-50 transition-colors"
|
||||
>
|
||||
<DownloadSimple size={16} />
|
||||
<span>{backupLoading ? 'Lade Backup…' : 'Backup herunterladen (.jsonl)'}</span>
|
||||
<span>{backupLoading ? 'Lade Backup…' : 'Backup herunterladen (.mana)'}</span>
|
||||
</button>
|
||||
<span class="text-xs text-muted-foreground">
|
||||
Experimentell — Import folgt in Kurze.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue