Support temps réel
Vue d’ensemble
Le support temps réel d’UnikSim repose sur Socket.IO, le backend NestJS et un modèle événementiel basé sur EventEmitter. HTTP reste la source de persistance et les sockets servent à diffuser les changements aux utilisateurs et aux administrateurs.
1. Architecture temps réel
flowchart LR
U[Utilisateur] --> FE[Frontend Angular / App]
A[Administrateur] --> ADM[Interface admin]
FE <--> WS[SupportGateway - Socket.IO]
ADM <--> WS
FE --> HTTP[API HTTP NestJS]
ADM --> HTTP
HTTP --> SS[SupportService]
SS --> DB[(MySQL)]
SS --> EVT[EventEmitter]
EVT --> WS
WS --> PRES[PresenceService]
WS --> ROOMS[Rooms Socket.IO]
ROOMS --> UC[user_userId]
ROOMS --> AC[admins]
ROOMS --> CC[conversation_conversationId]
À la connexion, le gateway authentifie le JWT, attache l’utilisateur au socket et enregistre son état de présence. Les conversations utilisent des rooms dédiées, tandis que les événements destinés au compte ou aux administrateurs sont envoyés dans leurs rooms respectives.
2. Envoi d’un message utilisateur
sequenceDiagram
actor U as Utilisateur
participant FE as Frontend
participant API as SupportService
participant DB as MySQL
participant EVT as EventEmitter
participant WS as SupportGateway
U->>FE: Envoie un message
FE->>API: POST message
API->>API: Valide conversation et piece jointe
API->>DB: Sauvegarde message USER
DB-->>API: Message cree
API->>EVT: MESSAGE_CREATED
EVT->>WS: evenement
WS-->>FE: message.created
Le message est d’abord persisté, puis diffusé. Le socket ne remplace donc pas la persistance HTTP : il propage simplement le nouvel état.
3. Réponse IA dans une conversation non escaladée
sequenceDiagram
actor U as Utilisateur
participant SS as SupportService
participant AI as AIService
participant DB as MySQL
participant EVT as EventEmitter
participant WS as SupportGateway
U->>SS: Message utilisateur
SS->>SS: Charge historique + langue + retrievalContexts
SS->>AI: queryRAG(...)
AI-->>SS: answer / insufficient_context
alt answer
SS->>DB: Sauvegarde message AI
SS->>EVT: MESSAGE_CREATED
EVT->>WS: evenement
WS-->>U: message.created
else insufficient_context
SS->>DB: Sauvegarde suggestion d'escalade
SS->>EVT: MESSAGE_CREATED
EVT->>WS: evenement
WS-->>U: Proposition de support humain
end
4. Escalade vers un administrateur
sequenceDiagram
actor U as Utilisateur
participant SS as SupportService
participant DB as MySQL
participant AI as AIService
participant EVT as EventEmitter
participant WS as SupportGateway
actor A as Administrateur
U->>SS: Demande escalade
SS->>DB: Transaction atomique conversation.escalated false -> true
SS->>DB: Cree ticket OPEN
SS->>DB: Sauvegarde message SYSTEM
SS->>EVT: MESSAGE_CREATED + TICKET_UPDATED
EVT->>WS: evenements
WS-->>U: mise a jour conversation
WS-->>A: ticket.updated
SS->>AI: Resume asynchrone de la conversation
AI-->>SS: Resume admin
A->>SS: Assign / repond au ticket
SS->>DB: Sauvegarde ADMIN message + read marker
SS->>EVT: MESSAGE_CREATED + TICKET_UPDATED
EVT->>WS: evenements
WS-->>U: message.created
WS-->>A: ticket.updated
La création du ticket est protégée par une transaction atomique afin d’éviter plusieurs tickets pour la même conversation. Le premier administrateur qui répond peut automatiquement devenir l’assigné du ticket.
5. Cycle de vie d’un ticket
stateDiagram-v2
[*] --> OPEN: escalade
OPEN --> IN_PROGRESS: assignTicket / premiere reponse admin
IN_PROGRESS --> RESOLVED: resolveTicket
OPEN --> RESOLVED: resolveTicket
RESOLVED --> IN_PROGRESS: reopenTicket si assigne
RESOLVED --> OPEN: reopenTicket sans assigne
Présence, typing et reconnexion
Le frontend maintient aussi plusieurs signaux temps réel :
- typing : diffusé uniquement aux autres sockets de la conversation active.
- online / away : dérivé de l’activité navigateur, du focus et d’un timer d’inactivité.
- telemetry : navigateur, plateforme, résolution, langue, seulement si le consentement est accordé.
- game presence : jeu actif, productCode et heure de démarrage.
- reconnect : le client renvoie présence, télémétrie, conversation active et présence de jeu.
Read markers et unread counts
Les marqueurs de lecture utilisateur et administrateur sont séparés. L’utilisateur compte comme non lus les messages ADMIN postérieurs à son marqueur, alors que l’administrateur compte les messages USER postérieurs à son propre marqueur.
lastUserReadAt/lastUserReadMessageIdlastAdminReadAt/lastAdminReadMessageId
Fichiers principaux
uniksim-back-end/src/gateway/support.gateway.tsuniksim-back-end/src/service/support.service.tsuniksimFrontEnd/src/app/service/support/support-socket.service.ts
Points d’attention
- Ne pas utiliser Socket.IO comme source de vérité : la persistance doit précéder la diffusion.
- Vérifier l’appartenance à une conversation avant de joindre sa room.
- Les non-admins ne doivent pouvoir vérifier que la présence des administrateurs qui leur sont assignés.
- Après reconnexion, le client doit restaurer ses rooms et états actifs.
Architecture frontend du support
Le frontend ne traite pas Socket.IO comme une base de données. Les écritures importantes passent par l’API HTTP, puis les événements temps réel mettent l’interface à jour dès que le backend confirme le nouvel état.
flowchart LR
UI[Composants UI]
API[Services HTTP]
SOCK[SupportSocketService]
STATE[Observables / état local]
WS[SupportGateway]
BACK[SupportService]
UI -->|actions utilisateur| API
API --> BACK
BACK -->|EventEmitter| WS
WS -->|message.created / ticket.updated / typing / presence| SOCK
SOCK --> STATE
STATE --> UI
UI -->|typing / join / leave / status| SOCK
SOCK --> WS
SupportSocketService
uniksimFrontEnd/src/app/service/support/support-socket.service.ts centralise la connexion Socket.IO du frontend. Il expose les principaux événements sous forme de streams/observables afin que les composants n'aient pas à manipuler directement le socket.
message.created : ajoute ou rafraîchit un message dans la conversation.
ticket.updated : rafraîchit l'état du ticket et ses unread counts.
typing : affiche l'indicateur de saisie.
présence utilisateur/admin : met à jour les états online/away.
notification.created : propage une nouvelle notification et déclenche le son associé.
Reconnexion
Après une reconnexion Socket.IO, le client restaure explicitement son contexte actif :
Séparation HTTP / WebSocket
message.created
Assigner/résoudre/réouvrir un ticket
Recevoir ticket.updated
Marquer comme lu
Présence, typing et changements temps réel
Persistance et validation
Synchronisation immédiate de l'interface