Alert-Parent Backend
Description
Alert-Parent est une plateforme interne qui permet aux équipes pédagogiques d'EPITECH Bénin d'envoyer des alertes aux parents et référents financiers des étudiants concernant leurs résultats académiques.
Fonctionnalités principales
- Gestion des promos : création de promotions par cycle (Bachelor, MSc, Codac) et année de fin
- Gestion des étudiants : création unitaire, import CSV en masse, changement de classe/promo
- Alertes pédagogiques : Tepitech, Stumpers, Modules, Présences, Projets, Roadblocks, -42, Évaluation de stage
- File d'attente email : les alertes sont mises en queue dans MongoDB et envoyées progressivement via l'API Resend
- Authentification : JWT classique + Microsoft Azure AD (SSO)
Architecture
Stack technique
| Composant |
Technologie |
| Framework |
Express.js (Node.js 20) |
| Base de données |
MongoDB Atlas |
| Email transactionnel |
Resend API |
| Authentification |
JWT + Microsoft Azure AD |
| Conteneur |
Docker (node:20-alpine, pnpm) |
Routes API
| Route |
Description |
/api/users |
Inscription, login, gestion des comptes admin |
/api/students |
CRUD étudiants, import CSV, bulk update |
/api/promos |
CRUD promos, mapping classe/promo |
/api/alerts |
Envoi d'alertes pédagogiques par type |
/api/docs |
Documentation Swagger interactive |
/health |
Endpoint de vérification de santé |
Modèle de données
Student
├── firstname, lastname, email, sexe
├── promo (ObjectId → Promo)
├── classe (TEK1, TEK1 PSO, TEK2, TEK3, PreMSC, MSC1, MSC2, CODAC)
├── ref_financier_1_* (prénom, nom, email, sexe)
└── ref_financier_2_* (optionnel)
Promo
├── cycle (BACHELOR, MSC, CODAC)
└── end_year (ex: 2027)
MailSended
├── from (user qui a envoyé), to (email destinataire)
├── student (ObjectId → Student)
├── topic (Tepitech, Module, Présence, etc.)
├── obj (sujet), message (HTML)
├── isSent (yes/no)
└── createdAt, updatedAt
File d'attente email (Resend)
Un processus asynchrone tourne en boucle dans server.js :
- Toutes les 5 secondes, il cherche un
MailSended avec isSent: "no"
- Il l'envoie via l'API Resend
- En cas de succès, il marque
isSent: "yes"
- En cas d'erreur, il attend 60 secondes avant de réessayer
Ce mécanisme découple la création d'alertes de leur envoi effectif.
Collections MongoDB
| Collection |
Rôle |
students |
Étudiants avec leurs référents financiers |
promos |
Promotions par cycle et année |
mailsendeds |
File d'attente des mails à envoyer |
users |
Comptes administrateurs |
emailconfirms |
Tokens de confirmation email |
passwordresets |
Tokens de reset mot de passe |
Diagrammes
Architecture globale
graph TB
User[Utilisateur / Navigateur]
Frontend["Frontend<br/>alert.epitools.bj"]
Nginx["Nginx<br/>Reverse proxy + TLS"]
Backend["Backend API<br/>Express.js :5010"]
MongoDB["MongoDB Atlas<br/>(Cloud)"]
Resend["Resend API<br/>(Email)"]
AzureAD["Azure AD<br/>(SSO)"]
User --> Nginx
Nginx --> Frontend
Nginx --> Backend
Backend --> MongoDB
Backend --> Resend
Backend --> AzureAD
Flux d'envoi d'alerte
sequenceDiagram
participant Admin as Admin (Frontend)
participant API as Backend API
participant DB as MongoDB Atlas
participant Queue as Mail Queue (loop)
participant Resend as Resend API
participant Parent as Parent (Email)
Admin->>API: POST /api/alerts/tepitech
API->>DB: Student.findOne({email})
API->>DB: MailSended.create({isSent: "no"})
API-->>Admin: {success: [...], failed: [...]}
loop Toutes les 5 secondes
Queue->>DB: MailSended.find({isSent: "no"})
Queue->>Resend: resend.emails.send(...)
Resend->>Parent: Email envoyé
Queue->>DB: MailSended.update({isSent: "yes"})
end
Docker
Dockerfile
L'image utilise node:20-alpine avec pnpm comme gestionnaire de paquets. L'application tourne en tant qu'utilisateur non-root pour la sécurité.
docker-compose.yml
services:
backend:
image: ghcr.io/epitechafrik/alert-parent-backend:${IMAGE_TAG:-latest}
env_file: .env
ports:
- "127.0.0.1:5011:5010"
restart: always
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5010/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
Points importants :
- L'image est tirée depuis GHCR (
ghcr.io/epitechafrik/alert-parent-backend)
- Le port est bindé sur
127.0.0.1 uniquement (accessible seulement via Nginx)
- Les variables d'environnement sont chargées depuis
.env via env_file
- Le healthcheck vérifie
/health sur le port interne 5010
Health Endpoint
GET /health
Utilisé par Docker Compose (healthcheck), Uptime Kuma (monitoring) et le pipeline CI/CD (vérification post-déploiement).
Réponse (200 OK)
{
"status": "ok",
"timestamp": "2026-02-22T10:30:00.000Z",
"uptime_seconds": 86400,
"environment": "production",
"dependencies": {
"mongodb": {
"status": "ok",
"latency_ms": 12
},
"resend": {
"status": "configured"
},
"smtp": {
"status": "configured"
}
}
}
Réponse (503 Service Unavailable)
Retourné quand MongoDB est inaccessible :
{
"status": "degraded",
"timestamp": "2026-02-22T10:30:00.000Z",
"uptime_seconds": 120,
"environment": "production",
"dependencies": {
"mongodb": {
"status": "error",
"latency_ms": null
},
"resend": {
"status": "configured"
},
"smtp": {
"status": "configured"
}
}
}
Utilisation
# Test simple
curl http://127.0.0.1:5011/health
# Test avec formatage
curl -s http://127.0.0.1:5011/health | python3 -m json.tool
# Vérifier uniquement le status code
curl -o /dev/null -s -w "%{http_code}" http://127.0.0.1:5011/health
# 200 = OK, 503 = dégradé
Variables d'environnement
Toutes les variables sont définies dans le fichier .env à la racine du projet (jamais commité dans git). Le template est dans .env.example.
Application
| Variable |
Description |
Exemple |
NODE_ENV |
Mode d'exécution |
production |
PORT |
Port interne du serveur |
5010 |
Base de données
| Variable |
Description |
Exemple |
MONGO_URI |
URI MongoDB Atlas |
mongodb+srv://user:pass@cluster.mongodb.net/dbname |
Authentification
| Variable |
Description |
Exemple |
JWT_SECRET |
Clé secrète JWT (64 chars min) |
chaîne aléatoire longue |
ADMIN_EMAIL |
Email du premier admin créé au démarrage |
admin@epitech.eu |
PASSWORD_SIZE |
Taille minimum des mots de passe |
8 |
PASSWORD_CAPITAL |
Exiger une majuscule |
true |
PASSWORD_LOWERCASE |
Exiger une minuscule |
true |
PASSWORD_NUMBER |
Exiger un chiffre |
true |
PASSWORD_CHAR |
Exiger un caractère spécial |
true |
Email
| Variable |
Description |
Exemple |
MAIL_NAME |
Nom d'expéditeur |
EPITECH Info |
MAIL_HOST |
Serveur SMTP |
alouette.o2switch.net |
MAIL_PORT |
Port SMTP |
465 |
MAIL_ADDR |
Adresse d'envoi |
no-reply@epitech.bj |
MAIL_PASS |
Mot de passe SMTP |
secret |
RESEND_TOKEN |
Token API Resend (envoi des alertes) |
re_xxxxx |
URLs
| Variable |
Description |
Exemple |
CORS_ORIGIN |
Origine autorisée CORS |
https://alert.epitools.bj |
FRONT_URL |
URL du frontend |
https://alert.epitools.bj |
API_URL |
URL publique de l'API |
https://api.epitools.bj |
Microsoft Azure AD (optionnel)
| Variable |
Description |
MICROSOFT_CLIENT_ID |
Client ID de l'App Registration Azure |
MICROSOFT_TENANT_ID |
Tenant ID Azure |
Docker
| Variable |
Description |
Exemple |
IMAGE_TAG |
Tag de l'image Docker à utiliser |
latest ou sha-abc1234 |
Rollback
Quand faire un rollback
- Le déploiement a cassé une fonctionnalité critique
- Le health check échoue après un déploiement
- Une régression est détectée en production
Procédure
# 1. Trouver la version précédente
docker images ghcr.io/epitechafrik/alert-parent-backend --format "table {{.Tag}}\t{{.CreatedAt}}"
# 2. Exécuter le rollback
cd /root/projects/alert-parent/alert-parent-backend
./scripts/rollback.sh sha-XXXXXXX
# 3. Vérifier
curl -s http://127.0.0.1:5011/health | python3 -m json.tool
docker compose logs backend --tail 20
Après le rollback
- Investiguer la cause du problème sur la branche
main
- Corriger et pousser un fix
- Le pipeline redéploiera automatiquement
Backups
MongoDB Atlas
La base de données est hébergée sur MongoDB Atlas, qui gère automatiquement :
- Snapshots automatiques : toutes les 6 heures
- Rétention : configurable dans Atlas (7 jours par défaut)
- Point-in-time recovery : restauration à n'importe quel moment
Backup manuel
mongodump --uri="mongodb+srv://USER:PASSWORD@cluster.mongodb.net/al3rtParent" --out=./dump-$(date +%Y%m%d)
Restauration
# Restaurer un dump dans une base locale (pour test)
mongorestore --db alertParentLocal ./dump-YYYYMMDD/al3rtParent
# Restaurer dans Atlas
mongorestore --uri="mongodb+srv://USER:PASSWORD@cluster.mongodb.net/al3rtParent" ./dump-YYYYMMDD/al3rtParent