330 lines
13 KiB
Markdown
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.
|