Files
Momento/memento-note/docs/brainstorm-documentation.md
Antigravity 1fcea6ed7d
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 7s
feat: brainstorm sessions, PDF document Q&A, embedding fixes, and UI improvements
- Add brainstorm feature with collaborative canvas, AI idea generation, live cursors, playback, and export
- Add PDF upload/extraction/ingestion pipeline with pgvector document search (RAG)
- Add document Q&A overlay with streaming chat and PDF preview
- Add note attachments UI with status polling, grid layout, and auto-scroll
- Add task extraction AI tool and agent executor improvements
- Fix NoteEmbedding missing updatedAt column, re-index 66 notes with 1536-dim embeddings
- Fix brainstorm 'Create Note' button: add success toast and redirect to created note
- Fix memory echo notification infinite polling
- Fix chat route to always include document_search tool
- Add brainstorm i18n keys across all 14 locales
- Add socket server for real-time brainstorm collaboration
- Add hierarchical notebook selector and organize notebook dialog improvements
- Add sidebar brainstorm section with session management
- Update prisma schema with brainstorm tables, attachments, and document chunks
2026-05-14 17:43:21 +00:00

535 lines
25 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Brainstorm — Documentation Complète
## Vue d'ensemble
Le brainstorm est un outil de génération d'idées assistée par IA basé sur un graphe radial D3. L'utilisateur saisit une "graine" (seed idea), l'IA génère 9 idées en 3 vagues (Variations, Analogies, Disruptions), et l'utilisateur peut approfondir, dismiss, convertir en note, ou ajouter ses propres idées. Le tout en temps-réel via Socket.io.
---
## Architecture
```
[Browser] ←→ [Next.js API Routes] ←→ [PostgreSQL]
↕ ↕
[Socket.io Client] ←→ [Socket.io Server :3002]
```
- **Frontend** : React + D3.js + React Query + Socket.io Client
- **Backend** : Next.js App Router + Prisma + OpenAI
- **Temps réel** : Socket.io sur le port 3002
---
## Modèles de données (Prisma)
### BrainstormSession
| Champ | Type | Description |
|-------|------|-------------|
| id | String (cuid) | PK |
| seedIdea | String | L'idée graine saisie par l'utilisateur |
| sourceNoteId | String? | FK vers la note source (optionnel) |
| contextNoteIds | String? | JSON string des IDs des notes de contexte |
| exportedNoteId | String? | FK vers la note exportée |
| userId | String | FK vers le propriétaire |
| inviteToken | String? | Token d'invitation unique |
| inviteExpiry | DateTime? | Date d'expiration du token |
| status | String | "active" par défaut |
| Relations | | ideas[], participants[], activities[], shares[] |
### BrainstormIdea
| Champ | Type | Description |
|-------|------|-------------|
| id | String (cuid) | PK |
| sessionId | String | FK vers la session |
| waveNumber | Int | 1, 2 ou 3 |
| title | String | Titre de l'idée |
| description | String | Description détaillée |
| connectionToSeed | String? | Lien avec l'idée graine |
| noveltyScore | Int? | Score de nouveauté (0-100) |
| parentIdeaId | String? | FK vers l'idée parent (auto-référence) |
| convertedToNoteId | String? | FK vers la note créée par conversion |
| relatedNoteIds | String? | JSON string des IDs des notes liées |
| status | String | "active", "dismissed", "converted" |
| positionX | Float? | Position X sur le canvas |
| positionY | Float? | Position Y sur le canvas |
| createdBy | String? | FK vers l'utilisateur créateur |
| createdByType | String | "ai" ou "human" |
| Relations | | session, parentIdea?, children[], noteRefs[], creator? |
### BrainstormNoteRef
| Champ | Type | Description |
|-------|------|-------------|
| id | String (cuid) | PK |
| ideaId | String | FK vers l'idée |
| noteId | String? | FK vers la note (peut être null) |
| relation | String | "derived_from", "opposes", "extends", "synthesizes", "transposes", "none_found" |
| explanation | String | Pourquoi cette note est liée |
| verdict | String | "unresolved", "accepted", "dismissed" |
### BrainstormParticipant
| Champ | Type | Description |
|-------|------|-------------|
| sessionId + userId | Unique | Un user = un rôle par session |
| role | String | "host", "editor", "viewer" |
| joinedAt, lastSeenAt | DateTime | Présence |
### BrainstormActivity
| Champ | Type | Description |
|-------|------|-------------|
| action | String | "wave_generated", "manual_idea", "idea_dismissed", "idea_converted", "joined", "invite_created" |
| details | String? | JSON stringifié |
### BrainstormShare
| Champ | Type | Description |
|-------|------|-------------|
| sessionId + userId | Unique | Un partage par couple session/user |
| sharedBy | String | FK vers l'envoyeur |
| status | String | "pending", "accepted", "declined", "removed" |
| permission | String | "editor", "viewer" |
---
## Pages et URLs
| URL | Description |
|-----|-------------|
| `/brainstorm` | Page principale du brainstorm |
| `/brainstorm?session=<id>` | Ouvrir une session spécifique |
| `/brainstorm?seed=<text>` | Auto-créer un brainstorm avec ce seed |
| `/brainstorm?sourceNoteId=<id>` | Créer depuis une note |
| `/brainstorm?invite=<token>` | Rejoindre via token d'invitation |
---
## API Routes
### `POST /api/brainstorm` — Créer un brainstorm
**Input** : `{ seedIdea, sourceNoteId?, contextNoteIds?, locale? }`
**Processus** :
1. Si pas de `contextNoteIds` → embedding du seed → recherche des 8 notes les plus proches
2. LLM classe chaque note : SUPPORT, TENSION, ou EXTENSION
3. LLM génère 9 idées en 3 vagues :
- **Wave 1 (Variations)** : 3 idées, dont au moins 1 de SUPPORT, 1 répondant à TENSION
- **Wave 2 (Analogies)** : 3 idées, dont au moins 1 d'EXTENSION, 1 transposition de pattern
- **Wave 3 (Disruptions)** : 3 idées, dont au moins 1 inversion de SUPPORT, 1 synthèse de contradictions
4. Chaque idée a : wave, title, description, connectionToSeed, noveltyScore, noteRefs[]
5. Positionnement radial : angle = `(idx % 3) * (2π/3) + (wave-1) * 0.5`, radius = `wave * 150`
6. Crée session + host participant + log activity + 9 idées avec noteRefs
**Retour** : Session complète + `{ support, tension, extension }` counts
### `GET /api/brainstorm` — Lister les sessions de l'utilisateur
**Retour** : `BrainstormSessionListItem[]` (id, seedIdea, totalIdeas, activeIdeas, dates)
### `GET /api/brainstorm/shared` — Sessions partagées acceptées
**Processus** : Fetch shares where userId + accepted, upsert participant si manquant
**Retour** : Même format que la liste + `_isShared: true`
### `GET /api/brainstorm/[sessionId]` — Détail d'une session
**Accès** : Propriétaire OU participant OU share accepted
**Retour** : Session complète avec ideas (ordonnées par wave/date), noteRefs, creator, sourceNote, exportedNote
### `DELETE /api/brainstorm/[sessionId]` — Supprimer une session
**Accès** : Propriétaire uniquement
### `POST /api/brainstorm/[sessionId]/expand` — Approfondir une idée
**Accès** : Propriétaire uniquement
**Input** : `{ ideaId, locale? }`
**Processus** :
1. Charge les noteRefs de l'idée parent + 5 notes via embedding
2. LLM génère 9 sous-idées en 3 vagues relatives au parent
3. Positionnement radial autour du parent
4. Crée les idées avec `parentIdeaId = source idea`
**Retour** : Session mise à jour
### `POST /api/brainstorm/[sessionId]/manual-idea` — Ajouter une idée manuelle
**Accès** : Participant avec rôle editor
**Input** : `{ title, description?, parentIdeaId?, locale? }`
**Processus** :
1. Wave = `min(parent.wave + 1, 3)` si parent, sinon 1
2. Crée l'idée avec `createdBy = userId`, `createdByType = 'human'`
3. Auto-link : embedding → 3 notes les plus proches → BrainstormNoteRef avec relation "extends"
4. **Enrichissement IA** (non-bloquant) : LLM polit le titre, enrichit la description, set noveltyScore. Respecte la locale (`IMPORTANT: You MUST write ALL text in ${lang}`)
**Retour** : Session mise à jour (201)
### `POST /api/brainstorm/[sessionId]/dismiss` — Rejeter une idée
**Accès** : Participant avec rôle editor
**Input** : `{ ideaId }`
**Processus** : Transaction → status = "dismissed" + tous noteRefs verdict = "dismissed"
### `POST /api/brainstorm/[sessionId]/convert` — Convertir en note
**Accès** : Propriétaire uniquement
**Input** : `{ ideaId }`
**Processus** :
1. Crée une Note avec :
- Titre = titre de l'idée
- Contenu = markdown formaté (description, connection, novelty, source brainstorm, noteRefs avec relations)
- Labels = `['brainstorm', 'idée']`
- Même notebook que la note source
2. Transaction : status = "converted", convertedToNoteId = note.id, noteRefs verdict = "accepted", tag les notes référencées avec "brainstorm-fruitful"
**Retour** : Note créée (201)
### `POST /api/brainstorm/[sessionId]/finalize` — Finaliser la session
**Accès** : Propriétaire uniquement
**Processus** :
- Pour chaque note référencée : si tous les refs sont dismissed → tag "brainstorm-dry"
- Compte notesEnriched (≥1 accepted) et notesMarkedDry (all dismissed)
**Retour** : `{ notesSolicited, notesEnriched, notesMarkedDry }`
### `POST /api/brainstorm/[sessionId]/export` — Exporter en note
**Accès** : Propriétaire uniquement
**Processus** :
- Génère un markdown complet : header, summary, sections par wave, notes sollicitées, notes converties
- Crée une Note avec labels `['brainstorm', 'export']`
- Update session.exportedNoteId
**Retour** : Note créée (201)
### `POST /api/brainstorm/[sessionId]/update-position` — Sauvegarder la position d'un nœud
**Input** : `{ ideaId, positionX, positionY }`
### `POST /api/brainstorm/[sessionId]/invite` — Créer une invitation
**Accès** : Host uniquement
**Input** : `{ role, expiresInHours?, email? }`
- Si `email` fourni : trouve l'utilisateur, crée une Notification, retourne `{ mode: 'email' }`
- Sinon : génère un token, retourne `{ mode: 'link', inviteUrl }`
### `POST /api/brainstorm/join` — Rejoindre via token
**Input** : `{ token }`
**Processus** : Vérifie token + expiry → crée BrainstormParticipant → notifie le owner
### `GET /api/brainstorm/[sessionId]/activity` — Feed d'activité
**Retour** : 50 dernières activités avec user info
---
## Server Actions (`app/actions/brainstorm.ts`)
### `createBrainstormShare(sessionId, recipientEmail, permission?)`
Partage par email (même pattern que NoteShare).
1. Vérifie que le user est propriétaire
2. Cherche le recipient par email
3. Gère les cas existants :
- `accepted` → retourne `{ message: 'already_shared' }` (succès info)
- `pending` → retourne `{ message: 'already_pending' }` (succès info)
- `declined/removed` → ré-invite (remet à pending)
4. Sinon → crée un `BrainstormShare` avec status pending
### `respondToBrainstormShare(shareId, action)`
Accepter ou refuser un partage.
- Accept → upsert `BrainstormParticipant` (idempotent)
- Decline → update status
### `getPendingBrainstormShares()`
Retourne les shares pending pour l'utilisateur courant (avec session + sharer info).
### `getAcceptedBrainstormShares()`
Retourne les shares accepted (pour afficher dans la sidebar).
### `removeBrainstormShare(sessionId)`
Passe le share en status "removed".
---
## Interface utilisateur — Page Brainstorm
### Layout global
```
┌──────────────────────────────────────────────────────────────┐
│ HEADER (fixed, border-bottom, backdrop-blur) │
│ [Wind icon] Waves of Thought │
│ "Unfold dimensions of potentiality" │
│ [__________ input seed idea __________] [+] │
│ • • • AI is harvesting seeds of thought... │
├──────────────────────────────────┬─────────────┬────┐ │
│ │ │ │ │
│ CANVAS (D3) │ DETAIL │ S │ │
│ │ PANEL │ I │ │
│ ○ ring 1 │ (400px) │ D │ │
│ ○ ring 2 │ │ E │ │
│ ○ ring 3 │ │ B │ │
│ │ │ A │ │
│ [toolbar flottant en bas] │ │ R │ │
│ │ │ │ │
├──────────────────────────────────┴─────────────┴────┘ │
│ [Activity Feed panel] (slide depuis la droite) │
│ [BrainstormShareDialog] (modal) │
│ [Impact Toast] (fixed bottom center) │
└──────────────────────────────────────────────────────────────┘
```
### Header
- **Icône** : `<Wind>` dans un carré orange qui tourne pendant la génération
- **Titre** : "Waves of Thought" (serif)
- **Sous-titre** : "Unfold dimensions of potentiality" (muted)
- **Input seed** : Grand champ serif italic avec glow gradient au focus
- **Bouton submit** : `<Plus>` icône, positionné à droite dans l'input, disabled si vide ou en génération
- **Indicateur de génération** : 3 points orange pulsants + texte "AI is harvesting seeds of thought..."
### Canvas D3 (WaveCanvas)
#### Éléments visuels
- **Fond** : `#F8F7F2` avec grille de points (20px)
- **3 anneaux** : rayons 200, 400, 600 — traits gris pointillés, opacité 0.5
- **Nœud racine** (seed) :
- Cercle noir (#141414), rayon 40
- Texte "SEED" en blanc, 10px bold
- Label de l'idée graine en serif italic 18px, positionné à y=80
- **Nœuds idée** :
- Cercle blanc avec bordure colorée par wave (orange/blue/violet)
- Rayon 28 (18 si dismissed)
- Texte : titre tronqué à 18 caractères, positionné sous le cercle
- Badges :
- **Converti** : fond vert + checkmark ✓
- **Notes liées** : emoji 📎 en haut-gauche
- **Créé par humain** : cercle bleu avec initiale en haut-droite
- **Créé par IA** : symbole ✦ violet en haut-droite
- **Dismissed** : opacité 0.3
- **Liens** :
- Wave (racine → idée) : gris pointillé, 1.5px
- Parent (idée → sous-idée) : jaune solid, 2px
#### Forces D3
- `forceLink` : distance = wave × 200 (wave links), 180 (parent links)
- `forceManyBody` : strength -800 (répulsion)
- `forceRadial` : rayon = wave × 200, strength 0.8
- `forceCollide` : radius + 30
#### Interactions
| Action | Effet |
|--------|-------|
| **Clic sur nœud** | Sélectionne l'idée → ouvre le panneau détail |
| **Double-clic sur nœud** | Ouvre l'éditeur inline pour créer un enfant |
| **Double-clic sur canvas** | Ouvre l'éditeur inline pour créer une idée racine |
| **Drag d'un nœud** | Déplace le nœud, fixe la position, émet `idea:moved` au socket |
| **Zoom/Pan** | d3.zoom, échelle [0.1, 5], centré avec scale 0.8 |
#### Éditeur inline (double-clic)
Apparaît sous le point de clic, carte flottante (260px) :
- En-tête : icône "+" bleue + label "Réponse" ou "Nouvelle idée"
- Input serif avec fond subtil
- Raccourcis : `↵ enregistrer` · `esc annuler`
- Si enfant : label "→ enfant"
- Triangle pointeur sous la carte
- **Enter** → appelle `onCreateIdea({ title, parentIdeaId, x, y })`
- **Escape** → ferme
#### Stabilité du canvas
- Le useEffect D3 ne se redéclenche QUE quand `sessionId` ou `ideasKey` (string sérialisée) changent
- Tous les callbacks (onNodeSelect, onPositionUpdate, onCreateIdea) sont passés via refs (`onNodeSelectRef.current`) pour éviter les re-renders
- Les remote moves (socket) mettent à jour directement les nœuds D3 sans re-render React
### Toolbar flottante (bas du canvas)
Pilule animée qui apparaît quand une session est active :
| Élément | Style | Action |
|---------|-------|--------|
| **Wave 1/2/3** | 3 points colorés (orange/blue/violet) | Légende visuelle |
| **Avatars** | Cercles colorés empilés (max 4, "+N") | Présence des utilisateurs connectés |
| **Exporter** | Texte orange | Appelle `exportBrainstorm` puis `finalizeBrainstorm` |
| **Inviter** | Texte émeraude, icône `<UserPlus>` | Ouvre `BrainstormShareDialog` |
| **Activité** | Icône `<Activity>`, muted/orange si actif | Toggle le panneau Activity Feed |
| **Supprimer** | Icône poubelle, muted → rose au hover | Supprime la session |
### Panneau détail (droite, 400px, slide animé)
Apparaît quand une idée est sélectionnée :
| Section | Contenu |
|---------|---------|
| **Badge wave** | Pilule colorée (Wave 1 orange / Wave 2 blue / Wave 3 violet) |
| **Note créée** | Badge vert si convertie |
| **Fermer** | Bouton chevron droite |
| **Titre** | 3xl serif bold |
| **Score de nouveauté** | `<Zap>` + nombre |
| **Créateur** | Humain = cercle bleu + initiale, IA = spark violet + "IA" |
| **Description** | Texte de l'idée |
| **Connexion au seed** | Carte slate, citation italic |
| **Origine de l'idée** | Cartes noteRef avec badge de relation (emerald=positive, rose=opposes, amber=autre), bouton "View" |
| **Bouton Approfondir** | `<Wind>` + "Deepen", bordure dashed, hover orange → `expandIdea` |
| **Bouton Créer Note** | `<FileText>` + "Create Note", bordure dashed, hover émeraude → `convertIdea` |
| **Bouton Non pertinent** | Texte muted, hover rose → `dismissIdea` |
### Sidebar sessions (bande droite, 64px)
- Icône `<History>` en haut
- Liste scrollable de boutons circulaires (40px) avec la première lettre du seed
- **Actif** : fond sombre, texte blanc, scale 110, shadow
- **Partagé** : fond orange clair, texte orange
- **Normal** : fond blanc, texte muted
- Filet décoratif en bas
### Activity Feed (panneau coulissant, 320px)
Slide depuis la droite avec animation spring :
- En-tête : icône + "Activity" + bouton fermer
- État vide : "No activity yet" italic
- Items : icône par type d'action, username bold, label d'action, titre idée (tronqué 30 chars), temps relatif (1m/1h/1d)
- Types : `manual_idea` (ampoule bleue), `wave_generated` (éclair orange), `joined` (user+ vert), `idea_dismissed` (X rose), `invite_created` (user+ violet)
### BrainstormShareDialog (modal)
- Trigger : bouton "Inviter" de la toolbar
- Header : icône orange + "Partager le brainstorm" + seed idea tronqué
- Champ email avec label "Adresse email"
- Bouton "Partager" orange avec `<UserPlus>`
- Messages de feedback :
- Succès (vert + ✓) : "Invitation envoyée!" / "Invitation renvoyée!"
- Info (ambre + ⚠) : "Cette personne a déjà accès" / "Invitation déjà en attente"
- Erreur (rose + ⚠) : "No account found with this email" etc.
- Note : "La personne recevra une notification pour accepter ou refuser."
### Impact Toast (fixed bottom center)
Apparaît après Export + Finalize :
- "X note(s) enriched / X note(s) marked dry"
- Disparaît après 4 secondes
---
## Sidebar gauche (app principale)
### Section Brainstorms (`SidebarBrainstorms`)
- **Vue vide** : Icône `<Sparkles>` orange + "Aucune session" + "Démarrer →"
- **Loading** : 3 skeletons pulsants
- **Liste** (max 10) :
- **Sessions possédées** : Cercle orange + `<Sparkles>` + seed idea + count idées + date + bouton supprimer (rose au hover)
- **Sessions partagées** : Cercle bleu + `<Sparkles>` + seed idea + badge "partagé" + count idées + date (pas de bouton supprimer)
- Clic → navigate vers `/brainstorm?session={id}`
### Navigation
- Bouton "brainstorms" dans le toggle de vues (icône `<Sparkles>` orange, highlight orange quand actif)
---
## Notifications (cloche)
### Partages brainstorm pending
- Section dédiée entre les reminders et les share requests de notes
- Avatar orange gradient avec initiale de l'envoyeur
- Icône `<Wind>` + label "BRAINSTORM" orange
- Nom de l'envoyeur + "invited you to a brainstorm" + aperçu du seed (tronqué 35 chars)
- Boutons Accepter (orange) / Refuser
### Notifications système
- `brainstorm_invite` : icône `<Wind>` émeraude
- `brainstorm_joined` : icône `<Wind>` bleue
---
## Temps réel (Socket.io)
### Événements client → serveur
| Event | Data | Quand |
|-------|------|-------|
| `cursor:move` | `{ x, y }` ou `null` | Mouvement souris sur le canvas |
| `idea:moved` | `{ ideaId, positionX, positionY, userId }` | Fin de drag d'un nœud |
| `activity:new` | `{ action, userId, userName, details }` | Action utilisateur |
### Événements serveur → client
| Event | Data | Effet |
|-------|------|-------|
| `presence:update` | `PresenceUser[]` | Mise à jour de la liste des utilisateurs connectés |
| `cursor:update` | `{ userId, cursor: {x,y} }` | Déplacement du curseur d'un autre user |
| `activity:new` | `ActivityEvent` | Nouvelle activité dans le feed |
| `idea:moved` | `{ ideaId, positionX, positionY }` | Déplacement d'un nœud par un autre user |
| `idea:added` | — | Placeholder (non utilisé côté client) |
| `idea:dismissed` | — | Placeholder (non utilisé côté client) |
### Flux de déplacement en temps réel
1. User A drag un nœud → fin de drag → `handlePositionUpdate` → émet `idea:moved` + POST API (persist)
2. Socket server → broadcast `idea:moved` aux autres dans la room
3. User B → `useBrainstormSocket` callback → `setRemoteMove(...)` (avec compteur séquentiel)
4. WaveCanvas → `useEffect([remoteMove])` → fixe fx/fy du nœud cible → 30 ticks de simulation → update positions liens/nœuds directement dans D3
### Curseurs live
- Chaque user a un curseur coloré (SVG arrow + nom) affiché sur le canvas des autres
- 12 couleurs assignées en round-robin
- `useCursorTracking` attache un listener mousemove au container et émet `cursor:move`
### Ghost Cursor IA
- Quand une vague IA est en génération, un curseur violet animé apparaît
- Se déplace aléatoirement dans un rayon de 150-350px du centre
- Pulsation violette + badge "AI ✦"
---
## Flux de partage
### Par email (server action — principal)
```
Propriétaire → Dialog email → createBrainstormShare()
→ Cherche recipient par email
→ Crée BrainstormShare (pending)
→ Destinataire voit dans NotificationPanel (cloche)
→ Accept → Upsert BrainstormParticipant
→ Decline → Update status
→ Apparaît dans sidebar (bleu, badge "partagé")
```
### Par lien (API invite — secondaire)
```
Propriétaire → invite route → génère token → copie URL
→ Destinataire ouvre URL avec ?invite=<token>
→ join route → vérifie token + expiry
→ Crée BrainstormParticipant
→ Notifie le owner
```
---
## Hooks React Query
| Hook | Type | Query Key | API |
|------|------|-----------|-----|
| `useBrainstormSessions()` | Query | `['brainstorm', 'sessions']` | GET /api/brainstorm |
| `useSharedBrainstormSessions()` | Query | `['brainstorm', 'shared-sessions']` | GET /api/brainstorm/shared |
| `useBrainstormSession(id)` | Query | `['brainstorm', 'session', id]` | GET /api/brainstorm/{id} |
| `useCreateBrainstorm()` | Mutation | — | POST /api/brainstorm |
| `useExpandIdea(id)` | Mutation | — | POST /api/brainstorm/{id}/expand |
| `useDismissIdea(id)` | Mutation | — | POST /api/brainstorm/{id}/dismiss |
| `useConvertIdea(id)` | Mutation | — | POST /api/brainstorm/{id}/convert |
| `useExportBrainstorm(id)` | Mutation | — | POST /api/brainstorm/{id}/export |
| `useFinalizeBrainstorm(id)` | Mutation | — | POST /api/brainstorm/{id}/finalize |
| `useDeleteBrainstorm()` | Mutation | — | DELETE /api/brainstorm/{id} |
| `useAddManualIdea(id)` | Mutation | — | POST /api/brainstorm/{id}/manual-idea |
| `useBrainstormActivity(id)` | Query | — | GET /api/brainstorm/{id}/activity (refetch 10s) |
---
## Fichiers sources
| Fichier | Rôle |
|---------|------|
| `components/brainstorm/brainstorm-page.tsx` | Page principale complète |
| `components/brainstorm/wave-canvas.tsx` | Canvas D3 (noeuds, liens, interactions) |
| `components/brainstorm/brainstorm-share-dialog.tsx` | Modal de partage par email |
| `components/brainstorm/activity-feed.tsx` | Panneau d'activité |
| `components/brainstorm/ghost-cursor.tsx` | Curseur IA animé |
| `components/brainstorm/live-cursors.tsx` | Curseurs des autres users + avatars |
| `hooks/use-brainstorm.ts` | Tous les hooks React Query |
| `hooks/use-brainstorm-socket.ts` | Hook Socket.io |
| `app/actions/brainstorm.ts` | Server actions (partage) |
| `app/api/brainstorm/route.ts` | POST create + GET list |
| `app/api/brainstorm/[sessionId]/route.ts` | GET/DELETE session |
| `app/api/brainstorm/[sessionId]/expand/route.ts` | POST approfondir |
| `app/api/brainstorm/[sessionId]/manual-idea/route.ts` | POST idée manuelle |
| `app/api/brainstorm/[sessionId]/dismiss/route.ts` | POST rejeter |
| `app/api/brainstorm/[sessionId]/convert/route.ts` | POST convertir en note |
| `app/api/brainstorm/[sessionId]/finalize/route.ts` | POST finaliser |
| `app/api/brainstorm/[sessionId]/export/route.ts` | POST exporter |
| `app/api/brainstorm/[sessionId]/update-position/route.ts` | POST position |
| `app/api/brainstorm/[sessionId]/invite/route.ts` | POST invitation par lien |
| `app/api/brainstorm/[sessionId]/activity/route.ts` | GET activités |
| `app/api/brainstorm/join/route.ts` | POST rejoindre par token |
| `app/api/brainstorm/shared/route.ts` | GET sessions partagées |
| `socket-server.ts` | Serveur Socket.io |
| `types/brainstorm.ts` | Types TypeScript |
| `lib/brainstorm-collab.ts` | verifyParticipant + logActivity |
| `prisma/schema.prisma` | Modèles DB (lignes 454-572) |
| `components/notification-panel.tsx` | Notifications partage brainstorm |
| `components/sidebar.tsx` | SidebarBrainstorms (lignes 85-169) |
---
## Composants obsolètes (existent mais non utilisés)
| Fichier | Note |
|---------|------|
| `components/brainstorm/manual-idea-dialog.tsx` | Remplacé par l'éditeur inline du canvas |
| `components/brainstorm/invite-dialog.tsx` | Remplacé par BrainstormShareDialog |
| `components/brainstorm/brainstorm-create-dialog.tsx` | Remplacé par l'input inline du header |
| `components/brainstorm/brainstorm-canvas.tsx` | Ancienne implémentation avec react-force-graph-2d, remplacé par WaveCanvas (D3 direct) |