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
+4
View File
@@ -0,0 +1,4 @@
# Reminders Domain
Reminder models and cadence enums live here. Keep this layer free of platform
notification details so it stays easy to test and reuse.
@@ -0,0 +1,71 @@
// ignore_for_file: sort_constructors_first
import 'package:flutter/foundation.dart';
/// Reminder cadence supported by the local scheduling layer.
enum ReminderCadence { daily, weekly, monthly }
/// Reminder rule stored locally and optionally synced later.
@immutable
class ReminderRule {
const ReminderRule({
required this.id,
required this.title,
required this.cadence,
required this.nextAt,
this.personId,
this.enabled = true,
});
final String id;
final String? personId;
final String title;
final ReminderCadence cadence;
final DateTime nextAt;
final bool enabled;
ReminderRule copyWith({
String? id,
String? personId,
String? title,
ReminderCadence? cadence,
DateTime? nextAt,
bool? enabled,
}) {
return ReminderRule(
id: id ?? this.id,
personId: personId ?? this.personId,
title: title ?? this.title,
cadence: cadence ?? this.cadence,
nextAt: nextAt ?? this.nextAt,
enabled: enabled ?? this.enabled,
);
}
Map<String, dynamic> toJson() {
return <String, dynamic>{
'id': id,
'personId': personId,
'title': title,
'cadence': cadence.name,
'nextAt': nextAt.toUtc().toIso8601String(),
'enabled': enabled,
};
}
factory ReminderRule.fromJson(Map<String, dynamic> json) {
final String cadenceName =
json['cadence'] as String? ?? ReminderCadence.weekly.name;
return ReminderRule(
id: json['id'] as String,
personId: json['personId'] as String?,
title: json['title'] as String,
cadence: ReminderCadence.values.firstWhere(
(ReminderCadence cadence) => cadence.name == cadenceName,
orElse: () => ReminderCadence.weekly,
),
nextAt: DateTime.parse(json['nextAt'] as String).toLocal(),
enabled: json['enabled'] as bool? ?? true,
);
}
}