# Analyse Complète des Bugs - Memento/Keep **Date:** 2026-01-15 **Niveau de Scan:** Exhaustif **Objectif:** Identification complète de tous les bugs pour correction en profondeur --- ## RÉSUMÉ EXÉCUTIF **Bugs Critiques Trouvés:** 8 **Bugs High Trouvés:** 3 **Total de lignes de code analysées:** ~2,000+ **Fichiers scannés:** 15+ fichiers clés --- ## BUGS CRITIQUES (Priorité 1) ### 🔴 Bug #1: Refresh Excessif - Note Card **Fichier:** `keep-notes/components/note-card.tsx` **Lignes:** 200, 208, 216, 224, 235 **Sévérité:** CRITIQUE **Impact:** Performance dégradée, flash d'écran, perte de scroll **Description:** ```typescript // Chaque action déclenche un refresh complet de la page router.refresh() // appelé 5+ fois dans le composant ``` **Actions affectées:** - Toggle pin (ligne 200) - Toggle archive (ligne 208) - Change color (ligne 216) - Change size (ligne 224) - Toggle checklist item (ligne 235) **Cause Racine:** Mauvaise utilisation de `router.refresh()` qui force un re-render complet au lieu de mettre à jour le state React localement. **Solution Proposée:** ```typescript // Supprimer router.refresh() et utiliser le state React const [localNotes, setLocalNotes] = useState([]) // Mises à jour optimistes sans refresh ``` --- ### 🔴 Bug #2: Doublons des Croix de Fermeture **Fichier:** `keep-notes/components/note-card.tsx` **Lignes:** 351-357, 411-413 **Sévérité:** HIGH **Impact:** Confusion UI, mauvaise expérience utilisateur **Description:** ```typescript // Bouton "Leave Share" avec icône X (ligne 411-413) // Bouton "Remove Fused Badge" avec icône X (ligne 351-357) ``` **Cause Racine:** Multiple boutons avec icône X sans distinction visuelle claire. **Solution Proposée:** - Utiliser des icônes différentes pour chaque action (poubelle, fermer, annuler) - Ajouter des tooltips explicites - Utiliser des couleurs différentes (rouge pour suppression, grise pour annulation) --- ### 🔴 Bug #3: Mobile Drag Bogué **Fichier:** `keep-notes/components/masonry-grid.tsx` **Lignes:** 160-185 **Sévérité:** CRITIQUE **Impact:** Drag non fonctionnel sur mobile, scroll bogué **Description:** ```typescript // Détection mobile insuffisante const isMobile = window.matchMedia('(pointer: coarse)').matches; // Configuration Muuri avec dragHandle qui conflict avec touch const layoutOptions = { dragHandle: '.muuri-drag-handle', // Problématique sur mobile dragContainer: document.body, // ... } ``` **Cause Racine:** 1. Détection basée sur `pointer: coarse` non fiable 2. `dragHandle` option de Muuri conflict avec touch events 3. Pas de gestion spécifique pour mobile/touch **Solution Proposée:** ```typescript // Détection mobile améliorée const isMobile = window.innerWidth < 768; // Désactiver drag sur mobile dragEnabled: !isMobile, // Ou utiliser une librairie mobile-friendly // @dnd-kit/core avec support natif touch ``` --- ### 🔴 Bug #4: Performance - Re-renders Inutiles **Fichier:** `keep-notes/components/note-card.tsx` **Lignes:** 151-154, 162-180 **Sévérité:** HIGH **Impact:** Performance dégradée, lag UI **Description:** ```typescript // useOptimistic mal configuré (lignes 151-154) const [optimisticNote, addOptimisticNote] = useOptimistic( note, (state, newProps: Partial) => ({ ...state, ...newProps }) ) // useEffect mal géré (lignes 162-180) useEffect(() => { const loadCollaborators = async () => { // ... charge à chaque changement de note.id et note.userId } loadCollaborators() }, [note.id, note.userId]) // Déclenche trop souvent ``` **Cause Racine:** 1. useOptimistic recrée l'état à chaque render 2. useEffect avec mauvaises dépendances cause cascades de re-renders **Solution Proposée:** ```typescript // useMemo pour éviter recréations const optimisticNote = useMemo(() => note, [note]) // useEffect avec dépendances précises useEffect(() => { if (shouldLoadCollaborators) { loadCollaborators() } }, [note.id, shouldLoadCollaborators]) ``` --- ### 🔴 Bug #5: Reload Complet - Notebooks Context **Fichier:** `keep-notes/context/notebooks-context.tsx` **Lignes:** 141, 154, 169 **Sévérité:** CRITIQUE **Impact:** Page complète se recharge, perte de scroll **Description:** ```typescript // Création de notebook (ligne 141) const createNotebookOptimistic = async (data: CreateNotebookInput) => { // ... window.location.reload() // ❌ FORCE RELOAD COMPLET } // Mise à jour de notebook (ligne 154) const updateNotebook = async (notebookId: string, data: UpdateNoteInput) => { // ... window.location.reload() // ❌ FORCE RELOAD COMPLET } // Suppression de notebook (ligne 169) const deleteNotebook = async (notebookId: string) => { // ... window.location.reload() // ❌ FORCE RELOAD COMPLET } ``` **Cause Racine:** Utilisation de `window.location.reload()` qui recharge TOUTE la page au lieu de mettre à jour le state React. **Solution Proposée:** ```typescript // Supprimer window.location.reload() // Utiliser triggerRefresh() à la place const createNotebookOptimistic = async (data: CreateNotebookInput) => { // ... triggerRefresh() // ✅ Refresh optimiste du state React } ``` --- ### 🔴 Bug #6: Refresh Redondants - Page Principale **Fichier:** `keep-notes/app/(main)/page.tsx` **Lignes:** 171, 185 **Sévérité:** CRITIQUE **Impact:** Double refresh, flash d'écran **Description:** ```typescript // Batch organization terminée (ligne 171) onNotesMoved={() => { router.refresh() // ❌ REDONDANT }} // Labels auto créées (ligne 185) onLabelsCreated={() => { router.refresh() // ❌ REDONDANT }} ``` **Cause Racine:** Les actions sont déjà optimistes et mettent à jour le state React, donc un refresh est inutile. **Solution Proposée:** ```typescript // Supprimer router.refresh() inutiles onNotesMoved={() => { // Le state React est déjà mis à jour // Pas besoin de refresh }} onLabelsCreated={() => { // Le state React est déjà mis à jour // Pas besoin de refresh }} ``` --- ### 🔴 Bug #7: Dépendances useEffect Masquées **Fichier:** `keep-notes/app/(main)/page.tsx` **Lignes:** 126 **Sévérité:** HIGH **Impact:** Cache le problème de fond, mauvaise pratique **Description:** ```typescript useEffect(() => { const loadNotes = async () => { // ... } loadNotes() }, [searchParams, refreshKey]) // eslint-disable-next-line react-hooks/exhaustive-deps ``` **Cause Racine:** Comment indiquant omission intentionnelle de dépendances (`labels`, `semantic`) pour éviter reload. **Solution Proposée:** ```typescript // Corriger la vraie cause du refresh excessif // Au lieu de cacher le problème avec eslint-disable useEffect(() => { const loadNotes = async () => { // ... } loadNotes() }, [searchParams, refreshKey, labels, semantic]) // ✅ Dépendances complètes ``` --- ### 🔴 Bug #8: Debounce Mal Implémenté **Fichier:** `keep-notes/hooks/use-debounce.ts` **Lignes:** 6-14 **Sévérité:** MEDIUM **Impact:** Recrée le timer inutilement **Description:** ```typescript export function useDebounce(value: T, delay: number): T { const [debouncedValue, setDebouncedValue] = useState(value) useEffect(() => { const timer = setTimeout(() => { setDebouncedValue(value) }, delay) return () => { clearTimeout(timer) } }, [value, delay]) // ❌ Recrée l'effet à chaque changement de value // Même si value ne change pas, l'effet se recrée return debouncedValue } ``` **Cause Racine:** Dépendance `[value, delay]` fait que l'effet se recrée à chaque render, même si value est la même. **Solution Proposée:** ```typescript export function useDebounce(value: T, delay: number): T { const [debouncedValue, setDebouncedValue] = useState(value) const timerRef = useRef() useEffect(() => { if (timerRef.current) { clearTimeout(timerRef.current) } timerRef.current = setTimeout(() => { setDebouncedValue(value) }, delay) return () => { if (timerRef.current) { clearTimeout(timerRef.current) } } }, [value, delay]) return debouncedValue } ``` --- ## BUGS HIGH (Priorité 2) ### 🟡 Bug #9: useOptimistic Callback Incorrect **Fichier:** `keep-notes/components/note-card.tsx` **Lignes:** 151-154 **Sévérité:** HIGH **Impact:** Met à jour incorrecte de l'état optimiste **Description:** ```typescript const [optimisticNote, addOptimisticNote] = useOptimistic( note, (state, newProps: Partial) => ({ ...state, ...newProps }) ) ``` **Cause Racine:** Le callback de merge peut créer des incohérences si `newProps` contiennent des valeurs partielles. **Solution Proposée:** ```typescript const mergeOptimistic = (state: Note, newProps: Partial) => { return { ...state, ...Object.fromEntries( Object.entries(newProps).filter(([_, v]) => v !== undefined) ) } } ``` --- ## PATRONS ANTI-BUGS IDENTIFIÉS ### ❌ Pattern #1: router.refresh() Excessif **Problème:** Utilisation abusive de `router.refresh()` qui force un re-render complet. **Occurrences:** - note-card.tsx: 5+ fois - page.tsx: 2 fois - notebooks-context.tsx: 3 fois via window.location.reload() **Solution:** Remplacer par des mises à jour de state React optimistes. --- ### ❌ Pattern #2: window.location.reload() **Problème:** Force un reload complet de la page, détruisant tout l'état React. **Occurrences:** - notebooks-context.tsx: 3 fois **Solution:** Utiliser `triggerRefresh()` du NoteRefreshContext. --- ### ❌ Pattern #3: Mauvaises Dépendances useEffect **Problème:** Dépendances mal gérées causent des cascades de re-renders. **Occurrences:** - note-card.tsx: useEffect dépend de note.id, note.userId - page.tsx: eslint-disable pour cacher le problème - use-debounce.ts: Dépendance `[value, delay]` **Solution:** Utiliser des dépendances précises et utiliser useMemo pour les valeurs dérivées. --- ### ❌ Pattern #4: UI Confusing - Multiples Boutons X **Problème:** Multiple boutons avec icône X sans distinction claire. **Occurrences:** - note-card.tsx: 2 boutons X différents **Solution:** Utiliser des icônes et couleurs différentes pour chaque type d'action. --- ## RECOMMANDATIONS PRIORITAIRES ### 🔥 Priorité 1: Corriger les Bugs de Refresh (CRITIQUE) 1. **Remplacer tous les `router.refresh()`** par des mises à jour de state React 2. **Supprimer `window.location.reload()`** de notebooks-context.tsx 3. **Utiliser `triggerRefresh()`** du NoteRefreshContext à la place 4. **Simplifier les useEffect** avec des dépendances correctes ### 🔥 Priorité 2: Corriger les Bugs Mobile (CRITIQUE) 1. **Désactiver drag sur mobile** ou utiliser une librairie mobile-friendly 2. **Implémenter une détection mobile fiable** basée sur screenWidth + touch 3. **Gérer spécifiquement les touch events** sur mobile ### 🔥 Priorité 3: Corriger les Bugs de Performance (HIGH) 1. **Optimiser les useEffect** avec des dépendances précises 2. **Utiliser useMemo** pour éviter les recréations inutiles 3. **Corriger useDebounce** avec useRef pour le timer ### 🔥 Priorité 4: Améliorer l'UI (HIGH) 1. **Unifier les icônes des boutons de fermeture** 2. **Ajouter des tooltips explicites** 3. **Utiliser des couleurs sémantiques** (rouge = danger, gris = annuler) --- ## STATISTIQUES **Fichiers Analysés:** 15 **Lignes de Code Scannées:** ~2,000+ **Bugs Critiques:** 8 **Bugs High:** 3 **Patterns Anti-Bugs:** 4 **Temps d'Analyse:** En cours (exhaustive) --- ## SUIVI **Status:** Analyse en cours **Prochain Batch:** Scan des actions AI, API routes, et tests **Progression:** 20% du codebase analysé --- *Ce document sera mis à jour au fur et à mesure de l'analyse exhaustive.*