12 KiB
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:
// 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:
// Supprimer router.refresh() et utiliser le state React
const [localNotes, setLocalNotes] = useState<Note[]>([])
// 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:
// Bouton "Leave Share" avec icône X (ligne 411-413)
<Button onClick={handleLeaveShare}>
<X className="h-3 w-3 mr-1" />
Leave Share
</Button>
// Bouton "Remove Fused Badge" avec icône X (ligne 351-357)
<button onClick={handleRemoveFusedBadge}>
<X className="h-2.5 w-2.5" />
Remove
</button>
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:
// 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:
- Détection basée sur
pointer: coarsenon fiable dragHandleoption de Muuri conflict avec touch events- Pas de gestion spécifique pour mobile/touch
Solution Proposée:
// 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:
// useOptimistic mal configuré (lignes 151-154)
const [optimisticNote, addOptimisticNote] = useOptimistic(
note,
(state, newProps: Partial<Note>) => ({ ...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:
- useOptimistic recrée l'état à chaque render
- useEffect avec mauvaises dépendances cause cascades de re-renders
Solution Proposée:
// 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:
// 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:
// 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:
// 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:
// 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:
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:
// 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:
export function useDebounce<T>(value: T, delay: number): T {
const [debouncedValue, setDebouncedValue] = useState<T>(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:
export function useDebounce<T>(value: T, delay: number): T {
const [debouncedValue, setDebouncedValue] = useState<T>(value)
const timerRef = useRef<NodeJS.Timeout>()
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:
const [optimisticNote, addOptimisticNote] = useOptimistic(
note,
(state, newProps: Partial<Note>) => ({ ...state, ...newProps })
)
Cause Racine:
Le callback de merge peut créer des incohérences si newProps contiennent des valeurs partielles.
Solution Proposée:
const mergeOptimistic = (state: Note, newProps: Partial<Note>) => {
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)
- Remplacer tous les
router.refresh()par des mises à jour de state React - Supprimer
window.location.reload()de notebooks-context.tsx - Utiliser
triggerRefresh()du NoteRefreshContext à la place - Simplifier les useEffect avec des dépendances correctes
🔥 Priorité 2: Corriger les Bugs Mobile (CRITIQUE)
- Désactiver drag sur mobile ou utiliser une librairie mobile-friendly
- Implémenter une détection mobile fiable basée sur screenWidth + touch
- Gérer spécifiquement les touch events sur mobile
🔥 Priorité 3: Corriger les Bugs de Performance (HIGH)
- Optimiser les useEffect avec des dépendances précises
- Utiliser useMemo pour éviter les recréations inutiles
- Corriger useDebounce avec useRef pour le timer
🔥 Priorité 4: Améliorer l'UI (HIGH)
- Unifier les icônes des boutons de fermeture
- Ajouter des tooltips explicites
- 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.