- 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
25 KiB
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 :
- Si pas de
contextNoteIds→ embedding du seed → recherche des 8 notes les plus proches - LLM classe chaque note : SUPPORT, TENSION, ou EXTENSION
- 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
- Chaque idée a : wave, title, description, connectionToSeed, noveltyScore, noteRefs[]
- Positionnement radial : angle =
(idx % 3) * (2π/3) + (wave-1) * 0.5, radius =wave * 150 - 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 :
- Charge les noteRefs de l'idée parent + 5 notes via embedding
- LLM génère 9 sous-idées en 3 vagues relatives au parent
- Positionnement radial autour du parent
- Crée les idées avec
parentIdeaId = source ideaRetour : 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 :
- Wave =
min(parent.wave + 1, 3)si parent, sinon 1 - Crée l'idée avec
createdBy = userId,createdByType = 'human' - Auto-link : embedding → 3 notes les plus proches → BrainstormNoteRef avec relation "extends"
- 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 :
- 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
- 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
emailfourni : 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).
- Vérifie que le user est propriétaire
- Cherche le recipient par email
- 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)
- Sinon → crée un
BrainstormShareavec 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 :
#F8F7F2avec 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.8forceCollide: 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
sessionIdouideasKey(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)
- Sessions possédées : Cercle orange +
- 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>émeraudebrainstorm_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
- User A drag un nœud → fin de drag →
handlePositionUpdate→ émetidea:moved+ POST API (persist) - Socket server → broadcast
idea:movedaux autres dans la room - User B →
useBrainstormSocketcallback →setRemoteMove(...)(avec compteur séquentiel) - 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
useCursorTrackingattache un listener mousemove au container et émetcursor: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) |