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

@ -0,0 +1,71 @@
import '../../application/application.dart';
import 'http_api_client.dart';
final class HttpRemoteAuthApi implements RemoteAuthApi {
const HttpRemoteAuthApi(this.client);
final HttpApiClient client;
@override
Future<RemoteAuthResult> register({
required String email,
required String password,
String? displayName,
}) async {
final registered = await client.postJson(
'/auth/register',
body: {
'email': email,
'password': password,
if (displayName != null) 'displayName': displayName,
},
expectedStatuses: const {201},
);
final userId = _requiredString(registered, 'userId');
final registeredEmail = _requiredString(registered, 'email');
final loggedIn = await login(email: email, password: password);
return RemoteAuthResult(
userId: userId,
email: registeredEmail,
token: loggedIn.token,
expiresAt: loggedIn.expiresAt,
);
}
@override
Future<RemoteAuthResult> login({
required String email,
required String password,
}) async {
final response = await client.postJson(
'/auth/login',
body: {'email': email, 'password': password},
);
return RemoteAuthResult(
userId: response['userId'] is String
? response['userId'] as String
: email.trim().toLowerCase(),
email: response['email'] is String
? response['email'] as String
: email.trim().toLowerCase(),
token: _requiredString(response, 'token'),
expiresAt: DateTime.parse(_requiredString(response, 'expiresAt')).toUtc(),
);
}
@override
Future<void> logout(String token) {
return client.postEmpty('/auth/logout', bearerToken: token);
}
String _requiredString(Map<String, Object?> json, String key) {
final value = json[key];
if (value is String && value.trim().isNotEmpty) {
return value;
}
throw RemoteAuthException(
RemoteAuthFailure.unknown,
'$key is missing from auth response.',
);
}
}