seogeneratorserver/server.js
StillHammer dbf1a3de8c Add technical plan for multi-format export system
Added plan.md with complete architecture for format-agnostic content generation:
- Support for Markdown, HTML, Plain Text, JSON formats
- New FormatExporter module with neutral data structure
- Integration strategy with existing ContentAssembly and ArticleStorage
- Bonus features: SEO metadata generation, readability scoring, WordPress Gutenberg format
- Implementation roadmap with 4 phases (6h total estimated)

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 16:14:29 +08:00

262 lines
8.3 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)
// ========================================
require('dotenv').config();
const { logSh } = require('./lib/ErrorReporting');
const { ModeManager } = require('./lib/modes/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 mode = await ModeManager.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;
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() {
// Arrêt propre sur SIGTERM/SIGINT
process.on('SIGTERM', () => this.handleShutdownSignal('SIGTERM'));
process.on('SIGINT', () => this.handleShutdownSignal('SIGINT'));
// 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
await ModeManager.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
ModeManager.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 status = ModeManager.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 {
await ModeManager.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: ModeManager.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) => {
console.error('💥 ERREUR CRITIQUE DÉMARRAGE:', error.message);
process.exit(1);
});
}
// ============= EXPORTS =============
module.exports = { SEOGeneratorServer };