Alert-Parent — Erreurs courantes¶
Backend ne démarre pas¶
Symptôme : docker compose ps montre le backend en "Restarting"
Causes possibles :
.envmanquant ou incomplet → vérifier que.envexiste et contient toutes les variablesMONGO_URIinvalide → vérifier la chaîne de connexion Atlas- Port déjà utilisé →
lsof -i :5011
Diagnostic :
Port already allocated¶
Symptôme : docker compose up échoue avec port is already allocated
Cause : Un ancien conteneur utilise encore le port.
Solution :
# Identifier le conteneur qui utilise le port
docker ps --format "table {{.Names}}\t{{.Ports}}" | grep 5011
# Arrêter l'ancien conteneur
docker stop NOM_CONTENEUR
docker rm NOM_CONTENEUR
# Relancer
docker compose up -d
Permission denied sur .env¶
Symptôme : Le pipeline échoue avec Permission denied lors de l'écriture du .env
Cause : L'utilisateur SSH n'a pas les droits sur le répertoire du projet.
Solution :
GHCR denied (pull image échoue)¶
Symptôme : docker compose pull échoue avec denied ou unauthorized
Causes :
- Le VPS n'est pas authentifié auprès de GHCR
- Le token a expiré
Solution :
# Se connecter à GHCR
echo $GITHUB_TOKEN | docker login ghcr.io -u USERNAME --password-stdin
# Ou vérifier les permissions du repo
# Settings > Actions > General > Workflow permissions > Read and write
git pull échoue sur le VPS¶
Symptôme : Le pipeline échoue à l'étape git pull avec Permission denied (publickey)
Cause : Le VPS n'a pas de clé SSH GitHub configurée pour les repos privés.
Solution : Ne pas utiliser git pull. Le pipeline doit utiliser SCP pour copier le docker-compose.yml. Voir le guide CI/CD.
MongoDB ECONNREFUSED¶
Symptôme : Le health check retourne 503 avec mongodb.status: "error"
Causes possibles :
- Le fichier .env est vide : le
MONGO_URIn'est pas défini - L'IP du VPS n'est pas dans la whitelist Atlas : aller sur cloud.mongodb.com > Network Access > ajouter l'IP du VPS
- Le cluster Atlas est en pause : vérifier le statut du cluster dans le dashboard Atlas
Health check échoue (503)¶
Symptôme : /health retourne {"status": "degraded"}
Cause : MongoDB n'est pas accessible
Actions :
- Vérifier le statut MongoDB Atlas dans le dashboard Atlas
- Vérifier que l'IP du VPS est dans la whitelist Atlas
- Tester la connexion :
Emails ne s'envoient pas¶
Symptôme : MailSended reste à isSent: "no"
Causes :
RESEND_TOKENinvalide → vérifier dans le dashboard Resend- Quota Resend dépassé → vérifier les limites
- Erreur dans la boucle mail → chercher "Mail loop error" dans les logs
Diagnostic :
Container "unhealthy"¶
Symptôme : docker compose ps montre "(unhealthy)"
Action : Le healthcheck /health échoue. Vérifier les logs et la connexion MongoDB.
Erreurs de campagnes d'alertes (frontend)¶
Un étudiant présent dans le fichier importé ne reçoit pas l'alerte¶
Symptôme : un fichier de notes/présences est chargé dans le composer, mais un login présent dans ce fichier ne figure pas parmi les destinataires réels de l'envoi.
Cause (comportement voulu, pas un bug) : pour les templates pilotés par fichier (Tepitech, stumper, module...), les destinataires réels sont les étudiants présents dans le fichier uploadé, pas tout le groupe ciblé (campus/promo/classe/sélection). resolveFileRecipients() (backend/controllers/alertCampaignController.js) restreint l'envoi aux logins du fichier qui correspondent à un étudiant du ciblage. Un login du fichier hors du ciblage actuel, ou introuvable en base, génère un warning (file_login_outside_target / file_login_unknown_student) plutôt qu'un envoi silencieusement ignoré — mais si aucun login du fichier ne correspond au ciblage, preview/send renvoie une erreur bloquante (no_file_recipient_in_target).
Solution : vérifier les warnings renvoyés par POST /alert-campaigns/preview-draft (ou /:id/preview) avant d'envoyer — ils listent précisément les logins ignorés et pourquoi (campus/promo/classe différents du ciblage, ou étudiant introuvable). Ajuster le ciblage ou le fichier en conséquence.
Le formulaire de composer se vide en changeant de campus¶
Symptôme (résolu) : remplir le composer puis changer le campus en dernier effaçait template, topic, variables, fichiers et surcharges déjà saisis.
Cause : le handler de changement de campus réinitialisait tout l'état du formulaire au lieu des seuls champs réellement dépendants du campus.
Résolution : fix(composer): campus change no longer wipes the whole form — le changement de campus ne réinitialise plus que ce qui dépend effectivement du campus (promo + étudiants sélectionnés) ; template, topic, variables, fichiers et surcharges sont préservés.
La preview réinitialise les champs qu'on vient de corriger¶
Symptôme (résolu) : après une erreur de preview sur un brouillon existant, corriger les champs puis recliquer Preview effaçait la correction.
Cause : Preview déclenchait une mutation update, dont le succès invalidait la query détail de la campagne — le refetch réinitialisait variablesSchema et les globalVariables en cours de saisie.
Résolution : fix(composer): stop preview from resetting form fields — la mutation d'update n'invalide plus que les listes de campagnes, pas la query détail de la campagne en cours d'édition (le composer garde son état via setCampaign), et la normalisation des globalVariables ne mute plus l'état pendant un recalcul transitoire du schéma.
L'historique affiche « — » pour la promo/classe d'une campagne¶
Symptôme (résolu) : une campagne ciblant des étudiants sélectionnés individuellement (pas par promo/classe) affichait « — » dans les colonnes Promo/Classe de l'historique, même si les étudiants ciblés appartenaient bien à une promo/classe identifiable.
Cause : ces colonnes ne lisaient que les champs promo/classe de la campagne, qui restent null quand le ciblage se fait par sélection directe d'étudiants (pas par groupe).
Résolution : fix(campaigns): show promo/classe from targeted students as fallback — à défaut de promo/classe au niveau de la campagne, l'UI et le résumé backend (targetSummary) retombent sur les promos/classes distinctes des étudiants réellement ciblés.
Pipeline CI/CD échoue¶
Job Build échoue¶
- "pnpm-lock.yaml not found" : le fichier doit être commité dans le repo
- "unauthorized" : vérifier les permissions GHCR du repo (Settings > Actions > General > Workflow permissions > Read and write)
Job Deploy échoue¶
- "Connection refused" : vérifier
SERVER_HOSTet que le VPS est accessible - "Permission denied" : vérifier
SERVER_SSH_KEY(clé privée complète, incluant les lignes BEGIN et END) - "docker: command not found" : Docker n'est pas installé sur le VPS ou l'utilisateur n'est pas dans le groupe docker (
usermod -aG docker UTILISATEUR)