EPIDOCS — Erreurs courantes¶
Frontend¶
Page blanche après déploiement¶
Symptôme : L'application affiche une page blanche ou une erreur 500.
Cause : Les variables NEXT_PUBLIC_* ne sont pas injectées au build time.
Solution :
# Vérifier que les variables sont dans le .env sur le VPS
ssh root@VPS_IP
cat /root/projects/epidocs/epidocs-frontend/.env
# Les variables NEXT_PUBLIC_* doivent être présentes AVANT le build Docker
# Si elles manquent, les ajouter et reconstruire l'image
Warning
Les variables NEXT_PUBLIC_* sont injectées au build time, pas au runtime. Un simple restart du conteneur ne suffit pas — il faut rebuild l'image Docker.
Boucle de redirection /auth¶
Symptôme : L'utilisateur est redirigé en boucle vers /auth après connexion.
Cause possible 1 : Le cookie auth_token est bloqué par le navigateur (Domain invalide).
Solution :
# Vérifier dans les DevTools > Application > Cookies
# Si le cookie n'apparaît pas, c'est un problème de Domain
# Le backend doit configurer AUTH_COOKIE_DOMAIN = None en dev
# ou AUTH_COOKIE_DOMAIN = ".epitools.bj" en prod
Cause possible 2 : Le proxy Next.js ne lit pas correctement les cookies.
Solution : Vérifier que src/proxy.js utilise bien request.cookies.get() et non cookies() de next/headers.
Erreur 503 sur toutes les requêtes API¶
Symptôme : Toutes les requêtes API retournent 503, y compris /auth/sign_in.
Cause : Le mode maintenance est activé côté backend et les routes d'auth ne sont pas exemptées.
Solution :
# Se connecter directement au backend pour désactiver la maintenance
curl -X PUT http://127.0.0.1:7010/admin/system-status \
-H "Cookie: auth_token=VOTRE_TOKEN" \
-H "Content-Type: application/json" \
-d '{"is_active": true}'
Danger
Si les routes d'auth sont bloquées par la maintenance, aucun admin ne peut se connecter. Corriger le middleware backend pour exempter /auth/sign_in et /auth/callback.
"Mode maintenance" affiché alors que le système est actif¶
Symptôme : Le dashboard admin affiche "MODE MAINTENANCE" même quand is_active: true.
Cause : Le backend retourne les données en camelCase (isActive) mais le frontend lit en snake_case (is_active).
Solution : Vérifier que normalizeStatusData() dans systemStatusService.js gère bien les deux formats :
Résultats de recherche étudiants vides¶
Symptôme : La recherche d'étudiants dans le wizard de génération ne retourne aucun résultat malgré des étudiants existants.
Cause : Le backend retourne { students: [...] } mais le code frontend cherche data.results.
Solution : Vérifier que le code utilise bien :
Erreur 500 sur GET /documents/available-document-types¶
Symptôme : 'User' object has no attribute 'section' dans les logs backend.
Cause : Un admin appelle cette route qui tente d'accéder à request.user.section, mais les admins n'ont pas d'attribut section.
Solution : Passer ?studentEmail=xxx ou ?classe=PGE1 comme query param pour que le backend utilise la section de l'étudiant ou de la classe au lieu de celle de l'utilisateur connecté.
Backend¶
TypeError sur PUT /admin/system-status¶
Symptôme : TypeError: '<=' not supported between instances of 'str' and 'datetime.datetime'
Cause : Les champs scheduled_start et scheduled_end sont stockés comme strings mais comparés avec timezone.now() (datetime).
Solution : Parser les dates avec parse_datetime() avant la comparaison dans la vue backend.
Génération en lot timeout¶
Symptôme : La requête POST /documents/admin/batch-generate timeout pour les grandes classes.
Cause : La génération de nombreux PDFs prend du temps. Le timeout par défaut d'Axios est trop court.
Solution : Le frontend utilise déjà un timeout de 300 secondes (5 minutes). Si ce n'est pas suffisant :
# Vérifier côté Nginx
# /etc/nginx/sites-available/epidocs
proxy_read_timeout 600s;
proxy_connect_timeout 600s;
proxy_send_timeout 600s;
Cookie auth_token non défini après login¶
Symptôme : Le login réussit (200 OK) mais le cookie n'est pas stocké dans le navigateur.
Cause : Le Set-Cookie du backend a un attribut Domain incompatible avec le frontend.
Solution :
- Dev :
AUTH_COOKIE_DOMAIN = Nonedans les settings Django - Prod :
AUTH_COOKIE_DOMAIN = ".epitools.bj"(domaine racine avec point)