# FAQ / Dépannage ## Synchronisation Escada ### « Import timeout — vérifiez les logs (> 15 min) » Le subprocess Playwright n'a pas répondu dans le temps imparti. Causes possibles : - Escadaweb répond très lentement (en pic de charge) - Captcha / re-login imposé par Escada - Container Docker en surcharge **Que faire** : 1. Aller dans `/logs` et chercher le dernier `[sync]` actif 2. Si Playwright est bloqué sur un écran de login : lancer un Actualiser des classes (re-login) 3. Si gros volume de classes : lancer la sync en plusieurs lots de 5-6 classes ### « Aucune classe récupérée » Le scraping Playwright a échoué — souvent token de session expiré. **Que faire** : recliquer sur « Actualiser » (force un re-login propre). ### « Le push échoue toujours sur le même apprenti » Possibles causes : - L'apprenti existe en local mais pas (ou plus) sur Escada → le pending est obsolète, à supprimer - Le nom diffère entre local et Escada (ex : prénom composé partiel) - La page Escada de cet apprenti est verrouillée par un autre éditeur (lock pessimiste Escada) **Que faire** : 1. Vérifier les logs pour le message d'erreur exact 2. Si l'apprenti n'existe plus : supprimer le pending manuellement en DB 3. Sinon : retenter plus tard ### « L'option 'Forcer la réimportation complète' est en rouge — c'est dangereux ? » Pas dangereux mais **destructif** : - Tous les pendings concernés sont écrasés (les modifs locales pas encore poussées sont perdues) - Tous les statuts d'absences sont remis à ce qu'Escada dit À utiliser **uniquement** quand on veut sciemment reprendre l'état complet d'Escada. ## Tâches planifiées (cron) ### « J'ai créé une tâche, elle ne se déclenche pas » Vérifier dans l'ordre : 1. La tâche est-elle **activée** ? (toggle vert) 2. Les heures choisies sont-elles dans le bon fuseau horaire ? (l'app fonctionne en `Europe/Zurich`) 3. La crontab du host appelle-t-elle bien `cron_tick.py` ? ```bash crontab -l | grep cron_tick # Doit avoir : * * * * * docker exec eptm-dashboard-app-1 python scripts/cron_tick.py ``` 4. Regarder le log d'exécution : `ls /logs/cron/` et `tail` sur le dernier fichier. ### « J'avais un job 'toutes les X minutes', il a disparu » L'ancien mode `interval` a été remplacé par `daily_multi`. Au boot du container, les jobs `interval` sont **automatiquement migrés** en `daily_multi` (l'intervalle est déroulé sur 24 h depuis minuit). Idem pour les anciens jobs `daily` (`HH:MM`) → convertis en `daily_multi` avec une seule heure. Si tu veux modifier un de ces jobs : ouvre-le, tu verras la grille 24 cases avec les heures qui étaient configurées. ### « La tâche ne notifie pas sur Telegram » - `notify_on` doit être `always`, `success` ou `failure` (pas `never`) - Le `bot_token` et `chat_id` doivent être valides → tester via le bouton « Tester Telegram » ## Édition d'absences ### « Le bouton 'Absent toute la journée' est grisé » Affichage « Absent toute la journée (Données chronoplan manquantes) » → aucun horaire n'est configuré pour cette classe et ce jour de la semaine. **Que faire** : admin → `/params → Horaires de classe`, sélectionner la classe, cocher les périodes du jour concerné, enregistrer. ### « Quel est le type de jour affiché en badge ? » Théorie / Pratique / Matu — défini par classe et par jour dans `/params → Horaires de classe`. Sert d'indication contextuelle dans le panneau d'édition. ## Authentification ### « Mon utilisateur n'a accès à aucune classe » À sa première connexion, un dialog s'ouvre pour configurer l'accès. Il doit fournir : - son email Escada (identifiant Keycloak) - son mot de passe Escada - un code TOTP courant Un script Playwright tourne en arrière-plan (visible dans `/logs` avec préfixe `[fetch_classes:]`) et remplit automatiquement `allowed_classes` dans `auth.yaml`. Si le dialog est fermé (« Plus tard »), il réapparaîtra au prochain login. ### « J'ai perdu mon téléphone avec mon code 2FA » Un admin peut réinitialiser le 2FA via `/users` : bouton « Réinitialiser 2FA ». Au prochain login, l'utilisateur reverra le QR code. ### « Comment révoquer l'accès d'un user » Admin → `/users` → bouton « Réinitialiser les droits » : efface `allowed_classes` + identifiants Escada. À sa prochaine connexion, le popup d'enrôlement réapparaîtra (s'il ne le reconfigure pas, il n'aura accès à rien). ## Données ### « Les BN affichent des trous (cellules vides) » C'est normal : un apprenti peut avoir commencé sa formation au S2 ou S3 → les premiers semestres restent vides. L'extraction depuis le PDF Escada respecte ces trous. Toutes les notes (pas juste les moyennes) sont stockées et affichées. ### « Les notes Matu n'apparaissent pas » Pré-requis : l'apprenti est dans une classe MP / MI correspondante. Le matching se fait via la classe MP1, MP2, etc. La sync Matu cherche le PDF correspondant **si la case 'BN' est cochée**. ### « L'adresse sur les avis sanction/retenue est fausse » Depuis mai 2026, l'app n'utilise **plus l'adresse de l'entreprise**. Elle prend : - l'adresse du **représentant légal** si l'apprenti est mineur (`majeur=False`) - l'adresse perso de **l'apprenti** sinon Vérifier que les champs `ApprentiFiche.resp_legal_*` et `ApprentiFiche.adresse/code_postal/localite` sont bien remplis (sync option « Données apprentis »). ## Performance ### « L'app rame quand je change de classe avec beaucoup d'apprentis » Le `_reload` reconstruit les tableaux HTML BN / Notes pour chaque apprenti — peut prendre quelques secondes pour 25+ apprentis. Un skeleton s'affiche pendant le chargement pour donner du feedback visuel. ### « L'app est bloquée pour les autres users quand je lance la synchro de mes classes » C'était un bug : le subprocess Playwright bloquait l'event loop. Corrigé en passant à `@rx.event(background=True)` + `asyncio.create_subprocess_exec`. Si ça revient, vérifier que `fetch_my_classes` est bien décoré `background=True` dans `profile.py`. ## Conteneur Docker ### « Le conteneur consomme 100 % CPU à l'idle » Bug historique lié au hot-reload qui détectait les fichiers WAL/SHM de SQLite comme des modifications source. Corrigé via `REFLEX_HOT_RELOAD_EXCLUDE_PATHS=/app/data` dans le docker-compose. ### « La version dans le sidebar ne change pas après un nouveau tag git » `data/VERSION` doit être mis à jour manuellement (le `.git` du container dev n'est pas synchronisé avec celui du hôte). Édite le fichier, puis : ```bash docker restart eptm-dashboard-app-1 ``` ### « Comment redémarrer proprement » ```bash cd /opt/eptm-dashboard docker compose -f docker-compose.dev.yml restart app ``` ### « Comment voir les logs du serveur Reflex » ```bash docker logs -f eptm-dashboard-app-1 ``` ## SSL / Accès depuis le web ### « Mon navigateur affiche un avertissement sécurité sur dev.dashboard.eptm-automation.ch » Vérifier le certificat affiché : si l'émetteur est « Fortinet CA » (et non Let's Encrypt), c'est ton firewall qui fait du SSL inspection / IPS — pas un problème du serveur. À demander à l'IT pour whitelister le domaine.