feat(online): session compte, stockage sécurisé et adapter API (ticket #64)

Ajoute l'adapter API distant (infrastructure/remote/auth_api.dart,
http_api_client.dart) et le stockage sécurisé du token d'auth
(infrastructure/security/secure_storage_auth_token_store.dart), câblés
dans app_bootstrap.dart. Étend le modèle Drift (migration
schemaVersion 9→10) et la couche application (ports, use cases,
entités) pour la session de compte. flutter pub get OK (ajout http,
flutter_secure_storage), build_runner OK, dart format appliqué,
analyze propre (mêmes infos préexistantes), 109/109 tests verts,
build APK debug validé. Premier ticket du chantier "Ajouter les
features serveur au client" (#63).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-19 21:25:49 +02:00
parent a557708273
commit e60c8bbdb8
19 changed files with 1799 additions and 7 deletions

View File

@ -102,6 +102,58 @@ final class EntityMetadata {
}
}
final class UserAccountSession {
UserAccountSession({
required String id,
required String serverUserId,
required String email,
this.displayName,
required this.isLoggedIn,
required this.createdAt,
required this.updatedAt,
this.lastAuthenticatedAt,
}) : id = _nonBlank(id, 'User account session id'),
serverUserId = _nonBlank(serverUserId, 'Server user id'),
email = _nonBlank(email, 'Email') {
if (displayName != null && displayName!.trim().isEmpty) {
throw const DomainException('Display name must not be blank.');
}
}
final String id;
final String serverUserId;
final String email;
final String? displayName;
final bool isLoggedIn;
final DateTime createdAt;
final DateTime updatedAt;
final DateTime? lastAuthenticatedAt;
UserAccountSession copyWith({
String? serverUserId,
String? email,
Object? displayName = _unchanged,
bool? isLoggedIn,
DateTime? updatedAt,
Object? lastAuthenticatedAt = _unchanged,
}) {
return UserAccountSession(
id: id,
serverUserId: serverUserId ?? this.serverUserId,
email: email ?? this.email,
displayName: displayName == _unchanged
? this.displayName
: displayName as String?,
isLoggedIn: isLoggedIn ?? this.isLoggedIn,
createdAt: createdAt,
updatedAt: updatedAt ?? this.updatedAt,
lastAuthenticatedAt: lastAuthenticatedAt == _unchanged
? this.lastAuthenticatedAt
: lastAuthenticatedAt as DateTime?,
);
}
}
final class MediaAsset {
const MediaAsset({
required this.metadata,
@ -997,7 +1049,9 @@ final class ActiveExerciseStepProgressState {
currentStepSnapshotId:
currentStepSnapshotId ?? this.currentStepSnapshotId,
status: status ?? this.status,
startedAt: startedAt == _unchanged ? this.startedAt : startedAt as DateTime?,
startedAt: startedAt == _unchanged
? this.startedAt
: startedAt as DateTime?,
accumulatedMs: accumulatedMs ?? this.accumulatedMs,
lastTransitionAt: lastTransitionAt ?? this.lastTransitionAt,
);