From 55a1809e71e1fc7e76a081e5041750d273cf37cb Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 14 Nov 2025 09:50:21 +0000 Subject: [PATCH 1/2] Fix: Chargement automatique SQLite/PostgreSQL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CORRECTIF URGENT: L'application chargeait toujours SQLite même avec PostgreSQL configuré, causant une perte apparente de toutes les données. Ajout de database-loader.js qui détecte automatiquement: - DB_TYPE=postgres → PostgreSQL - DATABASE_URL=postgresql:// → PostgreSQL - Sinon → SQLite Tous les routes et services mis à jour pour utiliser database-loader au lieu de charger directement database.js. Les données ne sont PAS perdues, elles sont dans PostgreSQL. L'application se reconnectera correctement après redémarrage. Fichiers modifiés: - config/database-loader.js (nouveau) - server.js - routes/*.js (11 fichiers) - services/*.js (2 fichiers) --- config/database-loader.js | 22 ++++++++++++++++++++++ routes/auth.routes.js | 2 +- routes/calendar.routes.js | 2 +- routes/notes.routes.js | 2 +- routes/openrouter.routes.js | 2 +- routes/rss.routes-v2.js | 2 +- routes/rss.routes.js | 2 +- routes/settings.routes.js | 2 +- routes/todos.routes.js | 2 +- routes/users.routes.js | 2 +- server.js | 2 +- services/rss-scheduler-v2.js | 2 +- services/rss-scheduler.js | 2 +- 13 files changed, 34 insertions(+), 12 deletions(-) create mode 100644 config/database-loader.js diff --git a/config/database-loader.js b/config/database-loader.js new file mode 100644 index 0000000..2e1435d --- /dev/null +++ b/config/database-loader.js @@ -0,0 +1,22 @@ +// Chargeur automatique de base de données (SQLite ou PostgreSQL) +const logger = require('./logger'); + +// Détecter le type de base de données +const DB_TYPE = process.env.DB_TYPE || 'sqlite'; +const DATABASE_URL = process.env.DATABASE_URL; + +logger.info(`Configuration de base de données: ${DB_TYPE}`); + +// Charger le module approprié +let databaseModule; + +if (DB_TYPE === 'postgres' || DATABASE_URL?.startsWith('postgresql://')) { + logger.info('Chargement de la configuration PostgreSQL'); + databaseModule = require('./database-postgres'); +} else { + logger.info('Chargement de la configuration SQLite'); + databaseModule = require('./database'); +} + +// Exporter toutes les fonctions du module chargé +module.exports = databaseModule; diff --git a/routes/auth.routes.js b/routes/auth.routes.js index f0bb807..1ff6e10 100644 --- a/routes/auth.routes.js +++ b/routes/auth.routes.js @@ -4,7 +4,7 @@ const router = express.Router(); const bcrypt = require('bcrypt'); const { body, validationResult } = require('express-validator'); -const { getOne } = require('../config/database'); +const { getOne } = require('../config/database-loader'); const { generateToken, authenticateToken } = require('../middleware/auth'); const logger = require('../config/logger'); diff --git a/routes/calendar.routes.js b/routes/calendar.routes.js index 82eea6b..21313d7 100644 --- a/routes/calendar.routes.js +++ b/routes/calendar.routes.js @@ -2,7 +2,7 @@ const express = require('express'); const router = express.Router(); const { google } = require('googleapis'); -const { getAll, getOne, runQuery } = require('../config/database'); +const { getAll, getOne, runQuery } = require('../config/database-loader'); const { authenticateToken, requireAdmin } = require('../middleware/auth'); const logger = require('../config/logger'); diff --git a/routes/notes.routes.js b/routes/notes.routes.js index 4960f7b..3b88977 100644 --- a/routes/notes.routes.js +++ b/routes/notes.routes.js @@ -6,7 +6,7 @@ const path = require('path'); const fs = require('fs'); const { body, validationResult } = require('express-validator'); -const { getAll, getOne, runQuery } = require('../config/database'); +const { getAll, getOne, runQuery } = require('../config/database-loader'); const { authenticateToken } = require('../middleware/auth'); const logger = require('../config/logger'); diff --git a/routes/openrouter.routes.js b/routes/openrouter.routes.js index 42a43e8..59b242f 100644 --- a/routes/openrouter.routes.js +++ b/routes/openrouter.routes.js @@ -2,7 +2,7 @@ const express = require('express'); const router = express.Router(); const { authenticateToken, requireAdmin } = require('../middleware/auth'); -const { getOne } = require('../config/database'); +const { getOne } = require('../config/database-loader'); const logger = require('../config/logger'); // Cache pour les modèles (rafraîchi toutes les heures) diff --git a/routes/rss.routes-v2.js b/routes/rss.routes-v2.js index aee90eb..4b3a289 100644 --- a/routes/rss.routes-v2.js +++ b/routes/rss.routes-v2.js @@ -3,7 +3,7 @@ const express = require('express'); const router = express.Router(); const Parser = require('rss-parser'); const axios = require('axios'); -const { getAll, getOne, runQuery } = require('../config/database'); +const { getAll, getOne, runQuery } = require('../config/database-loader'); const { authenticateToken, requireAdmin } = require('../middleware/auth'); const logger = require('../config/logger'); diff --git a/routes/rss.routes.js b/routes/rss.routes.js index aee90eb..4b3a289 100644 --- a/routes/rss.routes.js +++ b/routes/rss.routes.js @@ -3,7 +3,7 @@ const express = require('express'); const router = express.Router(); const Parser = require('rss-parser'); const axios = require('axios'); -const { getAll, getOne, runQuery } = require('../config/database'); +const { getAll, getOne, runQuery } = require('../config/database-loader'); const { authenticateToken, requireAdmin } = require('../middleware/auth'); const logger = require('../config/logger'); diff --git a/routes/settings.routes.js b/routes/settings.routes.js index 8943729..ede4272 100644 --- a/routes/settings.routes.js +++ b/routes/settings.routes.js @@ -1,7 +1,7 @@ // Routes de gestion des paramètres const express = require('express'); const router = express.Router(); -const { getAll, getOne, runQuery } = require('../config/database'); +const { getAll, getOne, runQuery } = require('../config/database-loader'); const { authenticateToken, requireAdmin } = require('../middleware/auth'); const logger = require('../config/logger'); diff --git a/routes/todos.routes.js b/routes/todos.routes.js index 20a93a5..31d2441 100644 --- a/routes/todos.routes.js +++ b/routes/todos.routes.js @@ -3,7 +3,7 @@ const express = require('express'); const router = express.Router(); const { body, validationResult } = require('express-validator'); -const { getAll, getOne, runQuery } = require('../config/database'); +const { getAll, getOne, runQuery } = require('../config/database-loader'); const { authenticateToken } = require('../middleware/auth'); const logger = require('../config/logger'); diff --git a/routes/users.routes.js b/routes/users.routes.js index 8973e4d..de19b63 100644 --- a/routes/users.routes.js +++ b/routes/users.routes.js @@ -4,7 +4,7 @@ const router = express.Router(); const bcrypt = require('bcrypt'); const { body, validationResult } = require('express-validator'); -const { getAll, getOne, runQuery } = require('../config/database'); +const { getAll, getOne, runQuery } = require('../config/database-loader'); const { authenticateToken, requireAdmin } = require('../middleware/auth'); const logger = require('../config/logger'); diff --git a/server.js b/server.js index 0b3128f..d1db284 100644 --- a/server.js +++ b/server.js @@ -7,7 +7,7 @@ const path = require('path'); const fs = require('fs'); const logger = require('./config/logger'); -const { initDatabase } = require('./config/database'); +const { initDatabase } = require('./config/database-loader'); // Créer l'application Express const app = express(); diff --git a/services/rss-scheduler-v2.js b/services/rss-scheduler-v2.js index 44617bf..32d3f3a 100644 --- a/services/rss-scheduler-v2.js +++ b/services/rss-scheduler-v2.js @@ -1,6 +1,6 @@ // Service RSS NOUVEAU - Architecture simple et robuste const Parser = require('rss-parser'); -const { getAll, getOne, runQuery } = require('../config/database'); +const { getAll, getOne, runQuery } = require('../config/database-loader'); const logger = require('../config/logger'); const parser = new Parser({ diff --git a/services/rss-scheduler.js b/services/rss-scheduler.js index 44617bf..32d3f3a 100644 --- a/services/rss-scheduler.js +++ b/services/rss-scheduler.js @@ -1,6 +1,6 @@ // Service RSS NOUVEAU - Architecture simple et robuste const Parser = require('rss-parser'); -const { getAll, getOne, runQuery } = require('../config/database'); +const { getAll, getOne, runQuery } = require('../config/database-loader'); const logger = require('../config/logger'); const parser = new Parser({ From 5121691688ab27e51a572635854b1671daab75c0 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 14 Nov 2025 09:51:39 +0000 Subject: [PATCH 2/2] =?UTF-8?q?Docs:=20Guide=20r=C3=A9cup=C3=A9ration=20do?= =?UTF-8?q?nn=C3=A9es=20+=20script=20diagnostic?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ajout d'outils pour diagnostiquer et récupérer les données: 1. RECUPERATION-DONNEES.md - Explication de ce qui s'est passé (données non perdues) - 2 options: rester sur SQLite ou migrer vers PostgreSQL - Commandes de vérification et debug 2. scripts/check-data.js - Diagnostic automatique des données - Affiche contenu SQLite ET PostgreSQL - Recommandations selon la situation Utilisation: node scripts/check-data.js Les données utilisateur sont dans data/notes.db (148KB) et peuvent être restaurées immédiatement. --- RECUPERATION-DONNEES.md | 157 ++++++++++++++++++++++++++++++++++++++++ scripts/check-data.js | 123 +++++++++++++++++++++++++++++++ 2 files changed, 280 insertions(+) create mode 100644 RECUPERATION-DONNEES.md create mode 100755 scripts/check-data.js diff --git a/RECUPERATION-DONNEES.md b/RECUPERATION-DONNEES.md new file mode 100644 index 0000000..2820cd6 --- /dev/null +++ b/RECUPERATION-DONNEES.md @@ -0,0 +1,157 @@ +# 🚨 RÉCUPÉRATION DES DONNÉES - Guide d'urgence + +## 📋 Qu'est-ce qui s'est passé ? + +Vos données ne sont **PAS perdues** ! Le problème était que: + +1. Docker était configuré pour utiliser PostgreSQL (`DB_TYPE=postgres`) +2. Mais le code chargeait toujours SQLite +3. Résultat: une nouvelle base SQLite vide était créée +4. Vos vraies données sont restées dans la base SQLite d'origine + +## ✅ Solution appliquée + +Un système de **détection automatique** a été ajouté (`config/database-loader.js`) qui: +- Détecte `DB_TYPE=postgres` → charge PostgreSQL +- Détecte `DATABASE_URL=postgresql://` → charge PostgreSQL +- Sinon → charge SQLite + +## 🔄 Deux options pour récupérer vos données + +### Option 1: Utiliser SQLite (RAPIDE - recommandé pour l'instant) + +**Revenir temporairement à SQLite le temps de tout vérifier:** + +```bash +# 1. Arrêter les containers +docker-compose down + +# 2. Modifier docker-compose.yml temporairement +# Commentez ces lignes dans la section notes-app > environment: +# - DATABASE_URL=postgresql://... +# - DB_TYPE=postgres + +# 3. Relancer +docker-compose build notes-app +docker-compose up -d +``` + +Vos données réapparaîtront immédiatement car SQLite sera rechargé. + +### Option 2: Migrer vers PostgreSQL (PROPRE - recommandé pour production) + +**Migration complète de SQLite → PostgreSQL:** + +```bash +# 1. Reconstruire avec le nouveau code +docker-compose build notes-app + +# 2. Démarrer les containers +docker-compose up -d + +# 3. Attendre 30 secondes que PostgreSQL démarre +sleep 30 + +# 4. Lancer la migration +bash scripts/run-migration.sh +``` + +Cette option copie toutes vos données de SQLite vers PostgreSQL. + +## 🔍 Vérifier que tout fonctionne + +### Après Option 1 (SQLite): + +```bash +# Vérifier les données +docker exec notes-todo-app node -e " +const { getAll } = require('./config/database-loader'); +getAll('SELECT COUNT(*) as count FROM notes').then(r => { + console.log('Notes:', r[0].count); + process.exit(0); +}); +" +``` + +### Après Option 2 (PostgreSQL): + +```bash +# Vérifier les données dans PostgreSQL +docker exec noteflow-postgres psql -U noteflow -d noteflow -p 5499 \ + -c "SELECT COUNT(*) FROM notes;" + +docker exec noteflow-postgres psql -U noteflow -d noteflow -p 5499 \ + -c "SELECT COUNT(*) FROM rss_articles;" +``` + +## 🎯 Recommandation + +**Pour l'instant:** +1. Utilisez **Option 1** (SQLite) pour récupérer immédiatement vos données +2. Vérifiez que tout fonctionne bien +3. Plus tard, quand vous êtes prêt, utilisez **Option 2** pour migrer vers PostgreSQL + +## 📂 Où sont vos données ? + +- **SQLite actuel:** `./data/notes.db` (vos vraies données sont ici) +- **PostgreSQL:** Container Docker `noteflow-postgres` (vide ou partiellement migré) + +## ⚠️ Important + +**NE SUPPRIMEZ PAS** le fichier `./data/notes.db` tant que vous n'avez pas: +1. Vérifié que tout fonctionne avec PostgreSQL +2. Confirmé que toutes vos données sont migrées +3. Testé l'application pendant plusieurs jours + +## 🆘 En cas de problème + +### Voir les logs +```bash +docker-compose logs notes-app | tail -50 +``` + +### Identifier quelle base est utilisée +```bash +docker exec notes-todo-app node -e " +console.log('DB_TYPE:', process.env.DB_TYPE); +console.log('DATABASE_URL:', process.env.DATABASE_URL?.replace(/:[^:@]+@/, ':***@')); +" +``` + +### Forcer SQLite même avec Docker +```bash +docker exec -e DB_TYPE=sqlite notes-todo-app node server.js +``` + +## 📞 Debug rapide + +```bash +# Compter les notes dans SQLite +docker exec notes-todo-app node -e " +const sqlite3 = require('sqlite3'); +const db = new sqlite3.Database('./data/notes.db'); +db.get('SELECT COUNT(*) as count FROM notes', (err, row) => { + console.log('Notes SQLite:', row.count); + db.close(); +}); +" 2>/dev/null + +# Compter les notes dans PostgreSQL +docker exec noteflow-postgres psql -U noteflow -d noteflow -p 5499 -t \ + -c "SELECT COUNT(*) FROM notes;" 2>/dev/null || echo "PostgreSQL non accessible" +``` + +## ✅ Checklist de récupération + +- [ ] Containers redémarrés avec nouvelle configuration +- [ ] Base de données accessible (SQLite OU PostgreSQL) +- [ ] Notes visibles dans l'interface +- [ ] Tâches visibles +- [ ] Flux RSS configurés +- [ ] Événements calendrier présents +- [ ] Paramètres restaurés + +--- + +**Date de création:** 2025-11-14 +**Commit de correction:** 55a1809 - Fix: Chargement automatique SQLite/PostgreSQL diff --git a/scripts/check-data.js b/scripts/check-data.js new file mode 100755 index 0000000..9358865 --- /dev/null +++ b/scripts/check-data.js @@ -0,0 +1,123 @@ +// Script de diagnostic - Vérifier où sont les données +const sqlite3 = require('sqlite3').verbose(); +const path = require('path'); +const { Pool } = require('pg'); + +console.log('\n🔍 DIAGNOSTIC DES DONNÉES\n'); +console.log('═══════════════════════════════════════════\n'); + +// Variables d'environnement +console.log('📋 Configuration actuelle:'); +console.log(' DB_TYPE:', process.env.DB_TYPE || '(non défini → SQLite)'); +console.log(' DATABASE_URL:', process.env.DATABASE_URL ? + process.env.DATABASE_URL.replace(/:[^:@]+@/, ':***@') : '(non défini)'); +console.log(''); + +// 1. Vérifier SQLite +const SQLITE_PATH = path.join(__dirname, '../data/notes.db'); +console.log('📊 Données dans SQLite (' + SQLITE_PATH + '):'); + +const sqliteDb = new sqlite3.Database(SQLITE_PATH, async (err) => { + if (err) { + console.log(' ❌ Erreur connexion SQLite:', err.message); + checkPostgres(); + return; + } + + const tables = ['users', 'notes', 'global_todos', 'rss_feeds', 'rss_articles', 'calendar_events', 'settings']; + let completed = 0; + + for (const table of tables) { + sqliteDb.get(`SELECT COUNT(*) as count FROM ${table}`, (err, row) => { + if (err) { + console.log(` • ${table}: ❌ ${err.message}`); + } else { + const icon = row.count > 0 ? '✅' : '⚪'; + console.log(` ${icon} ${table.padEnd(20)} : ${row.count}`); + } + + completed++; + if (completed === tables.length) { + sqliteDb.close(() => { + console.log(''); + checkPostgres(); + }); + } + }); + } +}); + +// 2. Vérifier PostgreSQL +async function checkPostgres() { + const DATABASE_URL = process.env.DATABASE_URL; + + if (!DATABASE_URL || !DATABASE_URL.startsWith('postgresql://')) { + console.log('📊 PostgreSQL: Non configuré (DATABASE_URL manquant)\n'); + showConclusion(); + return; + } + + console.log('📊 Données dans PostgreSQL:'); + + const pool = new Pool({ + connectionString: DATABASE_URL, + max: 1, + connectionTimeoutMillis: 3000, + }); + + try { + const client = await pool.connect(); + + const tables = ['users', 'notes', 'global_todos', 'rss_feeds', 'rss_articles', 'calendar_events', 'settings']; + + for (const table of tables) { + try { + const result = await client.query(`SELECT COUNT(*) as count FROM ${table}`); + const count = parseInt(result.rows[0].count); + const icon = count > 0 ? '✅' : '⚪'; + console.log(` ${icon} ${table.padEnd(20)} : ${count}`); + } catch (err) { + console.log(` • ${table.padEnd(20)} : ❌ ${err.message.split('\n')[0]}`); + } + } + + client.release(); + await pool.end(); + console.log(''); + showConclusion(); + + } catch (error) { + console.log(' ❌ Connexion impossible:', error.message); + console.log(''); + showConclusion(); + } +} + +function showConclusion() { + console.log('═══════════════════════════════════════════'); + console.log('\n💡 CONCLUSION:\n'); + + const dbType = process.env.DB_TYPE || 'sqlite'; + const hasDbUrl = process.env.DATABASE_URL?.startsWith('postgresql://'); + + if (dbType === 'postgres' || hasDbUrl) { + console.log(' L\'application est configurée pour PostgreSQL'); + console.log(' '); + console.log(' ⚠️ Si PostgreSQL est vide et SQLite contient des données:'); + console.log(' → Vos données sont dans SQLite'); + console.log(' → Lancez la migration: bash scripts/run-migration.sh'); + console.log(' '); + console.log(' ✅ Si PostgreSQL contient des données:'); + console.log(' → Migration déjà effectuée'); + console.log(' → Redémarrez: docker-compose restart notes-app'); + } else { + console.log(' L\'application est configurée pour SQLite'); + console.log(' '); + console.log(' ✅ Si SQLite contient des données:'); + console.log(' → Tout est normal'); + console.log(' → Vérifiez l\'interface web'); + } + + console.log('\n═══════════════════════════════════════════\n'); + process.exit(0); +}