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:
@@ -0,0 +1,70 @@
|
||||
/// Model de données Conversation avec sérialisation JSON
|
||||
library conversation_model;
|
||||
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import '../../domain/entities/conversation.dart';
|
||||
import '../../domain/entities/message.dart';
|
||||
import 'message_model.dart';
|
||||
|
||||
part 'conversation_model.g.dart';
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class ConversationModel extends Conversation {
|
||||
@JsonKey(
|
||||
fromJson: _messageFromJson,
|
||||
toJson: _messageToJson,
|
||||
)
|
||||
@override
|
||||
final Message? lastMessage;
|
||||
|
||||
const ConversationModel({
|
||||
required super.id,
|
||||
required super.name,
|
||||
super.description,
|
||||
required super.type,
|
||||
required super.participantIds,
|
||||
super.organizationId,
|
||||
this.lastMessage,
|
||||
super.unreadCount,
|
||||
super.isMuted,
|
||||
super.isPinned,
|
||||
super.isArchived,
|
||||
required super.createdAt,
|
||||
super.updatedAt,
|
||||
super.avatarUrl,
|
||||
super.metadata,
|
||||
}) : super(lastMessage: lastMessage);
|
||||
|
||||
static Message? _messageFromJson(Map<String, dynamic>? json) =>
|
||||
json == null ? null : MessageModel.fromJson(json);
|
||||
|
||||
static Map<String, dynamic>? _messageToJson(Message? message) =>
|
||||
message == null ? null : MessageModel.fromEntity(message).toJson();
|
||||
|
||||
factory ConversationModel.fromJson(Map<String, dynamic> json) =>
|
||||
_$ConversationModelFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => _$ConversationModelToJson(this);
|
||||
|
||||
factory ConversationModel.fromEntity(Conversation conversation) {
|
||||
return ConversationModel(
|
||||
id: conversation.id,
|
||||
name: conversation.name,
|
||||
description: conversation.description,
|
||||
type: conversation.type,
|
||||
participantIds: conversation.participantIds,
|
||||
organizationId: conversation.organizationId,
|
||||
lastMessage: conversation.lastMessage,
|
||||
unreadCount: conversation.unreadCount,
|
||||
isMuted: conversation.isMuted,
|
||||
isPinned: conversation.isPinned,
|
||||
isArchived: conversation.isArchived,
|
||||
createdAt: conversation.createdAt,
|
||||
updatedAt: conversation.updatedAt,
|
||||
avatarUrl: conversation.avatarUrl,
|
||||
metadata: conversation.metadata,
|
||||
);
|
||||
}
|
||||
|
||||
Conversation toEntity() => this;
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/// Model de données Message avec sérialisation JSON
|
||||
library message_model;
|
||||
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import '../../domain/entities/message.dart';
|
||||
|
||||
part 'message_model.g.dart';
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class MessageModel extends Message {
|
||||
const MessageModel({
|
||||
required super.id,
|
||||
required super.conversationId,
|
||||
required super.senderId,
|
||||
required super.senderName,
|
||||
super.senderAvatar,
|
||||
required super.content,
|
||||
required super.type,
|
||||
required super.status,
|
||||
super.priority,
|
||||
required super.recipientIds,
|
||||
super.recipientRoles,
|
||||
super.organizationId,
|
||||
required super.createdAt,
|
||||
super.readAt,
|
||||
super.metadata,
|
||||
super.attachments,
|
||||
super.isEdited,
|
||||
super.editedAt,
|
||||
super.isDeleted,
|
||||
});
|
||||
|
||||
factory MessageModel.fromJson(Map<String, dynamic> json) =>
|
||||
_$MessageModelFromJson(json);
|
||||
|
||||
Map<String, dynamic> toJson() => _$MessageModelToJson(this);
|
||||
|
||||
factory MessageModel.fromEntity(Message message) {
|
||||
return MessageModel(
|
||||
id: message.id,
|
||||
conversationId: message.conversationId,
|
||||
senderId: message.senderId,
|
||||
senderName: message.senderName,
|
||||
senderAvatar: message.senderAvatar,
|
||||
content: message.content,
|
||||
type: message.type,
|
||||
status: message.status,
|
||||
priority: message.priority,
|
||||
recipientIds: message.recipientIds,
|
||||
recipientRoles: message.recipientRoles,
|
||||
organizationId: message.organizationId,
|
||||
createdAt: message.createdAt,
|
||||
readAt: message.readAt,
|
||||
metadata: message.metadata,
|
||||
attachments: message.attachments,
|
||||
isEdited: message.isEdited,
|
||||
editedAt: message.editedAt,
|
||||
isDeleted: message.isDeleted,
|
||||
);
|
||||
}
|
||||
|
||||
Message toEntity() => Message(
|
||||
id: id,
|
||||
conversationId: conversationId,
|
||||
senderId: senderId,
|
||||
senderName: senderName,
|
||||
senderAvatar: senderAvatar,
|
||||
content: content,
|
||||
type: type,
|
||||
status: status,
|
||||
priority: priority,
|
||||
recipientIds: recipientIds,
|
||||
recipientRoles: recipientRoles,
|
||||
organizationId: organizationId,
|
||||
createdAt: createdAt,
|
||||
readAt: readAt,
|
||||
metadata: metadata,
|
||||
attachments: attachments,
|
||||
isEdited: isEdited,
|
||||
editedAt: editedAt,
|
||||
isDeleted: isDeleted,
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user