fix: restore brainstorming feature with missing socket server and real-time events
This commit is contained in:
329
docs/plan-reparation-prod-2026-05-19.md
Normal file
329
docs/plan-reparation-prod-2026-05-19.md
Normal file
@@ -0,0 +1,329 @@
|
||||
# Plan de réparation production — 19 mai 2026
|
||||
|
||||
## État actuel des problèmes
|
||||
|
||||
1. **Tables brainstorm manquantes en prod** — les 7 tables n'existent pas en base
|
||||
2. **Migration non enregistrée** — le container a été build avec 17 migrations, la 18e (brainstorm) est dans le code mais pas dans l'image
|
||||
3. **Redis fonctionne** — le container redis tourne, mais il faut vérifier que memento-web a bien `REDIS_URL`
|
||||
|
||||
## Étape 1 : Créer les tables brainstorm en prod
|
||||
|
||||
Se connecter au serveur en root, puis :
|
||||
|
||||
```bash
|
||||
docker exec -i memento-postgres psql -U memento -d memento <<'EOSQL'
|
||||
|
||||
-- ========================================
|
||||
-- Tables brainstorm
|
||||
-- ========================================
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "BrainstormSession" (
|
||||
"id" TEXT NOT NULL,
|
||||
"seedIdea" TEXT NOT NULL,
|
||||
"sourceNoteId" TEXT,
|
||||
"contextNoteIds" TEXT,
|
||||
"exportedNoteId" TEXT,
|
||||
"userId" TEXT NOT NULL,
|
||||
"inviteToken" TEXT,
|
||||
"inviteExpiry" TIMESTAMP(3),
|
||||
"liveblocksRoomId" TEXT,
|
||||
"isPublic" BOOLEAN NOT NULL DEFAULT false,
|
||||
"guestCanEdit" BOOLEAN NOT NULL DEFAULT false,
|
||||
"status" TEXT NOT NULL DEFAULT 'active',
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
CONSTRAINT "BrainstormSession_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "BrainstormIdea" (
|
||||
"id" TEXT NOT NULL,
|
||||
"sessionId" TEXT NOT NULL,
|
||||
"waveNumber" INTEGER NOT NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
"description" TEXT NOT NULL,
|
||||
"connectionToSeed" TEXT,
|
||||
"noveltyScore" INTEGER,
|
||||
"parentIdeaId" TEXT,
|
||||
"convertedToNoteId" TEXT,
|
||||
"relatedNoteIds" TEXT,
|
||||
"status" TEXT NOT NULL DEFAULT 'active',
|
||||
"positionX" DOUBLE PRECISION,
|
||||
"positionY" DOUBLE PRECISION,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"createdBy" TEXT,
|
||||
"createdByType" TEXT DEFAULT 'ai',
|
||||
CONSTRAINT "BrainstormIdea_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "BrainstormNoteRef" (
|
||||
"id" TEXT NOT NULL,
|
||||
"ideaId" TEXT NOT NULL,
|
||||
"noteId" TEXT,
|
||||
"relation" TEXT NOT NULL,
|
||||
"explanation" TEXT NOT NULL,
|
||||
"verdict" TEXT NOT NULL DEFAULT 'unresolved',
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"visibility" TEXT NOT NULL DEFAULT 'participants',
|
||||
CONSTRAINT "BrainstormNoteRef_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "BrainstormParticipant" (
|
||||
"id" TEXT NOT NULL,
|
||||
"sessionId" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"role" TEXT NOT NULL DEFAULT 'viewer',
|
||||
"joinedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"lastSeenAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT "BrainstormParticipant_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "BrainstormActivity" (
|
||||
"id" TEXT NOT NULL,
|
||||
"sessionId" TEXT NOT NULL,
|
||||
"userId" TEXT,
|
||||
"action" TEXT NOT NULL,
|
||||
"details" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT "BrainstormActivity_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "BrainstormShare" (
|
||||
"id" TEXT NOT NULL,
|
||||
"sessionId" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"sharedBy" TEXT NOT NULL,
|
||||
"status" TEXT NOT NULL DEFAULT 'pending',
|
||||
"permission" TEXT NOT NULL DEFAULT 'editor',
|
||||
"notifiedAt" TIMESTAMP(3),
|
||||
"respondedAt" TIMESTAMP(3),
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
CONSTRAINT "BrainstormShare_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "BrainstormSnapshot" (
|
||||
"id" TEXT NOT NULL,
|
||||
"sessionId" TEXT NOT NULL,
|
||||
"activityId" TEXT,
|
||||
"step" INTEGER NOT NULL,
|
||||
"label" TEXT,
|
||||
"ideaGraph" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT "BrainstormSnapshot_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- ========================================
|
||||
-- Index uniques
|
||||
-- ========================================
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "BrainstormSession_inviteToken_key" ON "BrainstormSession"("inviteToken");
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "BrainstormParticipant_sessionId_userId_key" ON "BrainstormParticipant"("sessionId", "userId");
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "BrainstormShare_sessionId_userId_key" ON "BrainstormShare"("sessionId", "userId");
|
||||
|
||||
-- ========================================
|
||||
-- Index de performance
|
||||
-- ========================================
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "BrainstormSession_userId_idx" ON "BrainstormSession"("userId");
|
||||
CREATE INDEX IF NOT EXISTS "BrainstormSession_userId_createdAt_idx" ON "BrainstormSession"("userId", "createdAt");
|
||||
CREATE INDEX IF NOT EXISTS "BrainstormSession_inviteToken_idx" ON "BrainstormSession"("inviteToken");
|
||||
CREATE INDEX IF NOT EXISTS "BrainstormSession_isPublic_idx" ON "BrainstormSession"("isPublic");
|
||||
CREATE INDEX IF NOT EXISTS "BrainstormIdea_sessionId_idx" ON "BrainstormIdea"("sessionId");
|
||||
CREATE INDEX IF NOT EXISTS "BrainstormIdea_waveNumber_idx" ON "BrainstormIdea"("waveNumber");
|
||||
CREATE INDEX IF NOT EXISTS "BrainstormIdea_status_idx" ON "BrainstormIdea"("status");
|
||||
CREATE INDEX IF NOT EXISTS "BrainstormIdea_parentIdeaId_idx" ON "BrainstormIdea"("parentIdeaId");
|
||||
CREATE INDEX IF NOT EXISTS "BrainstormIdea_sessionId_status_idx" ON "BrainstormIdea"("sessionId", "status");
|
||||
CREATE INDEX IF NOT EXISTS "BrainstormIdea_sessionId_waveNumber_createdAt_idx" ON "BrainstormIdea"("sessionId", "waveNumber", "createdAt");
|
||||
CREATE INDEX IF NOT EXISTS "BrainstormNoteRef_ideaId_idx" ON "BrainstormNoteRef"("ideaId");
|
||||
CREATE INDEX IF NOT EXISTS "BrainstormNoteRef_noteId_idx" ON "BrainstormNoteRef"("noteId");
|
||||
CREATE INDEX IF NOT EXISTS "BrainstormParticipant_sessionId_idx" ON "BrainstormParticipant"("sessionId");
|
||||
CREATE INDEX IF NOT EXISTS "BrainstormParticipant_userId_idx" ON "BrainstormParticipant"("userId");
|
||||
CREATE INDEX IF NOT EXISTS "BrainstormActivity_sessionId_createdAt_idx" ON "BrainstormActivity"("sessionId", "createdAt");
|
||||
CREATE INDEX IF NOT EXISTS "BrainstormShare_userId_idx" ON "BrainstormShare"("userId");
|
||||
CREATE INDEX IF NOT EXISTS "BrainstormShare_status_idx" ON "BrainstormShare"("status");
|
||||
CREATE INDEX IF NOT EXISTS "BrainstormSnapshot_sessionId_step_idx" ON "BrainstormSnapshot"("sessionId", "step");
|
||||
CREATE INDEX IF NOT EXISTS "BrainstormSnapshot_sessionId_createdAt_idx" ON "BrainstormSnapshot"("sessionId", "createdAt");
|
||||
|
||||
-- ========================================
|
||||
-- Clés étrangères
|
||||
-- ========================================
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "BrainstormSession" ADD CONSTRAINT "BrainstormSession_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
EXCEPTION WHEN duplicate_object THEN NULL;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "BrainstormSession" ADD CONSTRAINT "BrainstormSession_sourceNoteId_fkey" FOREIGN KEY ("sourceNoteId") REFERENCES "Note"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
EXCEPTION WHEN duplicate_object THEN NULL;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "BrainstormSession" ADD CONSTRAINT "BrainstormSession_exportedNoteId_fkey" FOREIGN KEY ("exportedNoteId") REFERENCES "Note"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
EXCEPTION WHEN duplicate_object THEN NULL;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "BrainstormIdea" ADD CONSTRAINT "BrainstormIdea_sessionId_fkey" FOREIGN KEY ("sessionId") REFERENCES "BrainstormSession"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
EXCEPTION WHEN duplicate_object THEN NULL;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "BrainstormIdea" ADD CONSTRAINT "BrainstormIdea_parentIdeaId_fkey" FOREIGN KEY ("parentIdeaId") REFERENCES "BrainstormIdea"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
EXCEPTION WHEN duplicate_object THEN NULL;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "BrainstormIdea" ADD CONSTRAINT "BrainstormIdea_convertedToNoteId_fkey" FOREIGN KEY ("convertedToNoteId") REFERENCES "Note"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
EXCEPTION WHEN duplicate_object THEN NULL;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "BrainstormNoteRef" ADD CONSTRAINT "BrainstormNoteRef_ideaId_fkey" FOREIGN KEY ("ideaId") REFERENCES "BrainstormIdea"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
EXCEPTION WHEN duplicate_object THEN NULL;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "BrainstormNoteRef" ADD CONSTRAINT "BrainstormNoteRef_noteId_fkey" FOREIGN KEY ("noteId") REFERENCES "Note"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
EXCEPTION WHEN duplicate_object THEN NULL;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "BrainstormParticipant" ADD CONSTRAINT "BrainstormParticipant_sessionId_fkey" FOREIGN KEY ("sessionId") REFERENCES "BrainstormSession"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
EXCEPTION WHEN duplicate_object THEN NULL;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "BrainstormParticipant" ADD CONSTRAINT "BrainstormParticipant_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
EXCEPTION WHEN duplicate_object THEN NULL;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "BrainstormActivity" ADD CONSTRAINT "BrainstormActivity_sessionId_fkey" FOREIGN KEY ("sessionId") REFERENCES "BrainstormSession"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
EXCEPTION WHEN duplicate_object THEN NULL;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "BrainstormActivity" ADD CONSTRAINT "BrainstormActivity_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
EXCEPTION WHEN duplicate_object THEN NULL;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "BrainstormShare" ADD CONSTRAINT "BrainstormShare_sessionId_fkey" FOREIGN KEY ("sessionId") REFERENCES "BrainstormSession"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
EXCEPTION WHEN duplicate_object THEN NULL;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "BrainstormShare" ADD CONSTRAINT "BrainstormShare_sharedBy_fkey" FOREIGN KEY ("sharedBy") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
EXCEPTION WHEN duplicate_object THEN NULL;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "BrainstormShare" ADD CONSTRAINT "BrainstormShare_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
EXCEPTION WHEN duplicate_object THEN NULL;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "BrainstormSnapshot" ADD CONSTRAINT "BrainstormSnapshot_sessionId_fkey" FOREIGN KEY ("sessionId") REFERENCES "BrainstormSession"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
EXCEPTION WHEN duplicate_object THEN NULL;
|
||||
END $$;
|
||||
|
||||
-- ========================================
|
||||
-- Enregistrer la migration dans Prisma
|
||||
-- ========================================
|
||||
|
||||
INSERT INTO "_prisma_migrations" (id, checksum, migration_name, logs, started_at, finished_at, applied_steps_count)
|
||||
VALUES (
|
||||
gen_random_uuid(),
|
||||
'manual-creation-20260519',
|
||||
'20260519120000_add_brainstorm_tables',
|
||||
NULL,
|
||||
now(),
|
||||
now(),
|
||||
1
|
||||
) ON CONFLICT DO NOTHING;
|
||||
|
||||
EOSQL
|
||||
```
|
||||
|
||||
## Étape 2 : Vérifier que les tables sont créées
|
||||
|
||||
```bash
|
||||
docker exec memento-postgres psql -U memento -d memento -c "SELECT tablename FROM pg_tables WHERE schemaname='public' AND tablename LIKE '%rainstorm%' ORDER BY tablename;"
|
||||
```
|
||||
|
||||
Résultat attendu : 7 lignes (BrainstormActivity, BrainstormIdea, BrainstormNoteRef, BrainstormParticipant, BrainstormSession, BrainstormShare, BrainstormSnapshot)
|
||||
|
||||
## Étape 3 : Vérifier les migrations enregistrées
|
||||
|
||||
```bash
|
||||
docker exec memento-postgres psql -U memento -d memento -c "SELECT migration_name FROM _prisma_migrations ORDER BY started_at DESC LIMIT 3;"
|
||||
```
|
||||
|
||||
Résultat attendu : la migration `20260519120000_add_brainstorm_tables` doit apparaître.
|
||||
|
||||
## Étape 4 : Vérifier Redis
|
||||
|
||||
```bash
|
||||
docker ps | grep redis
|
||||
docker exec memento-redis redis-cli ping
|
||||
```
|
||||
|
||||
Résultat attendu : `PONG`
|
||||
|
||||
Vérifier que memento-web a bien la variable REDIS_URL :
|
||||
|
||||
```bash
|
||||
docker exec memento-web env | grep REDIS
|
||||
```
|
||||
|
||||
Résultat attendu : `REDIS_URL=redis://redis:6379`
|
||||
|
||||
Si vide, il faut recréer le container :
|
||||
|
||||
```bash
|
||||
docker compose up -d --force-recreate memento-note
|
||||
```
|
||||
|
||||
## Étape 5 : Redémarrer l'app
|
||||
|
||||
```bash
|
||||
docker compose restart memento-note
|
||||
```
|
||||
|
||||
## Étape 6 : Vérifier les logs
|
||||
|
||||
```bash
|
||||
sleep 10
|
||||
docker logs memento-web --tail 30 2>&1 | grep -i -E "error|redis|brainstorm"
|
||||
```
|
||||
|
||||
Résultat attendu :
|
||||
- Aucune erreur `BrainstormSession does not exist`
|
||||
- Aucune erreur `redis ECONNREFUSED`
|
||||
- `[redis] Connected` doit apparaître
|
||||
|
||||
## Étape 7 : Tester le brainstorm
|
||||
|
||||
1. Ouvrir https://note.parsanet.org/brainstorm
|
||||
2. Taper une idée et cliquer le bouton +
|
||||
3. Vérifier que les 9 idées apparaissent sur le canvas
|
||||
|
||||
---
|
||||
|
||||
## Si l'étape 1 échoue
|
||||
|
||||
Copier le message d'erreur exact. Les causes possibles :
|
||||
- Permission denied → il faut être root (`sudo -i` avant)
|
||||
- duplicate_object → tables déjà créées partiellement, aller à l'étape 2 pour vérifier
|
||||
- Column exists → certaines colonnes existent déjà, les `IF NOT EXISTS` gèrent ça
|
||||
|
||||
## Si le brainstorm charge indéfiniment
|
||||
|
||||
Vérifier les logs en temps réel :
|
||||
|
||||
```bash
|
||||
docker logs memento-web -f --tail 50 2>&1 &
|
||||
```
|
||||
|
||||
Puis lancer un brainstorm et regarder les logs. Copier le message d'erreur exact.
|
||||
Reference in New Issue
Block a user