feat(unionflow): ajout Spec-Kit, constitution, mission mutuelles

- Config Spec-Kit pour Spec-Driven Development
- CONSTITUTION.md + .specify/memory/constitution.md
- Commandes Cursor /speckit.*, règles projet
- Mission: associations + mutuelles d'épargne et de financement
- .gitignore: versionner config spec-kit unionflow

Made-with: Cursor
This commit is contained in:
dahoud
2026-02-27 14:41:07 +00:00
parent 144b68f8e7
commit b1957c1c81
631 changed files with 104070 additions and 0 deletions

View File

@@ -0,0 +1,122 @@
library reports_repository;
import 'package:dio/dio.dart';
import '../models/analytics_model.dart';
/// Interface du repository des rapports
abstract class ReportsRepository {
Future<List<AnalyticsModel>> getMetriques(String typeMetrique, String periode);
Future<Map<String, dynamic>> getPerformanceGlobale();
Future<List<AnalyticsModel>> getEvolutions(String typeMetrique);
Future<Map<String, dynamic>> getStatistiquesMembres();
Future<Map<String, dynamic>> getStatistiquesCotisations(int annee);
Future<Map<String, dynamic>> getStatistiquesEvenements();
}
/// Implémentation via /api/v1/analytics
class ReportsRepositoryImpl implements ReportsRepository {
final Dio _dio;
static const String _analyticsBase = '/api/v1/analytics';
static const String _membresBase = '/api/membres';
static const String _cotisationsBase = '/api/cotisations';
static const String _evenementsBase = '/api/evenements';
ReportsRepositoryImpl(this._dio);
@override
Future<List<AnalyticsModel>> getMetriques(String typeMetrique, String periode) async {
try {
final response = await _dio.get(
'$_analyticsBase/metriques/$typeMetrique',
queryParameters: {'periodeAnalyse': periode},
);
if (response.statusCode == 200) {
final data = response.data;
if (data is List) {
return data.map((e) => AnalyticsModel.fromJson(e as Map<String, dynamic>)).toList();
}
if (data is Map) {
return [AnalyticsModel.fromJson(data as Map<String, dynamic>)];
}
}
return [];
} on DioException catch (e) {
if (e.response?.statusCode == 404 || e.response?.statusCode == 400) return [];
rethrow;
}
}
@override
Future<Map<String, dynamic>> getPerformanceGlobale() async {
try {
final response = await _dio.get('$_analyticsBase/performance-globale');
if (response.statusCode == 200 && response.data is Map) {
return response.data as Map<String, dynamic>;
}
return {};
} on DioException {
return {};
}
}
@override
Future<List<AnalyticsModel>> getEvolutions(String typeMetrique) async {
try {
final response = await _dio.get(
'$_analyticsBase/evolutions',
queryParameters: {'typeMetrique': typeMetrique},
);
if (response.statusCode == 200) {
final data = response.data;
if (data is List) {
return data.map((e) => AnalyticsModel.fromJson(e as Map<String, dynamic>)).toList();
}
}
return [];
} on DioException {
return [];
}
}
@override
Future<Map<String, dynamic>> getStatistiquesMembres() async {
try {
final response = await _dio.get('$_membresBase/statistiques');
if (response.statusCode == 200 && response.data is Map) {
return response.data as Map<String, dynamic>;
}
return {};
} on DioException {
return {};
}
}
@override
Future<Map<String, dynamic>> getStatistiquesCotisations(int annee) async {
try {
final response = await _dio.get(
'$_cotisationsBase/statistiques',
queryParameters: {'annee': annee},
);
if (response.statusCode == 200 && response.data is Map) {
return response.data as Map<String, dynamic>;
}
return {};
} on DioException {
return {};
}
}
@override
Future<Map<String, dynamic>> getStatistiquesEvenements() async {
try {
final response = await _dio.get('$_evenementsBase/statistiques');
if (response.statusCode == 200 && response.data is Map) {
return response.data as Map<String, dynamic>;
}
return {};
} on DioException {
return {};
}
}
}