Vue d’ensemble et objectif
Lorsque les utilisateurs rencontrent des erreurs, ils méritent un retour clair expliquant ce qui s’est passé et comment corriger le problème. Les messages d’erreur bruts du backend doivent être normalisés pour :
- Supprimer le bruit : enlever les préfixes "Error:" redondants et nettoyer les espaces
- Prévenir les fuites : s’assurer que les détails d’implémentation sensibles n’atteignent jamais l’utilisateur
- Fournir des repli : afficher des messages sûrs lorsque les erreurs sont vides ou mal formées
- Garantir la cohérence : appliquer la même logique à plus de 11 modules frontend
- Améliorer le débogage : consigner les détails complets dans Phantom Wing tout en montrant des résumés sûrs aux utilisateurs
Le problème : erreurs génériques contre erreurs utiles
Avant la standardisation, les modules PayCal utilisaient une gestion d’erreur ad hoc :
// ❌ MAUVAIS : expose l’erreur brute, duplique la logique
PC.showToast(error?.message || 'Import échoué.');
PW.error(`Import échoué : ${error.message}`);
Problèmes de cette approche :
- Les utilisateurs voient des messages bruts déroutants comme "ECONNREFUSED : connexion refusée"
- Chaque module implémente indépendamment sa propre logique de repli
- Aucun nettoyage cohérent des espaces ni suppression des préfixes
- Les messages d’erreur vides peuvent afficher "undefined" dans l’interface
La solution : un résolveur d’erreur standardisé
Tous les modules frontend PayCal utilisent désormais une fonction résolveur unifiée qui normalise les messages d’erreur :
// ✅ BIEN : normalisé, cohérent, sûr
const resolveThrownMessage = (error, fallbackMessage) => {
const raw = typeof error?.message === 'string'
? error.message
: String(error || '');
const normalized = raw.replace(/^Error:\s*/i, '').trim();
return normalized !== '' ? normalized : fallbackMessage;
};
Utilisation :
// Dans les blocs catch de tous les modules
try {
await updateProfile(data);
} catch (error) {
const message = resolveThrownMessage(error, 'Impossible de mettre à jour le profil.');
PC.showToast(message, 'error'); // L’utilisateur voit un retour utile
PW.error(message); // Consigné pour le débogage
}
Portée de l’implémentation
En avril 2026, ce modèle de gestion d’erreur standardisé a été appliqué à 11 modules frontend avec environ 40+ blocs catch normalisés :
Authentification et paramètres (7 modules)
html/js/auth-recovery/index.php(4 catches)html/js/signin/index.php(2 catches)html/js/signin/verification-reminder.js(2 catches)html/js/signin/verification-status-banner.js(1 catch)html/js/settings/index.php(8+ catches)
Modules cœur et données (4 modules)
html/js/core/network.js(3 catches)html/js/core/index.php(5 catches)html/js/core/billing.js(5 catches)html/js/earnings/index.php(4 catches)
Modules à forte valeur (10+ points de capture) :
html/js/organizations/index.php- gestion des organisations, demandes d’accès, pistes d’audit (19+ catches)html/js/sites/index.php- CRUD site, revenus, récupération du travail orphelin (10+ catches)html/js/calendar/calendar.js- opérations de saisie quotidienne, copier/coller/suppression (2 catches)
Catégories d’erreurs et modes de traitement
Le résolveur est appliqué de manière cohérente à plusieurs catégories d’erreurs :
1. Échecs de requêtes réseau
// Module réseau : erreurs HTTP, délais d’attente, problèmes de connexion
async function deleteResource(ep, id) {
try {
// ...logique fetch...
} catch (error) {
const resolved = resolveThrownMessage(error, 'Erreur réseau');
const msg = `[deleteResource] ${resolved}`;
PW.error(msg);
throw new Error(msg);
}
}
2. Gestion des réponses API
// Facturation/Paramètres : le serveur a renvoyé un message d’erreur dans la charge utile
try {
const response = await fetch('/api/v1/billing/subscription');
const payload = await response.json();
if (!response.ok) {
throw new Error(payload?.message || 'Impossible de charger l’état de la facturation.');
}
} catch (error) {
const resolved = resolveThrownMessage(error, 'Impossible de charger l’état de la facturation.');
setScreenReaderStatus(resolved);
}
3. Échecs d’opérations UI
// Calendrier/Organisations : actions initiées par l’utilisateur (coller, supprimer, mettre à jour)
button.addEventListener('click', async () => {
try {
await performAction();
PC.showToast('Succès !', 'save');
} catch (error) {
const message = resolveThrownMessage(error, 'Action échouée. Réessayez.');
PC.showToast(message, 'error');
}
});
4. Initialisation asynchrone
// Modules cœur : échecs de démarrage ou d’initialisation dépendante
try {
NavigationToggle.init();
} catch (err) {
const resolved = resolveThrownMessage(err, 'Initialisation de la navigation échouée');
PW.warn(resolved); // Consigné mais ne bloque pas la page
}
Considérations de sécurité
La normalisation des messages d’erreur protège la vie privée et l’intégrité du système :
- Aucun détail de base de données : les erreurs backend comme "UNIQUE constraint failed on email" sont interceptées à la frontière API et remplacées par des messages conviviaux
- Aucun chemin de fichier : les erreurs système révélant des chemins de fichier ou des détails de processus sont supprimées
- Aucune fuite d’auth : les réponses aux échecs d’authentification ne révèlent jamais si un compte existe (seulement des messages génériques résistants au timing)
- Aucun détail CORS/réseau : les erreurs de transport sont normalisées en messages génériques "Erreur de connexion"
- Repli sûr : tous les captureurs ont des messages de repli explicites ; jamais "undefined" ni "null"
Avantages pour l’expérience utilisateur
Cette standardisation donne aux utilisateurs un retour plus clair, plus sûr et plus cohérent, tout en facilitant le support et le débogage pour l’équipe.
- Les messages sont compréhensibles sans exposer de détails d’implémentation
- Le texte de repli reste sûr lorsque l’erreur backend est absente ou mal formée
- La journalisation reste utile au débogage sans divulguer de valeurs sensibles dans l’UI
Workflow de débogage et support
Le support peut s’appuyer sur un chemin de résolveur cohérent, puis examiner les journaux Phantom Wing pour le détail technique complet si nécessaire.
- L’utilisateur voit un message normalisé
- Phantom Wing enregistre en privé le contexte complet de l’erreur
- Le support peut corréler la classe de problème sans exposer la réponse backend brute
Tests et assurance qualité
La logique de normalisation est couverte par des tests de module ciblés et par des vérifications d’intégration sur les principaux flux frontend.
Maintenance et extensions futures
À mesure que PayCal ajoute d’autres modules, le même modèle de résolveur doit être réutilisé plutôt que de dupliquer un formatage d’erreur personnalisé.
- Les nouveaux modules doivent appeler directement le résolveur partagé
- Les messages de repli spécifiques au module doivent rester courts et orientés utilisateur
- Tout changement du résolveur doit être testé en régression sur des flux représentatifs
Cela garde le comportement prévisible à mesure que la base de code grandit et évite une deuxième génération de gestion d’erreur spécifique aux modules.
Résumé : la norme de gestion d’erreurs PayCal
PayCal a standardisé la gestion des erreurs frontend afin que les utilisateurs obtiennent des messages sûrs et cohérents tandis que les développeurs reçoivent les informations nécessaires au débogage.
- Normaliser les messages d’erreur avant affichage
- Masquer les détails d’implémentation aux utilisateurs
- Utiliser un texte de repli explicite pour les erreurs vides ou mal formées
- Consigner en privé les détails techniques pour le support et le débogage