feat(backup): download the full backup as ZIP

GET /export?format=zip streams the JSON backup compressed (plain JSON stays
the API default). The MindSift import recognises the backup ZIP next to the
plain JSON and the Markdown archive.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
sandrodachandClaude Opus 5.5 committed 2026-10-29 06:43:50 +01:00
1 parent 1601a6a2d5
commit 1df32ece92
7 files changed
+122 -25

No files matched your search

+10 -6
View File
@@ -2159,12 +2159,7 @@ func (s *Server) handleImportMindSift(w http.ResponseWriter, r *http.Request) {
writeError(w, http.StatusBadRequest, err.Error())
return
}
if strings.HasSuffix(strings.ToLower(name), ".json") || (len(data) > 0 && data[0] == '{') {
plan, err := storage.PlanMindSiftJSONImport(data)
s.runImport(w, r, plan, err)
return
}
plan, err := storage.PlanMindSiftArchiveImport(bytes.NewReader(data), int64(len(data)))
plan, err := storage.PlanMindSiftImport(data, name)
s.runImport(w, r, plan, err)
}
@@ -2197,6 +2192,15 @@ func (s *Server) handleExport(w http.ResponseWriter, r *http.Request) {
writeError(w, http.StatusInternalServerError, err.Error())
return
}
// ?format=zip: the same JSON compressed (backups grow quickly with notes); plain JSON stays the API default
if r.URL.Query().Get("format") == "zip" {
w.Header().Set("Content-Type", "application/zip")
w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="mindsift-backup-%s.zip"`, time.Now().Format("2006-01-02")))
if err := storage.WriteBackupZip(exportData, w); err != nil {
slog.Error("Backup-Export fehlgeschlagen", "user_id", userID, "error", err)
}
return
}
w.Header().Set("Content-Disposition", "attachment; filename=mindsift-export.json")
writeJSON(w, http.StatusOK, exportData)
}