Contexte
Lors d'une installation de test de SCRIBE, nous avons rencontré un problème
systématique lors des reconnexions utilisateur.
L'instance testée est déployée :
- dans un conteneur Podman ;
- sur un serveur Oracle Linux ;
- avec les données applicatives persistées hors du conteneur ;
- SCRIBE version 2.5.0 / build v2500 ;
- commit testé :
e96c9f5d844d3ad697ee20a3b4254aa2e97c24eb.
Le problème a été reproduit avec plusieurs comptes utilisateurs et depuis
un navigateur Chromium / Microsoft Edge.
Description du problème
Après une première connexion réussie, si l'utilisateur se déconnecte puis
essaie de se reconnecter sans recharger complètement la page, le premier
clic sur le bouton de connexion affiche :
Erreur réseau — serveur inaccessible
Pourtant le serveur reste accessible et l'API fonctionne normalement.
Un deuxième clic sur le bouton de connexion permet immédiatement d'entrer
dans l'application.
Un rechargement complet de la page avec Ctrl+F5 avant la reconnexion fait
également disparaître le problème.
Étapes pour reproduire
- Ouvrir SCRIBE.
- Se connecter avec un compte valide.
- Utiliser le bouton de déconnexion de SCRIBE.
- Sans recharger la page, saisir de nouveau des identifiants valides.
- Cliquer une seule fois sur le bouton de connexion.
Résultat observé
SCRIBE affiche :
Erreur réseau — serveur inaccessible
La connexion ne semble pas aboutir.
Un deuxième clic sur le bouton de connexion fonctionne immédiatement.
Résultat attendu
Après une déconnexion, l'utilisateur doit pouvoir se reconnecter dès le
premier clic, sans avoir besoin de recharger la page.
Analyse
Le problème ne semble pas provenir du réseau ni du backend d'authentification.
L'authentification HTTP réussit, mais une erreur survient ensuite pendant
la réinitialisation de l'interface frontend.
1. Les cartes Leaflet restent initialisées après la déconnexion
doLogout() remet notamment :
mais les instances Leaflet map et mapSoins ne sont pas détruites.
Lors de la reconnexion, initAfterLogin() appelle de nouveau initMap().
initMap() exécute alors :
sur un conteneur DOM ayant déjà été initialisé par Leaflet lors de la
session précédente.
Cela peut provoquer une exception de type :
Map container is already initialized
Le fait qu'un Ctrl+F5 résolve systématiquement le problème est cohérent
avec cette hypothèse : le rechargement complet détruit l'état JavaScript
et les anciennes instances Leaflet.
2. _appInitDone est positionné trop tôt
Dans la version actuelle :
async function initAfterLogin() {
if (_appInitDone) return;
_appInitDone = true;
Le drapeau est donc positionné avant que l'initialisation soit réellement
terminée.
Si initMap() ou une autre étape déclenche une exception, l'application
reste malgré tout considérée comme initialisée.
Cela explique également pourquoi le deuxième clic fonctionne :
initAfterLogin() est alors immédiatement ignoré puisque
_appInitDone === true.
3. Le message « Erreur réseau » masque l'erreur JavaScript réelle
doLogin() englobe actuellement dans le même try/catch :
- l'appel
fetch('/api/v1/auth/login', ...);
- l'enregistrement du token ;
- la mise à jour de l'état utilisateur ;
initAfterLogin() ;
- l'initialisation de l'interface.
Ainsi, une exception JavaScript produite après une authentification réussie
arrive dans :
catch(e) {
errEl.textContent = 'Erreur réseau — serveur inaccessible';
}
L'utilisateur reçoit donc un diagnostic réseau alors que le serveur est
parfaitement accessible.
Correctif testé
Nous avons appliqué localement le correctif suivant sur
app/static/js/scribe.js.
Nettoyage des cartes avant leur réinitialisation
function initMap() {
+ // Une reconnexion peut réinitialiser l'interface sans recharger la page.
+ // Détruire proprement une éventuelle instance Leaflet précédente.
+ if (map) {
+ try { map.remove(); } catch(e) {
+ console.warn('initMap: cleanup map', e);
+ }
+ map = null;
+ }
+ if (mapSoins) {
+ try { mapSoins.remove(); } catch(e) {
+ console.warn('initMap: cleanup mapSoins', e);
+ }
+ mapSoins = null;
+ }
+ markers = {};
+
map = L.map('map', {zoomControl:true}).setView([45.9, 6.1], 10);
Ne positionner _appInitDone qu'après une initialisation réussie
async function initAfterLogin() {
if (_appInitDone) return;
- _appInitDone = true;
+
// Afficher l'interface d'abord
Puis à la fin de l'initialisation :
await loadTransfertsEntrants();
+ // L'initialisation complète a réussi.
+ _appInitDone = true;
+
// Forcer recalcul taille carte après affichage
Nettoyage des cartes lors de la déconnexion
function doLogout() {
authToken = null;
currentUser = null;
_appInitDone = false;
+
+ // Nettoyer les cartes Leaflet avant une future reconnexion.
+ if (map) {
+ try { map.remove(); } catch(e) {
+ console.warn('logout: cleanup map', e);
+ }
+ map = null;
+ }
+ if (mapSoins) {
+ try { mapSoins.remove(); } catch(e) {
+ console.warn('logout: cleanup mapSoins', e);
+ }
+ mapSoins = null;
+ }
+ markers = {};
Validation du correctif
Après modification :
- reconstruction de l'image Podman SCRIBE ;
- recréation du conteneur en conservant les volumes de données persistants ;
- redémarrage de l'instance ;
- contrôle de
/health :
{"status":"ok","version":"2.5.0","build":"v2500"}
- contrôle de l'intégrité de la base persistante : OK ;
- tests successifs :
connexion
→ déconnexion
→ reconnexion sans rechargement de page
→ déconnexion
→ reconnexion sans rechargement de page
La reconnexion fonctionne désormais dès le premier clic.
Le message :
Erreur réseau — serveur inaccessible
ne réapparaît plus.
Le correctif n'a nécessité aucune modification de la base de données ni de
la configuration de l'instance.
Amélioration complémentaire possible
Indépendamment du correctif Leaflet, il serait probablement préférable de
séparer dans doLogin() :
- les erreurs liées à l'appel réseau / authentification ;
- les erreurs liées à l'initialisation du frontend après authentification.
Une exception dans initAfterLogin() ne devrait pas être présentée à
l'utilisateur comme une indisponibilité du serveur.
Cela faciliterait également le diagnostic d'éventuels futurs problèmes
d'initialisation.
Contexte
Lors d'une installation de test de SCRIBE, nous avons rencontré un problème
systématique lors des reconnexions utilisateur.
L'instance testée est déployée :
e96c9f5d844d3ad697ee20a3b4254aa2e97c24eb.Le problème a été reproduit avec plusieurs comptes utilisateurs et depuis
un navigateur Chromium / Microsoft Edge.
Description du problème
Après une première connexion réussie, si l'utilisateur se déconnecte puis
essaie de se reconnecter sans recharger complètement la page, le premier
clic sur le bouton de connexion affiche :
Pourtant le serveur reste accessible et l'API fonctionne normalement.
Un deuxième clic sur le bouton de connexion permet immédiatement d'entrer
dans l'application.
Un rechargement complet de la page avec
Ctrl+F5avant la reconnexion faitégalement disparaître le problème.
Étapes pour reproduire
Résultat observé
SCRIBE affiche :
Erreur réseau — serveur inaccessibleLa connexion ne semble pas aboutir.
Un deuxième clic sur le bouton de connexion fonctionne immédiatement.
Résultat attendu
Après une déconnexion, l'utilisateur doit pouvoir se reconnecter dès le
premier clic, sans avoir besoin de recharger la page.
Analyse
Le problème ne semble pas provenir du réseau ni du backend d'authentification.
L'authentification HTTP réussit, mais une erreur survient ensuite pendant
la réinitialisation de l'interface frontend.
1. Les cartes Leaflet restent initialisées après la déconnexion
doLogout()remet notamment :mais les instances Leaflet
mapetmapSoinsne sont pas détruites.Lors de la reconnexion,
initAfterLogin()appelle de nouveauinitMap().initMap()exécute alors :sur un conteneur DOM ayant déjà été initialisé par Leaflet lors de la
session précédente.
Cela peut provoquer une exception de type :
Le fait qu'un
Ctrl+F5résolve systématiquement le problème est cohérentavec cette hypothèse : le rechargement complet détruit l'état JavaScript
et les anciennes instances Leaflet.
2.
_appInitDoneest positionné trop tôtDans la version actuelle :
Le drapeau est donc positionné avant que l'initialisation soit réellement
terminée.
Si
initMap()ou une autre étape déclenche une exception, l'applicationreste malgré tout considérée comme initialisée.
Cela explique également pourquoi le deuxième clic fonctionne :
initAfterLogin()est alors immédiatement ignoré puisque_appInitDone === true.3. Le message « Erreur réseau » masque l'erreur JavaScript réelle
doLogin()englobe actuellement dans le mêmetry/catch:fetch('/api/v1/auth/login', ...);initAfterLogin();Ainsi, une exception JavaScript produite après une authentification réussie
arrive dans :
L'utilisateur reçoit donc un diagnostic réseau alors que le serveur est
parfaitement accessible.
Correctif testé
Nous avons appliqué localement le correctif suivant sur
app/static/js/scribe.js.Nettoyage des cartes avant leur réinitialisation
function initMap() { + // Une reconnexion peut réinitialiser l'interface sans recharger la page. + // Détruire proprement une éventuelle instance Leaflet précédente. + if (map) { + try { map.remove(); } catch(e) { + console.warn('initMap: cleanup map', e); + } + map = null; + } + if (mapSoins) { + try { mapSoins.remove(); } catch(e) { + console.warn('initMap: cleanup mapSoins', e); + } + mapSoins = null; + } + markers = {}; + map = L.map('map', {zoomControl:true}).setView([45.9, 6.1], 10);Ne positionner
_appInitDonequ'après une initialisation réussieasync function initAfterLogin() { if (_appInitDone) return; - _appInitDone = true; + // Afficher l'interface d'abordPuis à la fin de l'initialisation :
Nettoyage des cartes lors de la déconnexion
function doLogout() { authToken = null; currentUser = null; _appInitDone = false; + + // Nettoyer les cartes Leaflet avant une future reconnexion. + if (map) { + try { map.remove(); } catch(e) { + console.warn('logout: cleanup map', e); + } + map = null; + } + if (mapSoins) { + try { mapSoins.remove(); } catch(e) { + console.warn('logout: cleanup mapSoins', e); + } + mapSoins = null; + } + markers = {};Validation du correctif
Après modification :
/health:{"status":"ok","version":"2.5.0","build":"v2500"}La reconnexion fonctionne désormais dès le premier clic.
Le message :
Erreur réseau — serveur inaccessiblene réapparaît plus.
Le correctif n'a nécessité aucune modification de la base de données ni de
la configuration de l'instance.
Amélioration complémentaire possible
Indépendamment du correctif Leaflet, il serait probablement préférable de
séparer dans
doLogin():Une exception dans
initAfterLogin()ne devrait pas être présentée àl'utilisateur comme une indisponibilité du serveur.
Cela faciliterait également le diagnostic d'éventuels futurs problèmes
d'initialisation.