feat(backup): add automatic weekly encrypted backups

A silent safety net against in-app data loss or DB corruption, with zero
friction. Driven off the app lifecycle (startup + when hidden), it writes a
sealed .tanemaki copy into the app's private storage once a week, keeping the
newest 3 (rotating). Reuses the manual backup's encryption via the extracted
ExportImportService.buildSealedBackup(); never throws, so a failed copy can't
crash startup or backgrounding. Not registered on web (no file storage).

Settings shows a quiet reassurance line with the date of the last automatic
copy (localised via intl), hidden where no automatic backup exists.
This commit is contained in:
vjrj 2026-07-10 10:17:36 +02:00
parent cf6975b748
commit 9c449964fd
19 changed files with 559 additions and 29 deletions

View file

@ -0,0 +1,24 @@
import '../security/secret_store.dart';
/// Remembers when the last automatic backup ran, so the app only makes a fresh
/// copy once the interval has elapsed. Backed by the OS keystore (via
/// [SecretStore]) to honour the "no plaintext at rest" rule mirrors
/// [OnboardingStore]; there is no shared_preferences here.
class AutoBackupStore {
AutoBackupStore(this._store);
final SecretStore _store;
static const _lastKey = 'tane.auto_backup.last';
/// When the last automatic backup succeeded, or null if none has run yet.
Future<DateTime?> lastBackupAt() async {
final raw = await _store.read(_lastKey);
if (raw == null) return null;
return DateTime.tryParse(raw);
}
/// Records that an automatic backup succeeded at [when].
Future<void> markBackupAt(DateTime when) =>
_store.write(_lastKey, when.toIso8601String());
}