Documentation MVLS - Intégration DEMA1N
Version : 1.0
Dernière mise à jour : 12/12/2025
Table des matières
- Vue d'ensemble
- Architecture
- Configuration
- Intégration RabbitMQ
- Templates Brevo
- Champs spécifiques MVLS
- Guide d'utilisation
- Exemples de code
- Dépannage
Vue d'ensemble
MVLS (Mentoré Lycéen) est une intégration spécifique de DEMA1N qui permet de gérer les jeunes lycéens et les bénévoles éclaireurs dans un contexte particulier. Cette intégration utilise :
- RabbitMQ pour la synchronisation des données entre DEMA1N et la plateforme MVLS
- Templates Brevo pour l'envoi d'emails personnalisés
- Sandbox pour isoler les données MVLS des autres utilisateurs DEMA1N
- Champs spécifiques dans
externalInfospour stocker les données MVLS
Concepts clés
- Sandbox : Les utilisateurs MVLS ont
sandbox === 'MVLS'pour les distinguer des autres utilisateurs DEMA1N - Lycéen : Jeune MVLS avec le rôle
lyceen - Éclaireur : Bénévole MVLS avec le rôle
eclaireur - Binôme MVLS : Relation entre un lycéen et un éclaireur MVLS
Architecture
Structure des modules
back/src/mvls/
├── mvls.module.ts # Module NestJS MVLS
├── mvls.service.ts # Service principal MVLS
├── mvls.controller.ts # Contrôleur MVLS
└── mvls.interfaces.ts # Interfaces TypeScript
Flux de données
┌─────────────┐
│ DEMA1N │
│ (Backend) │
└──────┬──────┘
│
│ RabbitMQ Messages
│ (USER_CREATED, USER_UPDATED, USER_DELETED, BINOME_CREATED, BINOME_UPDATED)
│
▼
┌─────────────┐
│ RabbitMQ │
│ Exchange │
│ "dema1n" │
└──────┬──────┘
│
│ Routing Key: "user___mvls"
│
▼
┌─────────────┐
│ Plateforme │
│ MVLS │
└─────────────┘
Services impliqués
- MvlsService : Gestion des messages RabbitMQ et filtrage des données
- JeuneService : Gestion des jeunes MVLS et publication des messages
- BenevolesService : Gestion des bénévoles MVLS et publication des messages
- BinomeService : Gestion des binômes MVLS et publication des messages
- MailService : Envoi d'emails via templates Brevo pour MVLS
Configuration
Variables d'environnement
# RabbitMQ
RABBIT_MQ_URL=amqp://user:password@host:5672
RABBIT_MQ_EXCHANGE_NAME=dema1n
RABBIT_MQ_EXCHANGE_TYPE=topic
# Brevo (Sendinblue)
BREVO_API_KEY=votre_clé_api_brevo
BREVO_URL=https://api.brevo.com/v3
# Producer (pour identifier les messages)
PRODUCER=dema1n
Configuration RabbitMQ
L'exchange RabbitMQ est configuré dans mvls.module.ts :
RabbitMQModule.forRootAsync({
exchanges: [
{
name: configService.get<string>('RABBIT_MQ_EXCHANGE_NAME'),
type: configService.get<string>('RABBIT_MQ_EXCHANGE_TYPE'),
options: {
durable: true
}
}
]
})
Migration base de données
Une migration a été ajoutée pour supporter les templates Brevo :
// Migration: 1765124120829-addedBrevoTemplateId.ts
ALTER TABLE `message_template` ADD `brevoTemplateId` bigint NULL;
Intégration RabbitMQ
Types de messages
MVLS utilise plusieurs types de messages RabbitMQ :
1. Messages utilisateurs
USER_CREATED: Création d'un jeune ou bénévole MVLSUSER_UPDATED: Mise à jour d'un jeune ou bénévole MVLSUSER_DELETED: Suppression d'un jeune ou bénévole MVLS
2. Messages binômes
BINOME_CREATED: Création d'un binôme MVLSBINOME_UPDATED: Mise à jour d'un binôme MVLS (changement de statut/état)
Format des messages
Structure générale
interface IMvlsRabbitMQMessage {
header: {
name: string; // "USER_CREATED", "USER_UPDATED", "USER_DELETED", "BINOME_CREATED", "BINOME_UPDATED"
model: string; // "USER" ou "BINOME"
event: string; // "CREATED", "UPDATED", "DELETED"
date: string; // Date ISO 8601
requestId: string; // Identifiant unique de la requête
uniqid: string; // Identifiant unique du message
VERSION: string; // "1.0"
producer: string; // "dema1n"
};
body: IFilterLyceenDataForMvlsResult | IFilterEclaireurDataForMvlsResult | IUserDeletedDataForMvlsResult | IBinomeDataForMvlsResult;
}
Message USER_CREATED / USER_UPDATED (Lycéen)
{
"header": {
"name": "USER_CREATED",
"model": "USER",
"event": "CREATED",
"date": "2025-12-12T10:00:00.000Z",
"requestId": "abc123",
"uniqid": "xyz789",
"VERSION": "1.0",
"producer": "dema1n"
},
"body": {
"charte": true,
"notification": true,
"newEmail": null,
"user": {
"gender": "M",
"birthdate": "2007-05-15",
"firstname": "Jean",
"lastname": "Dupont",
"phoneNumber": "+33612345678",
"roles": ["lyceen"],
"userJwt": {
"username": "jean.dupont@example.com",
"ssoId": "sso-123",
"activationToken": "token-abc"
},
"mvlsLyceens": [{
"createdAt": "2025-12-01T10:00:00.000Z",
"mentor_sexe": "M",
"etudesSup": "totaly",
"travailEfficace": "kinda",
"preparationSup": "yes",
"nomClasse": "Terminale S",
"domaines": ["Sciences", "Technologie"],
"formations": ["Bac+3", "Bac+5"],
"communication": ["email", "phone"],
"statut": "EN_ATTENTE",
"state": "ACTIF"
}],
"parcoursLyceens": [{
"createdAt": "2025-12-01T10:00:00.000Z",
"filiere": "Scientifique",
"isBoursierSecondaire": "OUI",
"etablissement": {
"departmentCode": "75",
"nom": "Lycée Victor Hugo"
}
}]
}
}
}
Champ newEmail (optionnel) :
- Type : string | null
- Emplacement : Au niveau du body (racine du body)
- Description : Nouvel email de l'utilisateur si différent de user.userJwt.username. Si présent et différent de username, l'email de l'utilisateur sera mis à jour dans DEMA1N avec le préfixe mvls_ (ex: mvls_nouvel.email@example.com).
- Exemple avec changement d'email :
{
"body": {
"charte": true,
"notification": true,
"newEmail": "nouvel.email@example.com",
"user": {
"userJwt": {
"username": "ancien.email@example.com"
}
}
}
}
Message USER_DELETED
{
"header": {
"name": "USER_DELETED",
"model": "USER",
"event": "DELETED",
"date": "2025-12-12T10:00:00.000Z",
"requestId": "abc123",
"uniqid": "xyz789",
"VERSION": "1.0",
"producer": "dema1n"
},
"body": {
"email": "jean.dupont@example.com"
}
}
Message BINOME_CREATED / BINOME_UPDATED
{
"header": {
"name": "BINOME_CREATED",
"model": "BINOME",
"event": "CREATED",
"date": "2025-12-12T10:00:00.000Z",
"requestId": "abc123",
"uniqid": "xyz789",
"VERSION": "1.0",
"producer": "dema1n"
},
"body": {
"binome_id": "123",
"jeune_id": "456",
"benevole_id": "789",
"jeune_email": "jean.dupont@example.com",
"benevole_email": "marie.martin@example.com",
"status": "EN_ATTENTE",
"state": "ACTIF",
"creationDate": "2025-12-12T10:00:00.000Z",
"buildDate": null,
"statusUpdateDate": "2025-12-12T10:00:00.000Z"
}
}
Routing Key
Tous les messages MVLS utilisent le même routing key : user___mvls
Quand les messages sont envoyés
Messages utilisateurs
- USER_CREATED : Lors de la création d'un jeune ou bénévole MVLS
- USER_UPDATED :
- Lors de la mise à jour d'un jeune MVLS via
JeuneService.updateAdmin() - Lors de la mise à jour d'un bénévole MVLS via
BenevolesService.updateAdmin() - USER_DELETED :
- Lors de la suppression d'un jeune MVLS via
JeuneService.deleteJeune() - Lors de la suppression d'un bénévole MVLS via
BenevolesService.deleteBenevole()
Messages binômes
- BINOME_CREATED : Lors de la création d'un binôme MVLS via
BinomeService.createBinome() - BINOME_UPDATED : Lors de la mise à jour d'un binôme MVLS (changement de statut ou d'état)
Messages suivis
- SUIVI_CREATED : Lors de la création d'un suivi MVLS (checkpoint) via
SuivistatusService.createSuivistatus() - SUIVI_UPDATED : Lors de la mise à jour d'un suivi MVLS via
SuivistatusService.changeSuivistatus()
Format du message SUIVI_CREATED / SUIVI_UPDATED :
{
"header": {
"name": "SUIVI_CREATED",
"model": "SUIVI",
"event": "CREATED",
"date": "2025-12-12T10:00:00.000Z",
"requestId": "abc123",
"uniqid": "xyz789",
"VERSION": "1.0",
"producer": "dema1n"
},
"body": {
"suivi": {
"suivi_id": "123",
"binome_id": "456",
"step_id": "789",
"day_step": 5,
"status": "EN_ATTENTE",
"status_jeune": "EN_ATTENTE",
"status_benevole": "EN_ATTENTE",
"creation_date": "2025-12-12T10:00:00.000Z",
"status_update_date": "2025-12-12T10:00:00.000Z"
}
}
}
Réception des messages
Le service MVLS écoute les messages entrants via RabbitMQ :
@RabbitRPC({
exchange: 'dema1n',
queue: 'Dema1n_mvls',
routingKey: 'user___mvls'
})
public async pubSubHandler(msg: IMvlsRabbitMQMessage) {
// Traitement des messages reçus
}
Gestion du champ newEmail dans USER_UPDATED et USER_CREATED
Lors de la réception d'un message USER_UPDATED ou USER_CREATED, le champ newEmail peut être présent au niveau du body pour indiquer un changement d'email :
- Si
newEmailest présent et différent deuser.userJwt.username: - L'utilisateur est recherché par son ancien email (avec préfixe
mvls_) :mvls_+user.userJwt.username - L'email de l'utilisateur est mis à jour avec le nouvel email (avec préfixe
mvls_) :mvls_+newEmail -
Les autres champs de l'utilisateur sont également mis à jour selon les données du message
-
Si
newEmailestnullou identique àusername: - Aucune mise à jour de l'email n'est effectuée
- Seuls les autres champs sont mis à jour
Exemple de traitement :
// Message reçu avec newEmail différent de username
{
"body": {
"newEmail": "nouvel.email@example.com",
"user": {
"userJwt": {
"username": "ancien.email@example.com"
}
}
}
}
// Comportement :
// 1. Recherche de l'utilisateur : findByEmailMvls('mvls_ancien.email@example.com')
// 2. Mise à jour de l'email : user.email = 'mvls_nouvel.email@example.com'
// 3. Mise à jour des autres champs (firstName, lastName, etc.)
Système de suivi MVLS avec Inspire
Vue d'ensemble
Pour les binômes MVLS, les emails de checkpoint (steps avec suiviActivated = true) contiennent des liens vers Inspire Orientation qui permettent aux jeunes et aux bénévoles de répondre directement sur la plateforme Inspire.
URLs dans les emails Brevo
Lors de l'envoi d'un email de checkpoint MVLS, les variables suivantes sont ajoutées aux templates Brevo :
{{ params.contactok }}: URL pour répondre "Tout va bien" (RAS, actif = '1'){{ params.nocontact }}: URL pour répondre "Il y a un problème" (Inactif, actif = '0')
Format des URLs : https://inspire-orientation.org/mentorat/suivi/:token/:contactStatus/:suiviId/:type
Où :
- token : Hash MD5 sécurisé généré comme suit :
- Pour contactok : md5(binomeId + '/suivi/' + suiviId + '/' + contactStatus + '/contactok')
- Pour nocontact : md5(binomeId + '/suivi/' + suiviId + '/' + contactStatus + '/nocontact')
- contactStatus : 'jeune' ou 'benevole'
- suiviId : Identifiant du suivi (Suivistatus.id)
- type : 'contactok' ou 'nocontact' selon le type de réponse
Implémentation côté Inspire
1. Réception des messages RabbitMQ SUIVI_CREATED
Lorsqu'un suivi MVLS est créé, Inspire reçoit un message SUIVI_CREATED via RabbitMQ. Ce message contient toutes les informations nécessaires pour afficher le formulaire de suivi.
Actions à effectuer côté Inspire :
- Écouter les messages
SUIVI_CREATEDdans la queue RabbitMQ avec le routing keyuser___mvls - Extraire les données du suivi depuis
msg.body.suivi - Stocker les informations nécessaires pour afficher le formulaire :
suivi_id: Identifiant unique du suivibinome_id: Identifiant du binômeday_step: Jour du checkpoint (0, 5, 20, 60, etc.)status_jeuneetstatus_benevole: Statuts initiaux (généralement'EN_ATTENTE')
2. Affichage du formulaire de suivi
Quand un utilisateur clique sur le lien dans l'email Brevo, Inspire doit :
- Extraire les paramètres de l'URL :
token: Hash de sécuritécontactStatus:'jeune'ou'benevole'-
suiviId: Identifiant du suivi -
Valider le token (optionnel côté Inspire, mais recommandé pour la sécurité) :
- Reconstruire le hash attendu :
md5(binomeId + '/suivi/' + suiviId + '/' + contactStatus) -
Comparer avec le token reçu
-
Afficher le formulaire de suivi avec les options suivantes :
- RAS (
actif = '1') : "Tout va bien" - Inactif (
actif = '0') : "Il y a un problème" - Objectif atteint (
actif = '2') : "Nous avons atteint les objectifs" - Commentaire (optionnel) : Champ texte pour ajouter un commentaire
3. Envoi de la réponse à DEMA1N via RabbitMQ
Lorsque l'utilisateur soumet le formulaire, Inspire doit envoyer un message RabbitMQ à DEMA1N :
Type de message : SUIVI_UPDATE_FROM_INSPIRE
Exchange : dema1n
Routing Key : user___mvls
Format du message :
{
"header": {
"name": "SUIVI_UPDATE_FROM_INSPIRE",
"model": "SUIVI",
"event": "UPDATED",
"date": "2025-12-12T10:00:00.000Z",
"requestId": "abc123",
"uniqid": "xyz789",
"VERSION": "1.0",
"producer": "inspire"
},
"body": {
"suivi_update": {
"suivi_id": "789",
"contact_status": "jeune",
"actif": "1",
"comment": "Tout se passe très bien !"
}
}
}
Champs du body.suivi_update :
- suivi_id (string, obligatoire) : Identifiant du suivi reçu dans l'URL
- contact_status (string, obligatoire) : 'jeune' ou 'benevole' (reçu dans l'URL originale)
- actif (string, obligatoire) : '1' pour RAS, '0' pour Inactif, '2' pour objectif atteint
- comment (string, optionnel) : Commentaire optionnel
Exemple de code pour envoyer le message :
// Exemple avec la bibliothèque RabbitMQ de votre choix
const message = {
header: {
name: 'SUIVI_UPDATE_FROM_INSPIRE',
model: 'SUIVI',
event: 'UPDATED',
date: new Date().toISOString(),
requestId: generateUniqueId(),
uniqid: generateUniqueId(),
VERSION: '1.0',
producer: 'inspire'
},
body: {
suivi_update: {
suivi_id: suiviId,
contact_status: contactStatus, // 'jeune' ou 'benevole'
actif: actif, // '1', '0', ou '2'
comment: comment || null
}
}
};
await rabbitmqChannel.publish('dema1n', 'user___mvls', message);
4. Gestion des erreurs
Si DEMA1N ne peut pas traiter le message (suivi non trouvé, binôme non MVLS, etc.), le message sera loggé mais ne retournera pas d'erreur explicite via RabbitMQ.
Actions recommandées côté Inspire : - Logger tous les messages envoyés pour le debugging - Surveiller les logs DEMA1N si nécessaire pour vérifier que les messages sont bien traités - Ne pas bloquer l'utilisateur si possible (par exemple, permettre de réessayer)
5. Réception des messages SUIVI_UPDATED
Lorsqu'un suivi est mis à jour (soit depuis Inspire, soit depuis DEMA1N), Inspire reçoit un message SUIVI_UPDATED via RabbitMQ.
Actions recommandées côté Inspire : - Mettre à jour l'affichage du suivi si nécessaire - Notifier l'utilisateur si le statut a changé - Synchroniser les données locales avec les données reçues
Exemple de flux complet
- Création du suivi :
- DEMA1N crée un suivi pour un checkpoint MVLS (jour 5 par exemple)
- DEMA1N envoie un message
SUIVI_CREATEDvia RabbitMQ -
DEMA1N envoie un email Brevo au jeune avec deux URLs :
{{ params.contactok }}:https://inspire-orientation.org/mentorat/suivi/abc123/jeune/789/contactok{{ params.nocontact }}:https://inspire-orientation.org/mentorat/suivi/def456/jeune/789/nocontact
-
Réception côté Inspire :
- Inspire reçoit le message
SUIVI_CREATEDet stocke les informations - L'utilisateur clique sur l'un des deux liens dans l'email (contactok ou nocontact)
-
Inspire affiche le formulaire de suivi avec la réponse pré-sélectionnée selon le lien cliqué
-
Soumission du formulaire :
- L'utilisateur remplit le formulaire et clique sur "Envoyer"
-
Inspire envoie un message
SUIVI_UPDATE_FROM_INSPIREvia RabbitMQ à DEMA1N -
Mise à jour côté DEMA1N :
- DEMA1N reçoit le message
SUIVI_UPDATE_FROM_INSPIREvia RabbitMQ - DEMA1N valide les données et met à jour le suivi
-
DEMA1N envoie un message
SUIVI_UPDATEDvia RabbitMQ pour notifier la mise à jour -
Confirmation côté Inspire :
- Inspire peut écouter le message
SUIVI_UPDATEDpour confirmer la mise à jour - Inspire affiche un message de confirmation à l'utilisateur
- Inspire peut mettre à jour l'affichage si nécessaire
Templates Brevo
Configuration
Les templates Brevo sont configurés dans la table message_template avec le champ brevoTemplateId :
ALTER TABLE `message_template` ADD `brevoTemplateId` bigint NULL;
Utilisation
Lors de l'envoi d'un email via MailService.send(), si le template a un brevoTemplateId, l'email est envoyé via l'API Brevo au lieu de SMTP classique :
if (template.brevoTemplateId) {
const brevoResult = await this.sendForTemplate(
cleanedMailTo,
template.brevoTemplateId,
data,
view, // Slug pour le log
template.subject // Sujet pour le log
);
}
Format des données envoyées à Brevo
{
templateId: number,
messageVersions: [
{
to: [{ email: "destinataire@example.com" }],
params: {
// Variables du template Brevo
prenom: "Jean",
nom: "Dupont",
// ... autres variables
}
}
]
}
Logs MAIL
Les emails envoyés via Brevo sont loggés dans la table log-mail avec :
- Le slug du template
- Le destinataire (sans préfixe mvls_)
- Le sujet du template
- Un HTML contenant les variables transmises et la réponse Brevo API
Préfixe mvls_
Les emails MVLS peuvent avoir un préfixe mvls_ dans DEMA1N (ex: mvls_jean.dupont@example.com). Ce préfixe est automatiquement retiré avant l'envoi à Brevo pour garantir la compatibilité.
Champs spécifiques MVLS
Structure externalInfos
Les données spécifiques MVLS sont stockées dans le champ externalInfos (JSON) des entités Jeune et Benevole.
Champs lycéen (Jeune MVLS)
{
// Scolarité
nomClasse: string | null; // Nom de la classe
domaines: string[] | null; // Domaines d'intérêt
domainesAutre: string | null; // Autre domaine (si "Autre" sélectionné)
formations: string[] | null; // Formations souhaitées
formationsAutre: string | null; // Autre formation (si "Autre" sélectionné)
alternance: boolean | null; // Intérêt pour l'alternance
// Questions scolarité
etudesSup: string | null; // "totaly" | "kinda" | "notreally" | "no"
travailEfficace: string | null; // "totaly" | "kinda" | "notreally" | "no"
preparationSup: string | null; // "yes" | "kinda" | "no"
// Mentorat
mentor_sexe: string | null; // Préférence de genre du mentor
communication: string[] | null; // Préférences de communication
// Représentant légal
legalRepresentativeEmail: string | null;
legalRepresentativePhone: string | null;
// Adresse
streetNumber: string | null;
street: string | null;
zipcode: string | null;
city: string | null;
// Autres
voeux_formation: string | null;
besoins: string[] | null;
statut: string | null;
state: string | null;
dateUpdateStatut: Date | string | null;
dateUpdateState: Date | string | null;
}
Champs éclaireur (Bénévole MVLS)
{
// Formations
formations: string[] | null;
formationsAutre: string | null;
// Domaines
domaines: string | string[] | null;
domainesAutre: string | null;
// Autres
casierJudiciaire: boolean | null;
precision: string | null;
besoins: string[] | null;
alternance: boolean | null;
annee: string | null;
sourceOfFinanceStudies: string | null;
statut: string | null;
state: string | null;
dateUpdateStatut: Date | string | null;
dateUpdateState: Date | string | null;
}
Options des champs scolarité
affirmationOptions (pour etudesSup et travailEfficace)
[
{ label: 'Oui, totalement', value: 'totaly' },
{ label: 'Oui, plutôt', value: 'kinda' },
{ label: 'Non, pas vraiment', value: 'notreally' },
{ label: 'Non, pas du tout', value: 'no' }
]
preparationSupOptions (pour preparationSup)
[
{ label: 'Oui, suffisamment', value: 'yes' },
{ label: 'Oui, mais pas assez', value: 'kinda' },
{ label: 'Non, jamais', value: 'no' }
]
Guide d'utilisation
Pour les développeurs
1. Créer un jeune MVLS
// Dans JeuneService
const jeune = await this.jeuneRepository.create({
// ... champs standard
user: {
sandbox: 'MVLS',
// ... autres champs user
},
externalInfos: {
nomClasse: 'Terminale S',
domaines: ['Sciences', 'Technologie'],
etudesSup: 'totaly',
travailEfficace: 'kinda',
preparationSup: 'yes',
// ... autres champs MVLS
}
});
const jeuneSaved = await this.jeuneRepository.save(jeune);
// Publier le message RabbitMQ
if (jeuneSaved.user.sandbox === 'MVLS') {
await this.mvlsService.publishJeuneUpdatedMessage(
jeuneSaved.user,
jeuneSaved
);
}
2. Mettre à jour un jeune MVLS
// Dans JeuneService.updateAdmin()
const jeune = await this.jeuneRepository.findOne({
where: { id: jeuneId },
relations: ['user']
});
// Mise à jour des champs
jeune.externalInfos.etudesSup = 'kinda';
await this.jeuneRepository.save(jeune);
// Publier le message RabbitMQ
if (jeune.user.sandbox === 'MVLS') {
const jeuneReloaded = await this.jeuneRepository.findOne({
where: { id: jeune.id },
relations: ['user']
});
await this.mvlsService.publishJeuneUpdatedMessage(
jeuneReloaded.user,
jeuneReloaded
);
}
3. Supprimer un jeune MVLS
// Dans JeuneService.deleteJeune()
const jeune = await this.jeuneRepository.findOne({
where: { id: jeuneId },
relations: ['user']
});
if (jeune.user.sandbox === 'MVLS') {
// Envoyer le message USER_DELETED AVANT la suppression
await this.mvlsService.publishUserDeletedMessage(jeune.user.email);
}
// Supprimer l'utilisateur
await this.userRepository.delete(jeune.user.id);
4. Créer un binôme MVLS
// Dans BinomeService.createBinome()
const binome = await this.binomeRepository.create({
jeune: jeuneMVLS,
benevole: benevoleMVLS,
sandbox: 'MVLS',
// ... autres champs
});
const binomeSaved = await this.binomeRepository.save(binome);
// Publier le message RabbitMQ
if (binomeSaved.sandbox === 'MVLS') {
const binomeReloaded = await this.binomeRepository.findOne({
where: { id: binomeSaved.id },
relations: ['jeune', 'benevole', 'jeune.user', 'benevole.user']
});
await this.mvlsService.publishBinomeMessage(binomeReloaded, 'CREATED');
}
5. Envoyer un email via template Brevo
// Dans MailService.send()
const template = await this.messageTemplateRepository.findOne({
where: { name: 'jeune-mvls-inscrit' }
});
if (template.brevoTemplateId) {
await this.sendForTemplate(
'jean.dupont@example.com',
template.brevoTemplateId,
{
jeune: jeune,
prenom: jeune.user.firstName,
nom: jeune.user.lastName,
// ... autres variables
},
'jeune-mvls-inscrit', // Slug pour le log
template.subject // Sujet pour le log
);
}
Pour les administrateurs
Accéder aux champs MVLS dans le BO
- Jeunes MVLS :
/bo/jeunes/{id} - Section "SCOLARITÉ" contient les champs spécifiques MVLS
-
Les 3 questions scolarité sont visibles uniquement pour les MVLS
-
Bénévoles MVLS :
/bo/benevoles/{id} - Section spécifique MVLS avec les champs éclaireur
Vérifier les messages RabbitMQ
Les messages RabbitMQ sont loggés dans les logs de l'application :
docker-compose logs -f api | grep -i "mvls\|rabbitmq"
Vérifier les logs MAIL
Les emails envoyés via Brevo sont loggés dans la table log-mail :
SELECT * FROM `log-mail`
WHERE slug LIKE '%mvls%'
ORDER BY date_envoi DESC
LIMIT 10;
Exemples de code
Exemple complet : Création et mise à jour d'un jeune MVLS
// 1. Créer un jeune MVLS
const jeune = await jeuneRepository.create({
user: {
email: 'mvls_jean.dupont@example.com',
firstName: 'Jean',
lastName: 'Dupont',
sandbox: 'MVLS',
roles: ['lyceen']
},
externalInfos: {
nomClasse: 'Terminale S',
domaines: ['Sciences', 'Technologie'],
formations: ['Bac+3', 'Bac+5'],
etudesSup: 'totaly',
travailEfficace: 'kinda',
preparationSup: 'yes',
mentor_sexe: 'M',
communication: ['email', 'phone']
}
});
const jeuneSaved = await jeuneRepository.save(jeune);
// 2. Publier le message USER_CREATED
if (jeuneSaved.user.sandbox === 'MVLS') {
try {
await mvlsService.publishJeuneUpdatedMessage(
jeuneSaved.user,
jeuneSaved
);
} catch (error) {
console.error('Erreur publication RabbitMQ:', error);
// Ne pas faire échouer la création si la publication échoue
}
}
// 3. Mettre à jour les champs scolarité
jeuneSaved.externalInfos.etudesSup = 'kinda';
await jeuneRepository.save(jeuneSaved);
// 4. Publier le message USER_UPDATED
if (jeuneSaved.user.sandbox === 'MVLS') {
const jeuneReloaded = await jeuneRepository.findOne({
where: { id: jeuneSaved.id },
relations: ['user']
});
await mvlsService.publishJeuneUpdatedMessage(
jeuneReloaded.user,
jeuneReloaded
);
}
Exemple : Envoi d'email via Brevo
// Dans MailService
async sendWelcomeEmailToMvlsJeune(jeune: Jeune) {
const template = await this.messageTemplateRepository.findOne({
where: { name: 'jeune-mvls-inscrit' }
});
if (!template) {
throw new Error('Template jeune-mvls-inscrit non trouvé');
}
// Si le template a un brevoTemplateId, utiliser Brevo
if (template.brevoTemplateId) {
await this.sendForTemplate(
jeune.user.email.replace('mvls_', ''), // Retirer le préfixe
template.brevoTemplateId,
{
jeune: jeune,
prenom: jeune.user.firstName,
nom: jeune.user.lastName,
nomClasse: jeune.externalInfos?.nomClasse || '',
// ... autres variables pour le template Brevo
},
'jeune-mvls-inscrit',
template.subject
);
} else {
// Sinon, utiliser SMTP classique
await this.send(
jeune.user.email,
'jeune-mvls-inscrit',
{ jeune: jeune }
);
}
}
Dépannage
Les messages RabbitMQ ne sont pas envoyés
- Vérifier le sandbox : S'assurer que
user.sandbox === 'MVLS' - Vérifier les logs :
docker-compose logs -f api | grep -i "mvls" - Vérifier la connexion RabbitMQ : Vérifier que
RABBIT_MQ_URLest correct - Vérifier l'exchange : Vérifier que l'exchange
dema1nexiste dans RabbitMQ
Les emails Brevo ne sont pas envoyés
- Vérifier le brevoTemplateId : S'assurer que le template a un
brevoTemplateIddéfini - Vérifier les logs MAIL : Vérifier dans la table
log-mailsi l'email a été loggé - Vérifier les logs Brevo :
docker-compose logs -f api | grep -i "brevo" - Vérifier la clé API : Vérifier que
BREVO_API_KEYest correcte
Les champs MVLS ne s'affichent pas dans le BO
- Vérifier le sandbox : S'assurer que
jeune.user.sandbox === 'MVLS' - Vérifier externalInfos : S'assurer que
jeune.externalInfosexiste et contient les champs - Vérifier l'initialisation : Vérifier que les champs sont initialisés dans
fetch()du composant Vue
Erreur "Cannot find module '@nestjs/common'"
Ces erreurs sont des faux positifs du linter TypeScript dans l'environnement de développement. Le code compile correctement dans Docker. Pour vérifier :
docker exec -it Dema1n_api npm run build
Ressources supplémentaires
- Documentation réception messages USER_DELETED
- Documentation réception messages binômes
- Documentation vérification envoi RabbitMQ jeunes
- Documentation envoi binômes via RabbitMQ
Support
Pour toute question ou problème concernant l'intégration MVLS, contactez l'équipe technique DEMA1N.
Version du document : 1.0
Dernière mise à jour : 12/12/2025