ADR 0009 : Système de logging centralisé avec priorités et persistance Supabase
- Statut : Accepté (le 9 juillet 2026, à la clôture du Sprint 06 - logger livré des deux côtés, table
app_logscréée) - Décideurs : Seer MENSAH-ASSIAKOLEY (Développeur)
- Date : 9 juillet 2026
Contexte et Problème
Actuellement, l'application ne dispose pas d'un système de journalisation unifié permettant de suivre les événements critiques, les requêtes réseau et les erreurs dans un format structuré et persistant. Le débogage et le suivi des incidents en production sont donc difficiles, d'autant plus que les données de session d'authentification restent strictement locales au navigateur.
Julien souhaite un système de logger complet, inspiré du fonctionnement robuste de Java (loggers hiérarchiques par package/namespace, niveaux de priorité) et de Winston/Morgan sous Node.js, facilement reproductible sur toutes ses applications React. Ce système doit également s'intégrer dans tous les appels et requêtes API et stocker ces logs dans une table Supabase accessible de manière sécurisée.
Facteurs de Décision
- Priorités de logs : Support des niveaux de sévérité standard (
TRACE,DEBUG,INFO,WARN,ERROR,FATAL). - Héritage hiérarchique : Pouvoir configurer le niveau de verbosité globalement ou par module (ex: passer
services.authenDEBUGtout en gardant le reste de l'application enWARN). - Structure des logs : Chaque log doit enregistrer un message simple (
message), une description détaillée ou stack d'erreur (description), un horodatage (timestamp/created_at), ainsi que le contexte utilisateur (user_id). - Persistance de fichier et BDD :
- Côté navigateur : Stockage dans un buffer en mémoire avec option de téléchargement sous forme de fichier
.log. - Côté base de données : Synchronisation automatique des logs critiques dans une table publique Supabase
public.app_logs.
- Côté navigateur : Stockage dans un buffer en mémoire avec option de téléchargement sous forme de fichier
- Zéro boucle infinie : Les requêtes d'envoi de logs vers Supabase ne doivent pas s'auto-journaliser (risque d'appel récursif infini).
- Performance : Limiter la charge réseau en filtrant/filtrant par lot les logs envoyés en base (ex: uniquement
INFOet plus).
Options Envisagées
Option A : Utilisation de Winston côté client (via polyfills) et Morgan côté serveur
Winston est puissant pour Node.js mais lourd et non adapté nativement au navigateur (nécessite des polyfills Webpack/Vite pour les modules Node fs, path, etc.).
- Avantage : Même API des deux côtés.
- Inconvénient : Augmente drastiquement la taille du bundle frontend, difficile à faire fonctionner avec Vite, pas de support natif pour le téléchargement de fichier en navigateur ou l'intégration Supabase RLS.
Option B : Logger sur mesure pour React (logger.js) + Configuration Winston/Morgan pour Node (logger.server.js)
On conçoit un module de logging autonome en JS/TS pur pour React avec une interface inspirée de Java (LoggerFactory.getLogger('Name')), supportant les namespaces hiérarchiques, l'écriture en base via Supabase, et un export fichier natif. Côté serveur Node, on utilise la configuration Winston/Morgan standard pour conserver les meilleures pratiques de chaque environnement.
- Avantage : Zéro dépendance sur le frontend (léger), parfaitement adapté aux contraintes du navigateur (stockage en mémoire, téléchargement HTML5 de fichier
.log), et flexible pour cibler Supabase. - Inconvénient : Nécessite l'écriture du module de base sur mesure.
Décision Retenue
L'Option B a été retenue. Nous allons créer un logger autonome côté React (src/utils/logger.js) et configurer Winston/Morgan pour le backend.
Justification
Cette option garantit la légèreté de l'application frontend tout en offrant un comportement proche de Java (namespaces, priorités) et en résolvant élégamment le besoin d'un "fichier de log" dans le navigateur grâce au buffer téléchargeable. L'intégration Supabase s'effectue via un SupabaseTransport dédié et filtré pour éviter les surcharges.
Structure des logs (Schéma)
Chaque log généré par le système contiendra les informations suivantes :
| Champ | Type | Description |
|---|---|---|
timestamp / created_at |
timestamptz |
Date et heure de l'événement (généré automatiquement). |
level |
text |
Niveau de priorité (TRACE, DEBUG, INFO, WARN, ERROR, FATAL). |
category |
text |
Namespace du logger (ex: network.fetch, services.auth, components.TaskDetail). |
message |
text |
Message simple et court de résumé (ex: Connexion utilisateur réussie). |
description |
text |
Détails supplémentaires (paramètres de requête, corps de réponse, stack trace d'erreur). |
payload |
jsonb |
Données brutes optionnelles (payload de requête, détails d'erreur). |
user_id |
uuid |
Identifiant du membre Supabase connecté (si disponible). |
browser_info |
jsonb |
Métadonnées système (User Agent, URL courante, résolution d'écran). |
Mesures de Sécurité (RLS Supabase)
La table public.app_logs sera protégée par Row Level Security (RLS) :
- INSERT : Autorisé publiquement pour permettre à n'importe quel client (anonyme ou connecté) de signaler une erreur ou un événement.
- SELECT : Restreint aux utilisateurs ayant le rôle
super_managerdans la tablepublic.member. - UPDATE / DELETE : Complètement bloqués pour tout le monde afin de garantir que les journaux soient immuables et infalsifiables.
