# Système de notification de l'application ## Vue d'ensemble Le système de notification de l'application permet d'informer les utilisateurs de diverse action. ## Architecture ### Composants principaux 1. **Service de Notification** : Gère la création, l'envoi et le suivi des notifications. 2. **Interface Utilisateur** : Affiche les notifications aux utilisateurs via des pops-ups, des bannières ou des emails. 3. **Template Email** : Modèles prédéfinis pour les notifications par email. 4. **Type D'action** : Enum d'action qui déclenche des notifications (ex: nouvel utilisateur, utilisateur actif, ...). ### Service de Notification Le service de notification est responsable de la gestion des notifications. Il inclut les fonctionnalités suivantes : - Création de notifications basées sur des événements spécifiques. - Envoi de notifications via différents canaux (email, in-app). - Suivi de l'état des notifications (envoyé, lu, etc.). ### Interface Utilisateur L'interface utilisateur affiche les notifications de manière conviviale. Les notifications peuvent apparaître sous forme de pops-ups, de bannières ou d'emails. (Possibilité d'intéragir avec les notifications) ### Template Email Les templates email sont utilisés pour formater les notifications envoyées par email. Chaque type de notification a son propre template pour assurer une communication claire et cohérente. ### Type d'action ``` enum ActionType: String { case NewUser = "NEW_USER"; case ActiveUser = "ACTIVE_USER"; case PasswordReset = "PASSWORD_RESET"; case SubscriptionExpired = "SUBSCRIPTION_EXPIRED"; case OrganizationInvited = "ORGANIZATION_INVITED"; case OrganizationInactive = "ORGANIZATION_INACTIVE"; case OrganizationDeleted = "ORGANIZATION_DELETED"; case OrginizationUserInvited = "ORGANIZATION_USER_INVITED"; case UserDeleted = "USER_DELETED"; } ``` ## Flux de travail 1. L’administrateur crée un utilisateur depuis l’interface (formulaire “Créer un utilisateur”). 2. Le contrôleur valide la requête et appelle le cas d’usage UserAdministrationService->handle(ActionType::NewUser, $admin, $payload). 3. Le service crée l’utilisateur en base avec le statut INVITED, associe l’organisation de l’admin, et génère un lien signé/jeton de setup de mot de passe (TTL). 4. Le service publie un événement de domaine UserInvitedEvent { userId, adminId, organizationId } sur Messenger (transport async). 5. Handler async A — SendUserInvitationEmailHandler: 6. Construit l’email via Symfony Mailer + Twig (emails/user_invitation.html.twig) avec le lien de définition de mot de passe. 7. Envoie le mail à l’utilisateur invité. 8. Handler async B — NotifyAdminInvitationSentHandler: 9. Crée une notification interne (Notifier, canal “in‑app”). 10. Pousse un événement temps réel via Mercure sur le topic admin/{adminId}/events avec le type INVITATION_EMAIL_SENT. 11. L’UI admin affiche un toast/bannière confirmant “Email d’invitation envoyé”. 12. L’utilisateur ouvre l’email et clique le lien de définition de mot de passe. 13. Le PasswordSetupController vérifie la signature/le jeton et la validité (TTL), affiche le formulaire, puis enregistre le nouveau mot de passe. 14. À la réussite, l’utilisateur passe au statut ACTIVE et l’action publie UserActivatedEvent { userId, adminId, organizationId } sur Messenger (async). 15. Handler async C — NotifyAdminUserActivatedHandler: 16. Crée une notification interne (Notifier, canal “in‑app”) “Compte activé”. 17. Pousse un événement Mercure sur admin/{adminId}/events avec le type USER_ACTIVATED. 18. L’UI admin met à jour la liste des membres (badge “Actif”) et affiche un toast confirmant l’activation. 19. Journalisation/Audit: 20. Chaque handler écrit une trace (succès/échec) en base ou dans un EmailLog/NotificationLog. 21. En cas d’échec d’envoi, Messenger applique la stratégie de retry puis bascule en file failed si nécessaire (tableau de bord de supervision). 22. Cas “utilisateur existant ajouté à une autre organisation”: 23. Si l’email existe déjà, on rattache l’utilisateur à la nouvelle organisation et on publie OrganizationUserInvitedEvent. 24. Handler dédié envoie un email d’information (“Vous avez été ajouté à une nouvelle organisation”) et notifie l’admin via Notifier + Mercure. 25. Cas d’actions dérivées par enum: 26. ActionType::NewUser → déclenche UserInvitedEvent (steps 3–6). 27. ActionType::ActiveUser (si activé par un flux admin) → déclenche directement UserActivatedEvent (steps 9–10). 28. ActionType::OrganizationUserInvited → flux similaire au point 12 pour la multi‑organisation. 29. Autres actions (PasswordReset, UserDeleted, etc.) suivent le même patron: contrôleur → service (match enum) → événement Messenger → handlers (Mailer/Notifier/Mercure) → UI temps réel. ## Stack technologique - Symfony Messenger: asynchrone, retries, découplage des I/O lents. - Symfony Mailer + Twig: emails d’invitation et d’information. - Symfony Notifier (canal in‑app) + Mercure: notifications persistées + push temps réel vers l’UI admin. - Enum ActionType: routage clair dans l’application, évite la logique string‑based. ```mermaid flowchart LR %% Couche 1: Action initiale A[User action event - Admin cree un utilisateur] --> B[HTTP controller API - Symfony] B --> C[Domain service - UserAdministrationService] C -->|Inspecte enum ActionType::NewUser| C1[Create user - status INVITED - liaison organisation - genere lien jeton mot de passe TTL] C1 --> D[Dispatch UserInvitedEvent - userId adminId organizationId - vers Symfony Messenger bus] %% Couche 2: Messaging / Infra D --> E[Transport async - AMQP / Redis / Doctrine] E --> RQ[Retry queue] E --> FQ[Failed queue - dead letter] E --> W[Workers Messenger] F[Supervisor / systemd] --> W %% Monolog transversal (logs a chaque etape) A --> LOG_GLOBAL[Monolog - log event initial] B --> LOG_GLOBAL C --> LOG_GLOBAL C1 --> LOG_GLOBAL D --> LOG_GLOBAL E --> LOG_GLOBAL RQ --> LOG_GLOBAL FQ --> LOG_GLOBAL W --> LOG_GLOBAL %% Handlers pour l'invitation W --> H1[Handler A - Symfony Mailer + Twig] H1 --> H1o[Email d'invitation avec lien setup mot de passe] H1 --> LOG_GLOBAL W --> H2[Handler B - Symfony Notifier in-app] H2 --> UI1[Notification UI admin - Email d'invitation envoye] H2 --> LOG_GLOBAL W -. optionnel .-> WH1[Webhook HTTP sortant - invitation envoyee] WH1 --> LOG_GLOBAL W -. optionnel .-> SMS1[SMS gateway - SMS invitation] SMS1 --> LOG_GLOBAL W -. optionnel .-> PUSH1[Mobile push service - notification mobile] PUSH1 --> LOG_GLOBAL RQ --> METRICS[Metrics et dashboard] FQ --> METRICS LOG_GLOBAL --> METRICS %% Flux activation utilisateur subgraph Activation du compte UA[User action event - Invite clique le lien] --> PS[HTTP controller API - PasswordSetupController] PS -->|Verifie signature et TTL| PSOK[Set password - user status ACTIVE] PS --> LOG_GLOBAL PSOK --> LOG_GLOBAL PSOK --> D2[Dispatch UserActivatedEvent - userId adminId organizationId - vers Messenger bus] D2 --> E2[Transport async] E2 --> RQ2[Retry queue] E2 --> FQ2[Failed queue] E2 --> W2[Workers Messenger] F --> W2 D2 --> LOG_GLOBAL E2 --> LOG_GLOBAL RQ2 --> LOG_GLOBAL FQ2 --> LOG_GLOBAL W2 --> LOG_GLOBAL W2 --> H3[Handler C - Notifier in-app] H3 --> UI2[Notification UI admin - Compte active] H3 --> LOG_GLOBAL W2 -. optionnel .-> WH2[Webhook HTTP sortant - user active] WH2 --> LOG_GLOBAL W2 -. optionnel .-> MAIL2[Mailer ou SMS ou Push - confirmation utilisateur] MAIL2 --> LOG_GLOBAL RQ2 --> METRICS FQ2 --> METRICS end %% Cas particulier : utilisateur existant ajoute a une nouvelle organisation C -->|Email deja existant| SP1[Rattache a nouvelle organisation] SP1 --> LOG_GLOBAL SP1 --> D3[Dispatch OrganizationUserInvitedEvent] D3 --> E3[Transport async] --> W3[Workers] F --> W3 D3 --> LOG_GLOBAL E3 --> LOG_GLOBAL W3 --> LOG_GLOBAL W3 --> M3[Mailer - ajoute a une nouvelle organisation] M3 --> LOG_GLOBAL W3 --> N3[Notifier in-app - toast admin Utilisateur ajoute] N3 --> LOG_GLOBAL W3 -. optionnel .-> WH3[Webhook ou SMS ou Mobile] WH3 --> LOG_GLOBAL M3 --> METRICS N3 --> METRICS WH3 --> METRICS %% Styles classDef infra fill:#e8f0fe,stroke:#5b8def,stroke-width:1px; classDef handler fill:#dcf7e9,stroke:#2ea66a,stroke-width:1px; classDef ui fill:#f0d9ff,stroke:#9c27b0,stroke-width:1px; classDef audit fill:#eeeeee,stroke:#9e9e9e,stroke-width:1px; class E,E2,E3,RQ,FQ,RQ2,FQ2,METRICS infra; class W,W2,W3,H1,H2,H3,M3,N3 handler; class H1o,UI1,UI2 ui; class LOG_GLOBAL audit; ```