feat(backup): daily server and user backups, restore by section (backend)
Admins switch automatic backups on, pick the time and the retention (default 03:00, 3 days). Each run writes a gzip snapshot of the whole database (VACUUM INTO, consistent while others write) and one MindSift backup ZIP per active user below $DATA_DIR/backups, then deletes files past the retention. A restart after the time catches up on that day. Admins list, download and trigger runs; users list, download and restore their own backups. Import and restore can be limited to sections (notes, tasks, lists, inbox, themes): restore only empties the chosen sections. Export and import now carry custom themes. File names are checked against a fixed pattern, so no other file can be fetched through the API. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
cab5a79f6d
commit
c97765e08e
9 files changed
+632
-68
No files matched your search
@@ -2,6 +2,7 @@ package storage
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/sandrodach/mindsift/internal/domain"
|
||||
@@ -75,6 +76,7 @@ func (s *Store) ExportUserData(userID string) (*domain.FullExport, error) {
|
||||
docs, _ := s.GetDocuments(userID)
|
||||
lists, _ := s.GetAllListsForUser(userID)
|
||||
taskLists, _ := s.GetTaskLists(userID)
|
||||
themes, _ := s.GetUserThemes(userID)
|
||||
|
||||
return &domain.FullExport{
|
||||
ExportedAt: domain.NowISO(),
|
||||
@@ -84,6 +86,7 @@ func (s *Store) ExportUserData(userID string) (*domain.FullExport, error) {
|
||||
Documents: docs,
|
||||
Lists: lists,
|
||||
TaskLists: taskLists,
|
||||
Themes: themes,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -111,11 +114,13 @@ func (s *Store) SeedSMTPDefaultsFromEnv(host, port, user, pass, from string, tls
|
||||
|
||||
func (s *Store) GetSystemSettings() (*domain.SystemSettings, error) {
|
||||
settings := &domain.SystemSettings{
|
||||
SharingMode: SharingOrganizations,
|
||||
AllowRegistration: false,
|
||||
InstanceName: "MindSift",
|
||||
SMTPPort: "587",
|
||||
SMTPTLS: true,
|
||||
SharingMode: SharingOrganizations,
|
||||
AllowRegistration: false,
|
||||
InstanceName: "MindSift",
|
||||
SMTPPort: "587",
|
||||
SMTPTLS: true,
|
||||
BackupTime: DefaultBackupTime,
|
||||
BackupRetentionDays: DefaultBackupRetentionDays,
|
||||
}
|
||||
|
||||
rows, err := s.db.Query(`SELECT key, value FROM system_settings`)
|
||||
@@ -152,6 +157,16 @@ func (s *Store) GetSystemSettings() (*domain.SystemSettings, error) {
|
||||
settings.SMTPSkipVerify = v == "true"
|
||||
case "allow_private_webhooks":
|
||||
settings.AllowPrivateWebhooks = v == "true"
|
||||
case "backup_enabled":
|
||||
settings.BackupEnabled = v == "true"
|
||||
case "backup_time":
|
||||
if validBackupTime(v) {
|
||||
settings.BackupTime = v
|
||||
}
|
||||
case "backup_retention_days":
|
||||
if n, err := strconv.Atoi(v); err == nil && n > 0 {
|
||||
settings.BackupRetentionDays = n
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -182,6 +197,12 @@ func (s *Store) UpdateSystemSettings(settings *domain.SystemSettings) error {
|
||||
if settings.InstanceName == "" {
|
||||
settings.InstanceName = "MindSift"
|
||||
}
|
||||
if !validBackupTime(settings.BackupTime) {
|
||||
settings.BackupTime = DefaultBackupTime
|
||||
}
|
||||
if settings.BackupRetentionDays < 1 || settings.BackupRetentionDays > 365 {
|
||||
settings.BackupRetentionDays = DefaultBackupRetentionDays
|
||||
}
|
||||
_, err := s.db.Exec(`INSERT INTO system_settings (key, value) VALUES
|
||||
('sharing_mode', ?),
|
||||
('allow_registration', ?),
|
||||
@@ -193,7 +214,10 @@ func (s *Store) UpdateSystemSettings(settings *domain.SystemSettings) error {
|
||||
('smtp_from', ?),
|
||||
('smtp_tls', ?),
|
||||
('smtp_skip_verify', ?),
|
||||
('allow_private_webhooks', ?)
|
||||
('allow_private_webhooks', ?),
|
||||
('backup_enabled', ?),
|
||||
('backup_time', ?),
|
||||
('backup_retention_days', ?)
|
||||
ON CONFLICT(key) DO UPDATE SET value = excluded.value`,
|
||||
settings.SharingMode,
|
||||
regStr,
|
||||
@@ -206,6 +230,9 @@ func (s *Store) UpdateSystemSettings(settings *domain.SystemSettings) error {
|
||||
tlsStr,
|
||||
skipVerifyStr,
|
||||
privateHooksStr,
|
||||
strconv.FormatBool(settings.BackupEnabled),
|
||||
settings.BackupTime,
|
||||
strconv.Itoa(settings.BackupRetentionDays),
|
||||
)
|
||||
return err
|
||||
}
|
||||
Reference in new issue
Block a user