Files
Momento/docs/plan-reparation-prod-2026-05-19.md
Antigravity fdb148144e
Some checks failed
CI / Lint, Test & Build (push) Failing after 7m48s
CI / Deploy production (on server) (push) Has been cancelled
fix: restore brainstorming feature with missing socket server and real-time events
2026-05-19 20:07:56 +00:00

330 lines
13 KiB
Markdown

# 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.