feat: add local-first private AI digest workflow

Migrate app code into canonical feature slices, add phone-only AI digest scheduling and review, wire local notification/background task support, and cover the flow with tests.
This commit is contained in:
Rijad Zuzo
2026-05-17 00:17:20 +02:00
parent dab50abf0e
commit f655adfbea
212 changed files with 24178 additions and 15895 deletions
+8
View File
@@ -0,0 +1,8 @@
# Legacy Local Layer
This folder is now a compatibility layer.
The old horizontal `local` module was the main architectural weak spot. Its
root files now re-export canonical code from `lib/app/` and feature-owned
`domain/` files so older imports keep working while the real implementation
lives in clearer locations.
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+4
View File
@@ -0,0 +1,4 @@
# Legacy Local Storage Exports
These files exist as compatibility exports while the canonical storage layer has
moved to `lib/app/data/storage/`. Prefer editing the app-layer storage files.
@@ -1,19 +1,2 @@
/// Raw local state payload and associated schema version.
class LocalDataRecord {
const LocalDataRecord({required this.rawState, required this.schemaVersion});
final String rawState;
final int schemaVersion;
}
/// Persistence boundary for local app state.
abstract interface class LocalDataStore {
/// Reads latest persisted state payload.
Future<LocalDataRecord?> read();
/// Writes state payload and schema version.
Future<void> write({required String rawState, required int schemaVersion});
/// Clears persisted state payload.
Future<void> clear();
}
// Legacy compatibility export for the app storage contract.
export 'package:relationship_saver/app/data/storage/local_data_store.dart';
@@ -1,54 +1,2 @@
import 'package:hive_flutter/hive_flutter.dart';
import 'package:relationship_saver/features/local/storage/local_data_store.dart';
/// Hive-backed local store for future DB migration path.
class HiveLocalDataStore implements LocalDataStore {
static const String _boxName = 'relationship_saver_local';
static const String _stateKey = 'state_json';
static const String _schemaVersionKey = 'schema_version';
static bool _initialized = false;
@override
Future<void> clear() async {
final Box<dynamic> box = await _openBox();
await box.delete(_stateKey);
await box.delete(_schemaVersionKey);
}
@override
Future<LocalDataRecord?> read() async {
final Box<dynamic> box = await _openBox();
final String? rawState = box.get(_stateKey) as String?;
if (rawState == null || rawState.isEmpty) {
return null;
}
final int schemaVersion =
(box.get(_schemaVersionKey) as num?)?.toInt() ?? 0;
return LocalDataRecord(rawState: rawState, schemaVersion: schemaVersion);
}
@override
Future<void> write({
required String rawState,
required int schemaVersion,
}) async {
final Box<dynamic> box = await _openBox();
await box.put(_stateKey, rawState);
await box.put(_schemaVersionKey, schemaVersion);
}
Future<Box<dynamic>> _openBox() async {
if (!_initialized) {
await Hive.initFlutter();
_initialized = true;
}
if (!Hive.isBoxOpen(_boxName)) {
return Hive.openBox<dynamic>(_boxName);
}
return Hive.box<dynamic>(_boxName);
}
}
// Legacy compatibility export for the Hive local data store.
export 'package:relationship_saver/app/data/storage/local_data_store_hive.dart';
@@ -1,22 +1,2 @@
import 'package:relationship_saver/features/local/storage/local_data_store.dart';
/// In-memory local store for deterministic tests.
class InMemoryLocalDataStore implements LocalDataStore {
LocalDataRecord? _record;
@override
Future<void> clear() async {
_record = null;
}
@override
Future<LocalDataRecord?> read() async => _record;
@override
Future<void> write({
required String rawState,
required int schemaVersion,
}) async {
_record = LocalDataRecord(rawState: rawState, schemaVersion: schemaVersion);
}
}
// Legacy compatibility export for the in-memory local data store.
export 'package:relationship_saver/app/data/storage/local_data_store_in_memory.dart';
@@ -1,14 +1,2 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:relationship_saver/core/config/app_config.dart';
import 'package:relationship_saver/features/local/storage/local_data_store.dart';
import 'package:relationship_saver/features/local/storage/local_data_store_hive.dart';
import 'package:relationship_saver/features/local/storage/local_data_store_shared_prefs.dart';
/// Chooses local persistence backend for app state.
final Provider<LocalDataStore> localDataStoreProvider =
Provider<LocalDataStore>((Ref ref) {
if (AppConfig.useHiveLocalDb) {
return HiveLocalDataStore();
}
return SharedPrefsLocalDataStore();
});
// Legacy compatibility export for the local data store provider.
export 'package:relationship_saver/app/data/storage/local_data_store_provider.dart';
@@ -1,44 +1,2 @@
import 'package:relationship_saver/features/local/storage/local_data_store.dart';
import 'package:shared_preferences/shared_preferences.dart';
/// shared_preferences-backed local store used as stable default.
class SharedPrefsLocalDataStore implements LocalDataStore {
SharedPrefsLocalDataStore({
this.stateKey = 'local_data_state_v1',
this.schemaVersionKey = 'local_data_schema_version',
});
final String stateKey;
final String schemaVersionKey;
@override
Future<void> clear() async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.remove(stateKey);
await prefs.remove(schemaVersionKey);
}
@override
Future<LocalDataRecord?> read() async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
final String? rawState = prefs.getString(stateKey);
if (rawState == null || rawState.isEmpty) {
return null;
}
return LocalDataRecord(
rawState: rawState,
schemaVersion: prefs.getInt(schemaVersionKey) ?? 0,
);
}
@override
Future<void> write({
required String rawState,
required int schemaVersion,
}) async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setString(stateKey, rawState);
await prefs.setInt(schemaVersionKey, schemaVersion);
}
}
// Legacy compatibility export for the shared preferences local store.
export 'package:relationship_saver/app/data/storage/local_data_store_shared_prefs.dart';