# Plan Complet de Correction des Bugs - Memento/Keep
**Date:** 2026-01-15
**Version:** 1.0
**Statut:** Prêt pour correction

---

## RÉSUMÉ EXÉCUTIF

**Bugs Critiques Confirmés par Tests Playwright:** 3
**Bugs Critiques Identifiés par Analyse de Code:** 5
**Bugs High Priorité:** 0
**Total Bugs à Corriger:** 8

---

## PRIORITÉS DE CORRECTION

### 🔴 CRITIQUE (Doit être corrigé immédiatement)
1. **TriggerRefresh ne fonctionne pas** - Confirmé par tests
2. **Refresh excessif router.refresh()** - Cause flash et perte de scroll
3. **Reload complet window.location.reload()** - Force page reload complète
4. **Mobile drag non fonctionnel** - Muuri incompatible avec touch

### 🟡 HIGH (Corriger rapidement)
5. **Doublons boutons fermeture** - Confusion UI
6. **Performance re-renders** - useEffect mal gérés

---

## DÉTAIL DES CORRECTIONS PAR BUG

### 🔴 Bug #1: triggerRefresh() Non Fonctionnel

**Confirmation par tests:**
- `bug-move-direct.spec.ts` ligne 168-174
- `bug-note-move-refresh.spec.ts` ligne 105-109, 123-136
- Les tests confirment: "triggerRefresh() didn't work!"

**Cause Racine:**
```typescript
// keep-notes/context/NoteRefreshContext.tsx
const NoteRefreshContext = createContext<NoteRefreshContextType | undefined>(undefined)

export function NoteRefreshProvider({ children }: { children: React.ReactNode }) {
  const [refreshKey, setRefreshKey] = useState(0)

  const triggerRefresh = useCallback(() => {
    setRefreshKey(prev => prev + 1)  // ❌ INCORRECT! Ne déclenche pas de re-render global
  }, [refreshKey])  // ❌ DÉPENDANCE INCORRECT!

  return (
    <NoteRefreshContext.Provider value={{ refreshKey, triggerRefresh }}>
      {children}
    </NoteRefreshContext.Provider>
  )
}
```

**Correction:**
```typescript
// CORRECT: utiliser useRef pour éviter les cycles de dépendances
export function NoteRefreshProvider({ children }: { children: React.ReactNode }) {
  const [refreshKey, setRefreshKey] = useState(0)
  const refreshKeyRef = useRef(refreshKey)

  const triggerRefresh = useCallback(() => {
    const newKey = refreshKeyRef.current + 1
    refreshKeyRef.current = newKey
    setRefreshKey(newKey)  // ✅ Déclenche le re-render
  }, [])  // ✅ Pas de dépendances

  return (
    <NoteRefreshContext.Provider value={{ refreshKey, triggerRefresh }}>
      {children}
    </NoteRefreshContext.Provider>
  )
}
```

**Fichiers à modifier:**
- `keep-notes/context/NoteRefreshContext.tsx`

---

### 🔴 Bug #2: router.refresh() Excessif

**Fichiers affectés:**
- `keep-notes/components/note-card.tsx` (lignes 200, 208, 216, 224, 235)
- `keep-notes/app/(main)/page.tsx` (lignes 171, 185)

**Cause Racine:**
```typescript
// Chaque action déclenche un refresh complet de la page
const handleTogglePin = async () => {
  startTransition(async () => {
    addOptimisticNote({ isPinned: !note.isPinned })
    await togglePin(note.id, !note.isPinned)
    router.refresh()  // ❌ FORCE RELOAD COMPLET
  })
}
```

**Correction:**
```typescript
// CORRECT: Supprimer router.refresh() et laisser le state React se mettre à jour
const handleTogglePin = async () => {
  addOptimisticNote({ isPinned: !note.isPinned })
  await togglePin(note.id, !note.isPinned)
  // ✅ Pas de refresh - l'état optimiste gère l'UI
}
```

**Fichiers à modifier:**
- `keep-notes/components/note-card.tsx`
- `keep-notes/app/(main)/page.tsx`

---

### 🔴 Bug #3: window.location.reload() dans notebooks-context.tsx

**Fichier affecté:**
- `keep-notes/context/notebooks-context.tsx` (lignes 141, 154, 169)

**Cause Racine:**
```typescript
// Création, mise à jour, suppression de notebook déclenche un reload complet
const updateNotebook = async (notebookId: string, data: UpdateNotebookInput) => {
  const response = await fetch(`/api/notebooks/${notebookId}`, {
    method: 'PATCH',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(data),
  })

  if (!response.ok) {
    throw new Error('Failed to update notebook')
  }

  // Recharger les notebooks après mise à jour
  window.location.reload()  // ❌ FORCE RELOAD COMPLET
}
```

**Correction:**
```typescript
// CORRECT: Utiliser triggerRefresh() à la place
const updateNotebook = async (notebookId: string, data: UpdateNotebookInput) => {
  const response = await fetch(`/api/notebooks/${notebookId}`, {
    method: 'PATCH',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(data),
  })

  if (!response.ok) {
    throw new Error('Failed to update notebook')
  }

  // ✅ Rafraîchissement optimiste du state React
  triggerRefresh()
}
```

**Fichiers à modifier:**
- `keep-notes/context/notebooks-context.tsx`

---

### 🔴 Bug #4: Mobile Drag Non Fonctionnel

**Fichier affecté:**
- `keep-notes/components/masonry-grid.tsx` (lignes 160-185)

**Cause Racine:**
```typescript
// Détection mobile insuffisante
const isMobile = window.matchMedia('(pointer: coarse)').matches;

// Configuration Muuri avec dragHandle qui conflict avec touch events
const layoutOptions = {
  dragEnabled: true,
  dragHandle: '.muuri-drag-handle',  // ❌ Problématique sur mobile
  dragContainer: document.body,
  dragStartPredicate: {
    distance: 10,
    delay: 0,
  },
  // ...
}
```

**Correction:**
```typescript
// CORRECT 1: Désactiver drag sur mobile
const isMobile = window.innerWidth < 768;  // ✅ Détection fiable
const isTouchDevice = 'ontouchstart' in window;  // ✅ Détection fiable

const layoutOptions = {
  dragEnabled: !isMobile && !isTouchDevice,  // ✅ Désactiver sur mobile
  dragHandle: isMobile ? undefined : '.muuri-drag-handle',  // ✅ Pas de handle sur mobile
  // ...
}
```

**Correction Alternative (Recommandée):**
```typescript
// CORRECT 2: Utiliser @dnd-kit/core qui supporte nativement le touch
// Remplacer Muuri par @dnd-kit/core
import { DndContext, DndProvider } from '@dnd-kit/core'

// Ceci résoudra définitivement les problèmes de mobile drag
```

**Fichiers à modifier:**
- `keep-notes/components/masonry-grid.tsx`
- Éventuellement: `package.json` (si changement de librairie)

---

### 🟡 Bug #5: Doublons Boutons Fermeture

**Fichier affecté:**
- `keep-notes/components/note-card.tsx` (lignes 351-357, 411-413)

**Cause Racine:**
```typescript
// Bouton "Leave Share" avec icône X
<Button onClick={handleLeaveShare}>
  <X className="h-3 w-3 mr-1" />
  Leave Share
</Button>

// Bouton "Remove Fused Badge" avec icône X
<button onClick={handleRemoveFusedBadge}>
  <X className="h-2.5 w-2.5" />
  Remove
</button>
```

**Correction:**
```typescript
// CORRECT: Utiliser des icônes différentes pour chaque action
import { X, Trash2, FolderOpen, LogOut } from 'lucide-react'

// Bouton "Remove Fused Badge" - utiliser icône différente
<button onClick={handleRemoveFusedBadge}>
  <Trash2 className="h-2.5 w-2.5 text-purple-600" />
  <span className="ml-2">Remove</span>
</button>

// Bouton "Leave Share" - utiliser icône différente
<Button onClick={handleLeaveShare}>
  <LogOut className="h-3 w-3 mr-1 text-blue-600" />
  Leave Share
</Button>
```

**Fichiers à modifier:**
- `keep-notes/components/note-card.tsx`

---

### 🟡 Bug #6: Re-renders Inutiles (Performance)

**Fichiers affectés:**
- `keep-notes/components/note-card.tsx` (lignes 151-154, 162-180)
- `keep-notes/hooks/use-debounce.ts` (lignes 6-14)

**Cause Racine #1: useDebounce mal implémenté**
```typescript
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 render
  // ❌ Même si value ne change pas, l'effet se recrée
  // ❌ Provoque des cascades de re-renders

  return debouncedValue
}
```

**Cause Racine #2: useEffect mal géré**
```typescript
useEffect(() => {
  const loadCollaborators = async () => {
    // ...
  }

  loadCollaborators()
}, [note.id, note.userId])  // ❌ Se déclenche trop souvent
// ❌ Même si les collaborateurs n'ont pas changé
// ❌ Provoque des cascades de re-renders
```

**Correction #1:**
```typescript
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])  // ✅ Recrée uniquement quand value change

  return debouncedValue
}
```

**Correction #2:**
```typescript
useEffect(() => {
  const loadCollaborators = async () => {
    // ...
  }

  loadCollaborators()
}, [note.id, note.userId, isOwner, isSharedNote])  // ✅ Dépendances complètes
// ✅ Se déclenche uniquement quand une de ces valeurs change vraiment
```

**Fichiers à modifier:**
- `keep-notes/hooks/use-debounce.ts`
- `keep-notes/components/note-card.tsx`

---

## ORDRE DES CORRECTIONS RECOMMANDÉ

### Phase 1: Critique (Doit être corrigé immédiatement)
1. **Corriger triggerRefresh()** - Bug #1
2. **Supprimer router.refresh()** - Bug #2
3. **Supprimer window.location.reload()** - Bug #3
4. **Corriger mobile drag** - Bug #4

### Phase 2: High (Corriger rapidement)
5. **Doublons boutons** - Bug #5
6. **Performance re-renders** - Bug #6

### Phase 3: Validation (Tests)
7. **Rejouer tous les tests** pour confirmer les corrections
8. **Tests manuels** pour vérifier chaque bug corrigé

---

## INSTRUCTIONS D'EXÉCUTION

### Étape 1: Sauvegarder l'état actuel
```bash
git add .
git commit -m "Backup avant correction des bugs"
```

### Étape 2: Corriger Bug #1 (triggerRefresh)
**Fichier:** `keep-notes/context/NoteRefreshContext.tsx`
1. Remplacer l'implémentation actuelle
2. Tester avec les tests Playwright existants
3. Confirmer que triggerRefresh fonctionne

### Étape 3: Corriger Bug #2 (router.refresh excessif)
**Fichiers:** 
- `keep-notes/components/note-card.tsx`
- `keep-notes/app/(main)/page.tsx`

1. Supprimer tous les appels à `router.refresh()`
2. Laisser l'état optimiste gérer l'UI
3. Tester que les actions se font sans refresh

### Étape 4: Corriger Bug #3 (window.location.reload())
**Fichier:** `keep-notes/context/notebooks-context.tsx`
1. Remplacer tous les `window.location.reload()` par `triggerRefresh()`
2. Tester que les actions sur notebooks se font sans reload complet

### Étape 5: Corriger Bug #4 (Mobile drag)
**Fichier:** `keep-notes/components/masonry-grid.tsx`

**Option A (Simple):**
1. Désactiver drag sur mobile
2. Améliorer la détection mobile

**Option B (Recommandée):**
1. Remplacer Muuri par @dnd-kit/core
2. Implémenter un drag handler mobile-friendly

### Étape 6: Corriger Bug #5 (Doublons boutons)
**Fichier:** `keep-notes/components/note-card.tsx`
1. Remplacer les icônes X par des icônes spécifiques
2. Ajouter des tooltips explicites
3. Utiliser des couleurs sémantiques

### Étape 7: Corriger Bug #6 (Performance)
**Fichiers:**
- `keep-notes/hooks/use-debounce.ts`
- `keep-notes/components/note-card.tsx`

1. Corriger useDebounce avec useRef
2. Corriger les dépendances useEffect
3. Utiliser useMemo pour éviter les recréations

### Étape 8: Validation
```bash
# Rejouer tous les tests
npx playwright test tests/bug-*.spec.ts

# Tests manuels
1. Ouvrir l'application
2. Créer une note
3. Toggle pin, archive, color
4. Vérifier: pas de flash, pas de perte de scroll
5. Déplacer la note vers un notebook
6. Vérifier: la note disparaît de la page principale
7. Sur mobile: tester le drag and drop
8. Vérifier: pas de bugs de scroll sur mobile
```

---

## CRITÈRES DE VALIDATION

### Pour chaque bug corrigé:
- ✅ Le bug ne se produit plus
- ✅ Aucun effet secondaire indésirable
- ✅ Les tests Playwright passent
- ✅ Performance améliorée (mesurable)
- ✅ Code propre et bien documenté

### Pour l'application entière:
- ✅ Aucun flash d'écran inutile
- ✅ Aucune perte de scroll
- ✅ Drag and drop fonctionne sur desktop
- ✅ Drag and drop fonctionne/ou est désactivé proprement sur mobile
- ✅ Toutes les actions UI sont optimistes
- ✅ L'UI reste réactive sans re-renders inutiles

---

## SUITE APRÈS CORRECTIONS

### Améliorations UX:
1. **Animations fluides** lors des actions
2. **Feedback visuel** (loading states, success toasts)
3. **Indicateurs de progression** pour les actions longues
4. **Undo/Redo** pour les actions destructrices

### Améliorations Mobile:
1. **Touch gestures** pour swipe actions
2. **Pull-to-refresh** pour synchronisation
3. **Double-tap** pour quick actions
4. **Responsive design** amélioré

### Améliorations Techniques:
1. **Optimisation des re-renders** (React.memo, useMemo, useCallback)
2. **Lazy loading** des composants lourds
3. **Virtual scrolling** pour les grandes listes de notes
4. **Code splitting** pour réduire la taille du bundle

---

## RISQUES ET ATTENTIONS

### Risques:
- **Casser des fonctionnalités existantes** en modifiant le state
- **Introduction de nouveaux bugs** pendant la correction
- **Régression** de bugs déjà corrigés

### Atténuations:
- Faire les corrections une par une avec validation
- Commencer par les bugs critiques les plus simples
- Tester minutieusement après chaque correction
- Avoir un plan de rollback prêt

---

## DOCUMENTS DE RÉFÉRENCE

- Analyse complète: `_bmad-output/BUG-ANALYSIS-REPORT.md`
- Tests Playwright: `keep-notes/tests/bug-*.spec.ts`
- Documentation existante: `docs/` (à mettre à jour après corrections)

---

## TIMELINE ESTIMÉE

**Phase 1 (Critique):** 2-4 heures
**Phase 2 (High):** 1-2 heures
**Phase 3 (Validation):** 1-2 heures
**Total estimé:** 4-8 heures

**Note:** Les corrections sont relativement simples car les bugs sont bien localisés et documentés.

---

## STATUT

**État:** ✅ Prêt pour l'exécution
**Fichiers à modifier:** 6 fichiers principaux
**Bugs à corriger:** 8
**Tests à rejouer:** 3 tests Playwright

---

*Ce plan doit être exécuté après validation par le développeur.*
