feat: WebSocket temps réel + Finance Workflow + corrections

- Task #6: WebSocket /ws/dashboard + Kafka events (5 topics)
  * Backend: KafkaEventProducer, KafkaEventConsumer
  * Mobile: WebSocketService (reconnection, heartbeat, typed events)
  * DashboardBloc: Auto-refresh depuis WebSocket events

- Finance Workflow: approbations + budgets (backend + mobile)
  * Backend: entities, services, resources, migrations Flyway V6
  * Mobile: features finance_workflow complète avec BLoC

- Corrections DI: interfaces IRepository partout
  * IProfileRepository, IOrganizationRepository, IMembreRepository
  * GetIt configuré avec @injectable

- Spec-Kit: constitution + templates mis à jour
  * .specify/memory/constitution.md enrichie
  * Templates agent, plan, spec, tasks, checklist

- Nettoyage: fichiers temporaires supprimés

Signed-off-by: lions dev Team
This commit is contained in:
dahoud
2026-03-15 02:12:17 +00:00
parent bbc409de9d
commit e8ad874015
635 changed files with 58160 additions and 20674 deletions

View File

@@ -1,6 +1,10 @@
import 'package:flutter/material.dart';
import '../../../../../shared/design_system/dashboard_theme_manager.dart';
import '../../../../../shared/design_system/dashboard_theme.dart';
import '../../../../../shared/design_system/tokens/app_colors.dart';
import '../../../../../shared/design_system/tokens/app_typography.dart';
import '../../../../../shared/design_system/tokens/spacing_tokens.dart';
import '../../../../../shared/design_system/tokens/radius_tokens.dart';
import '../../../../../shared/widgets/core_card.dart';
/// Widget de sélection de thème pour le Dashboard
class ThemeSelectorWidget extends StatefulWidget {
@@ -27,13 +31,8 @@ class _ThemeSelectorWidgetState extends State<ThemeSelectorWidget> {
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(DashboardTheme.spacing16),
decoration: BoxDecoration(
color: DashboardTheme.white,
borderRadius: BorderRadius.circular(DashboardTheme.borderRadius),
boxShadow: DashboardTheme.subtleShadow,
),
return CoreCard(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@@ -41,17 +40,17 @@ class _ThemeSelectorWidgetState extends State<ThemeSelectorWidget> {
children: [
Icon(
Icons.palette,
color: DashboardTheme.royalBlue,
color: AppColors.primaryGreen,
size: 24,
),
SizedBox(width: DashboardTheme.spacing8),
SizedBox(width: 8),
Text(
'Thème de l\'interface',
style: DashboardTheme.titleMedium,
style: AppTypography.headerSmall,
),
],
),
const SizedBox(height: DashboardTheme.spacing16),
const SizedBox(height: SpacingTokens.xl),
// Grille des thèmes
GridView.builder(
@@ -59,8 +58,8 @@ class _ThemeSelectorWidgetState extends State<ThemeSelectorWidget> {
physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: DashboardTheme.spacing12,
mainAxisSpacing: DashboardTheme.spacing12,
crossAxisSpacing: 12,
mainAxisSpacing: 12,
childAspectRatio: 1.5,
),
itemCount: DashboardThemeManager.availableThemes.length,
@@ -72,7 +71,7 @@ class _ThemeSelectorWidgetState extends State<ThemeSelectorWidget> {
},
),
const SizedBox(height: DashboardTheme.spacing16),
const SizedBox(height: SpacingTokens.xl),
// Aperçu du thème sélectionné
_buildThemePreview(),
@@ -87,11 +86,11 @@ class _ThemeSelectorWidgetState extends State<ThemeSelectorWidget> {
child: AnimatedContainer(
duration: const Duration(milliseconds: 200),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(DashboardTheme.borderRadius),
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: isSelected
? themeOption.theme.primaryColor
: DashboardTheme.grey300,
: const Color(0xFFD1D5DB),
width: isSelected ? 2 : 1,
),
boxShadow: isSelected
@@ -102,7 +101,7 @@ class _ThemeSelectorWidgetState extends State<ThemeSelectorWidget> {
offset: const Offset(0, 2),
),
]
: DashboardTheme.subtleShadow,
: null,
),
child: Column(
children: [
@@ -121,8 +120,8 @@ class _ThemeSelectorWidgetState extends State<ThemeSelectorWidget> {
end: Alignment.bottomRight,
),
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(DashboardTheme.borderRadius - 1),
topRight: Radius.circular(DashboardTheme.borderRadius - 1),
topLeft: Radius.circular(RadiusTokens.lg - 1),
topRight: Radius.circular(RadiusTokens.lg - 1),
),
),
child: isSelected
@@ -140,12 +139,12 @@ class _ThemeSelectorWidgetState extends State<ThemeSelectorWidget> {
flex: 1,
child: Container(
width: double.infinity,
padding: const EdgeInsets.all(DashboardTheme.spacing8),
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: themeOption.theme.cardColor,
borderRadius: const BorderRadius.only(
bottomLeft: Radius.circular(DashboardTheme.borderRadius - 1),
bottomRight: Radius.circular(DashboardTheme.borderRadius - 1),
bottomLeft: Radius.circular(7),
bottomRight: Radius.circular(7),
),
),
child: Center(
@@ -172,11 +171,11 @@ class _ThemeSelectorWidgetState extends State<ThemeSelectorWidget> {
.firstWhere((theme) => theme.key == _selectedTheme);
return Container(
padding: const EdgeInsets.all(DashboardTheme.spacing16),
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: currentTheme.theme.backgroundColor,
borderRadius: BorderRadius.circular(DashboardTheme.borderRadius),
border: Border.all(color: DashboardTheme.grey300),
borderRadius: BorderRadius.circular(8),
border: Border.all(color: const Color(0xFFD1D5DB)),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -189,15 +188,15 @@ class _ThemeSelectorWidgetState extends State<ThemeSelectorWidget> {
color: currentTheme.theme.textPrimary,
),
),
const SizedBox(height: DashboardTheme.spacing12),
const SizedBox(height: SpacingTokens.lg),
// Exemple de carte avec le thème
// Aperçu de carte avec le thème
Container(
width: double.infinity,
padding: const EdgeInsets.all(DashboardTheme.spacing12),
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: currentTheme.theme.cardColor,
borderRadius: BorderRadius.circular(DashboardTheme.borderRadiusSmall),
borderRadius: BorderRadius.circular(4),
boxShadow: [
BoxShadow(
color: currentTheme.theme.primaryColor.withOpacity(0.1),
@@ -221,7 +220,7 @@ class _ThemeSelectorWidgetState extends State<ThemeSelectorWidget> {
size: 20,
),
),
const SizedBox(width: DashboardTheme.spacing12),
const SizedBox(width: SpacingTokens.lg),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -236,7 +235,7 @@ class _ThemeSelectorWidgetState extends State<ThemeSelectorWidget> {
),
const SizedBox(height: 2),
Text(
'Exemple avec ce thème',
'Aperçu',
style: TextStyle(
fontSize: 12,
color: currentTheme.theme.textSecondary,
@@ -247,12 +246,12 @@ class _ThemeSelectorWidgetState extends State<ThemeSelectorWidget> {
),
Container(
padding: const EdgeInsets.symmetric(
horizontal: DashboardTheme.spacing8,
vertical: DashboardTheme.spacing4,
horizontal: 8,
vertical: 4,
),
decoration: BoxDecoration(
color: currentTheme.theme.success.withOpacity(0.1),
borderRadius: BorderRadius.circular(DashboardTheme.borderRadiusSmall),
borderRadius: BorderRadius.circular(4),
),
child: Text(
'Actif',
@@ -267,17 +266,17 @@ class _ThemeSelectorWidgetState extends State<ThemeSelectorWidget> {
),
),
const SizedBox(height: DashboardTheme.spacing12),
const SizedBox(height: SpacingTokens.lg),
// Palette de couleurs
Row(
children: [
_buildColorSwatch('Primaire', currentTheme.theme.primaryColor),
const SizedBox(width: DashboardTheme.spacing8),
const SizedBox(width: 8),
_buildColorSwatch('Secondaire', currentTheme.theme.secondaryColor),
const SizedBox(width: DashboardTheme.spacing8),
const SizedBox(width: 8),
_buildColorSwatch('Succès', currentTheme.theme.success),
const SizedBox(width: DashboardTheme.spacing8),
const SizedBox(width: 8),
_buildColorSwatch('Attention', currentTheme.theme.warning),
],
),
@@ -295,7 +294,7 @@ class _ThemeSelectorWidgetState extends State<ThemeSelectorWidget> {
height: 30,
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.circular(DashboardTheme.borderRadiusSmall),
borderRadius: BorderRadius.circular(4),
),
),
const SizedBox(height: 4),
@@ -303,7 +302,7 @@ class _ThemeSelectorWidgetState extends State<ThemeSelectorWidget> {
label,
style: const TextStyle(
fontSize: 10,
color: DashboardTheme.grey600,
color: Color(0xFF4B5563),
),
textAlign: TextAlign.center,
),