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

13 KiB

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 :

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

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

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

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 :

docker exec memento-web env | grep REDIS

Résultat attendu : REDIS_URL=redis://redis:6379

Si vide, il faut recréer le container :

docker compose up -d --force-recreate memento-note

Étape 5 : Redémarrer l'app

docker compose restart memento-note

Étape 6 : Vérifier les logs

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 :

docker logs memento-web -f --tail 50 2>&1 &

Puis lancer un brainstorm et regarder les logs. Copier le message d'erreur exact.