seo-generator-server/server.js
StillHammer 64fb319e65 refactor: Synchronisation complète du codebase - Application de tous les patches
Application systématique et méthodique de tous les patches historiques.

##  FICHIERS SYNCHRONISÉS (19 fichiers)

### Core & Infrastructure:
- server.js (14 patches) - Lazy loading ModeManager, SIGINT hard kill, timing logs
- ModeManager.js (4 patches) - Instrumentation complète avec timing détaillé

### Pipeline System:
- PipelineDefinition.js (6 patches) - Source unique getLLMProvidersList()
- pipeline-builder.js (8 patches) - Standardisation LLM providers
- pipeline-runner.js (6 patches) - Affichage résultats structurés + debug console
- pipeline-builder.html (2 patches) - Fallback providers synchronisés
- pipeline-runner.html (3 patches) - UI améliorée résultats

### Enhancement Layers:
- TechnicalLayer.js (1 patch) - defaultLLM: 'gpt-4o-mini'
- StyleLayer.js (1 patch) - Type safety vocabulairePref
- PatternBreakingCore.js (1 patch) - Mapping modifications
- PatternBreakingLayers.js (1 patch) - LLM standardisé

### Validators & Tests:
- QualityMetrics.js (1 patch) - callLLM('gpt-4o-mini')
- PersonalityValidator.js (1 patch) - Provider gpt-4o-mini
- AntiDetectionValidator.js - Synchronisé

### Documentation:
- TODO.md (1 patch) - Section LiteLLM pour tracking coûts
- CLAUDE.md - Documentation à jour

### Tools:
- tools/analyze-skipped-exports.js (nouveau)
- tools/apply-claude-exports.js (nouveau)
- tools/apply-claude-exports-fuzzy.js (nouveau)

## 🎯 Changements principaux:
-  Standardisation LLM providers (openai → gpt-4o-mini, claude → claude-sonnet-4-5)
-  Lazy loading optimisé (ModeManager chargé à la demande)
-  SIGINT immediate exit (pas de graceful shutdown)
-  Type safety renforcé (conversions string explicites)
-  Instrumentation timing complète
-  Debug logging amélioré (console.log résultats pipeline)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-12 20:36:17 +08:00

290 lines
9.0 KiB
JavaScript

// ========================================
// FICHIER: server.js - POINT D'ENTRÉE MODES EXCLUSIFS
// RESPONSABILITÉ: Démarrage serveur avec sélection mode MANUAL/AUTO
// MODES: MANUAL (interface client) | AUTO (batch GSheets)
// ========================================
const startupTime = Date.now();
console.log(`[${Date.now() - startupTime}ms] Chargement dotenv...`);
require('dotenv').config();
console.log(`[${Date.now() - startupTime}ms] Chargement ErrorReporting...`);
const { logSh } = require('./lib/ErrorReporting');
console.log(`[${Date.now() - startupTime}ms] Chargement ModeManager...`);
// ⚡ LAZY LOADING: Charger ModeManager seulement quand nécessaire
let ModeManager = null;
function getModeManager() {
if (!ModeManager) {
const loadStart = Date.now();
logSh('⚡ Chargement ModeManager (lazy)...', 'DEBUG');
ModeManager = require('./lib/modes/ModeManager').ModeManager;
console.log(`[${Date.now() - startupTime}ms] ModeManager chargé !`);
logSh(`⚡ ModeManager chargé en ${Date.now() - loadStart}ms`, 'DEBUG');
}
return ModeManager;
}
/**
* SERVEUR SEO GENERATOR - MODES EXCLUSIFS
* Point d'entrée unique pour démarrer en mode MANUAL ou AUTO
*/
class SEOGeneratorServer {
constructor() {
this.startTime = Date.now();
this.isShuttingDown = false;
}
/**
* Démarrage principal du serveur
*/
async start() {
try {
// Banner de démarrage
this.displayStartupBanner();
// Gestion signaux système
this.setupSignalHandlers();
// Initialisation du gestionnaire de modes
const MM = getModeManager();
const mode = await MM.initialize();
logSh(`🎯 Serveur démarré en mode ${mode.toUpperCase()}`, 'INFO');
logSh(`⏱️ Temps de démarrage: ${Date.now() - this.startTime}ms`, 'DEBUG');
// Monitoring périodique
this.startHealthMonitoring();
return mode;
} catch (error) {
logSh(`❌ ÉCHEC DÉMARRAGE SERVEUR: ${error.message}`, 'ERROR');
logSh(`Stack trace: ${error.stack}`, 'ERROR');
await this.gracefulShutdown(1);
}
}
/**
* Affiche la bannière de démarrage
*/
displayStartupBanner() {
const version = require('./package.json').version || '1.0.0';
const nodeVersion = process.version;
const platform = process.platform;
// Bannière visuelle en console.log (pas de logging structuré)
console.log(`
╔════════════════════════════════════════════════════════════╗
║ SEO GENERATOR SERVER ║
║ MODES EXCLUSIFS ║
╠════════════════════════════════════════════════════════════╣
║ Version: ${version.padEnd(10)} │ Node: ${nodeVersion.padEnd(10)} │ OS: ${platform.padEnd(8)}
║ ║
║ 🎯 MANUAL MODE: Interface Client + API + WebSocket ║
║ 🤖 AUTO MODE: Traitement Batch Google Sheets ║
║ ║
║ 💡 Utilisation: ║
║ npm start (défaut: MANUAL) ║
║ npm start -- --mode=manual ║
║ npm start -- --mode=auto ║
║ SERVER_MODE=auto npm start ║
╚════════════════════════════════════════════════════════════╝
`);
logSh('🚀 === SEO GENERATOR SERVER - DÉMARRAGE ===', 'INFO');
logSh(`📦 Version: ${version} | Node: ${nodeVersion}`, 'INFO');
}
/**
* Configure la gestion des signaux système
*/
setupSignalHandlers() {
// SIGINT (Ctrl+C) : Kill immédiat sans graceful shutdown
process.on('SIGINT', () => {
console.log('\n🛑 SIGINT reçu - Arrêt immédiat (hard kill)');
process.exit(0);
});
// Arrêt propre sur SIGTERM
process.on('SIGTERM', () => this.handleShutdownSignal('SIGTERM'));
// Gestion erreurs non capturées
process.on('uncaughtException', (error) => {
logSh(`❌ ERREUR NON CAPTURÉE: ${error.message}`, 'ERROR');
logSh(`Stack: ${error.stack}`, 'ERROR');
this.gracefulShutdown(1);
});
process.on('unhandledRejection', (reason, promise) => {
logSh(`❌ PROMESSE REJETÉE: ${reason}`, 'ERROR');
logSh(`Promise: ${promise}`, 'DEBUG');
// Ne pas arrêter pour les rejections non gérées, juste logger
});
}
/**
* Gère les signaux d'arrêt
*/
async handleShutdownSignal(signal) {
logSh(`🛑 Signal reçu: ${signal}`, 'INFO');
await this.gracefulShutdown(0);
}
/**
* Arrêt propre du serveur
*/
async gracefulShutdown(exitCode = 0) {
if (this.isShuttingDown) {
logSh('⚠️ Arrêt déjà en cours...', 'WARNING');
return;
}
this.isShuttingDown = true;
const shutdownStart = Date.now();
logSh('🛑 ARRÊT SERVEUR EN COURS...', 'INFO');
try {
// Arrêter le monitoring
if (this.healthInterval) {
clearInterval(this.healthInterval);
}
// Arrêter le mode actuel via ModeManager
const MM = getModeManager();
await MM.stopCurrentMode();
// Nettoyage final
await this.finalCleanup();
const shutdownDuration = Date.now() - shutdownStart;
const totalUptime = Date.now() - this.startTime;
logSh(`✅ Arrêt terminé (${shutdownDuration}ms)`, 'INFO');
logSh(`⏱️ Uptime total: ${Math.floor(totalUptime / 1000)}s`, 'INFO');
logSh('👋 Au revoir !', 'INFO');
} catch (error) {
logSh(`❌ Erreur durant arrêt: ${error.message}`, 'ERROR');
exitCode = 1;
}
// Attendre un peu pour que les logs se finalisent
setTimeout(() => {
process.exit(exitCode);
}, 100);
}
/**
* Nettoyage final avant arrêt
*/
async finalCleanup() {
try {
// Sauvegarder l'état final
const MM = getModeManager();
MM.saveModeState();
// Autres nettoyages si nécessaire
} catch (error) {
logSh(`⚠️ Erreur nettoyage final: ${error.message}`, 'WARNING');
}
}
/**
* Démarre le monitoring de santé
*/
startHealthMonitoring() {
const HEALTH_CHECK_INTERVAL = 30000; // 30 secondes
this.healthInterval = setInterval(() => {
try {
this.performHealthCheck();
} catch (error) {
logSh(`⚠️ Erreur health check: ${error.message}`, 'WARNING');
}
}, HEALTH_CHECK_INTERVAL);
logSh('💓 Health monitoring démarré', 'DEBUG');
}
/**
* Vérifie la santé du système
*/
performHealthCheck() {
const MM = getModeManager();
const status = MM.getStatus();
const memUsage = process.memoryUsage();
const uptime = process.uptime();
// Log périodique de l'état
logSh(`💓 Health Check - Mode: ${status.currentMode} | Uptime: ${Math.floor(uptime)}s | RAM: ${Math.round(memUsage.rss / 1024 / 1024)}MB`, 'TRACE');
// Vérifications critiques
if (memUsage.rss > 1024 * 1024 * 1024) { // > 1GB
logSh('⚠️ Utilisation mémoire élevée', 'WARNING');
}
if (!status.currentMode) {
logSh('⚠️ Aucun mode actif détecté', 'WARNING');
}
}
/**
* API pour changer de mode (si nécessaire)
*/
async switchMode(newMode, force = false) {
logSh(`🔄 Demande changement mode vers: ${newMode}`, 'INFO');
try {
const MM = getModeManager();
await MM.switchToMode(newMode, force);
logSh(`✅ Changement mode réussi vers: ${newMode}`, 'INFO');
return true;
} catch (error) {
logSh(`❌ Échec changement mode: ${error.message}`, 'ERROR');
throw error;
}
}
/**
* Retourne le statut actuel
*/
getStatus() {
return {
server: {
startTime: this.startTime,
uptime: Date.now() - this.startTime,
isShuttingDown: this.isShuttingDown,
nodeVersion: process.version,
platform: process.platform,
pid: process.pid
},
mode: getModeManager().getStatus(),
memory: process.memoryUsage(),
timestamp: new Date().toISOString()
};
}
}
// ========================================
// DÉMARRAGE AUTOMATIQUE
// ========================================
// Démarrer le serveur si ce fichier est exécuté directement
if (require.main === module) {
const server = new SEOGeneratorServer();
server.start().catch((error) => {
logSh(`💥 ERREUR CRITIQUE DÉMARRAGE: ${error.message}`, 'ERROR');
process.exit(1);
});
}
// ============= EXPORTS =============
module.exports = { SEOGeneratorServer };