Aller au contenu

Alert-Parent — Erreurs courantes

Backend ne démarre pas

Symptôme : docker compose ps montre le backend en "Restarting"

Causes possibles :

  1. .env manquant ou incomplet → vérifier que .env existe et contient toutes les variables
  2. MONGO_URI invalide → vérifier la chaîne de connexion Atlas
  3. Port déjà utilisé → lsof -i :5011

Diagnostic :

cd /root/projects/alert-parent/alert-parent-backend
docker compose logs backend --tail 50

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 :

chown -R UTILISATEUR:UTILISATEUR /root/projects/alert-parent/alert-parent-backend

GHCR denied (pull image échoue)

Symptôme : docker compose pull échoue avec denied ou unauthorized

Causes :

  1. Le VPS n'est pas authentifié auprès de GHCR
  2. 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 :

  1. Le fichier .env est vide : le MONGO_URI n'est pas défini
    cat /root/projects/alert-parent/alert-parent-backend/.env | wc -l
    # Si 0 → le DOTENV_FILE secret est vide ou manquant
    
  2. L'IP du VPS n'est pas dans la whitelist Atlas : aller sur cloud.mongodb.com > Network Access > ajouter l'IP du VPS
  3. 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 :

  1. Vérifier le statut MongoDB Atlas dans le dashboard Atlas
  2. Vérifier que l'IP du VPS est dans la whitelist Atlas
  3. Tester la connexion :
    docker compose exec backend node -e "require('mongoose').connect(process.env.MONGO_URI)"
    

Emails ne s'envoient pas

Symptôme : MailSended reste à isSent: "no"

Causes :

  1. RESEND_TOKEN invalide → vérifier dans le dashboard Resend
  2. Quota Resend dépassé → vérifier les limites
  3. Erreur dans la boucle mail → chercher "Mail loop error" dans les logs

Diagnostic :

docker compose logs backend | grep -i "mail"

Container "unhealthy"

Symptôme : docker compose ps montre "(unhealthy)"

Action : Le healthcheck /health échoue. Vérifier les logs et la connexion MongoDB.

docker compose logs backend --tail 50
curl -s http://127.0.0.1:5011/health | python3 -m json.tool

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_HOST et 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)