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:
parent
cf6975b748
commit
9c449964fd
19 changed files with 559 additions and 29 deletions
24
apps/app_seeds/lib/services/auto_backup_store.dart
Normal file
24
apps/app_seeds/lib/services/auto_backup_store.dart
Normal 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());
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue