Ajoute la synchronisation client incrémentale LWW vers l'API serveur (application/use_cases.dart: SyncUseCases, ports.dart, migration Drift schemaVersion 10→11 pour les métadonnées de sync et mappings de ressources, infrastructure/remote/sync_api.dart) et l'écran de profil avec entrée sur l'accueil (presentation/profile_screen.dart, home_screen.dart, presentation.dart). Développés dans le même worktree partagé par DevBackend et DevFrontend ; commit combiné car test/presentation/home_screen_test.dart mélange authentiquement les deux tickets (le test de l'entrée Profil et la mise à jour du fake de bootstrap requise par le nouveau getter syncUseCases sur AppDependencies). Corrige au passage une couleur `crimson` inexistante dans le thème (remplacée par colorScheme.error) et une signature de paramètres positionnels/nommés incohérente sur un fake de test. flutter pub get OK, build_runner OK, dart format appliqué, analyze propre (mêmes infos préexistantes), 119/119 tests verts, build APK debug validé. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -48,6 +48,50 @@ class OnlineAccountSessions extends Table {
|
||||
];
|
||||
}
|
||||
|
||||
class SyncMetadataEntries extends Table {
|
||||
@override
|
||||
String get tableName => 'sync_metadata';
|
||||
|
||||
TextColumn get id => text().withDefault(const Constant('singleton'))();
|
||||
TextColumn get serverCursor => text().nullable()();
|
||||
DateTimeColumn get lastSuccessfulSyncAt => dateTime().nullable()();
|
||||
DateTimeColumn get lastAttemptAt => dateTime().nullable()();
|
||||
DateTimeColumn get lastFailureAt => dateTime().nullable()();
|
||||
TextColumn get status => text().withDefault(const Constant('idle'))();
|
||||
IntColumn get pendingPushCount => integer().nullable()();
|
||||
|
||||
@override
|
||||
Set<Column> get primaryKey => {id};
|
||||
|
||||
@override
|
||||
List<String> get customConstraints => [
|
||||
"CHECK (id = 'singleton')",
|
||||
"CHECK (status IN ('idle', 'syncing', 'success', 'failure'))",
|
||||
'CHECK (pending_push_count IS NULL OR pending_push_count >= 0)',
|
||||
];
|
||||
}
|
||||
|
||||
class RemoteResourceMappings extends Table {
|
||||
@override
|
||||
String get tableName => 'remote_resource_mappings';
|
||||
|
||||
TextColumn get id => text()();
|
||||
TextColumn get resourceType => text()();
|
||||
TextColumn get clientId => text().withLength(min: 1)();
|
||||
TextColumn get serverId => text().withLength(min: 1)();
|
||||
DateTimeColumn get serverUpdatedAt => dateTime()();
|
||||
|
||||
@override
|
||||
Set<Column> get primaryKey => {id};
|
||||
|
||||
@override
|
||||
List<String> get customConstraints => [
|
||||
"CHECK (resource_type IN ('exercise', 'program', 'workoutTemplate', "
|
||||
"'workoutHistory', 'mediaAsset'))",
|
||||
'UNIQUE (resource_type, client_id)',
|
||||
];
|
||||
}
|
||||
|
||||
class MediaAssets extends SyncableTable {
|
||||
@override
|
||||
String get tableName => 'media_assets';
|
||||
|
||||
Reference in New Issue
Block a user