mirror of
https://github.com/R0m1k3/LogiFlow.git
synced 2026-10-23 06:58:19 +02:00
Automate database migration execution on production startup
Add logic to run database migrations automatically when the application starts in production. Includes a new migration script to create the webhook_bap_config table and a utility script for creating new migration files. Replit-Commit-Author: Agent Replit-Commit-Session-Id: cfbfe47c-0c9a-4ebf-8a41-2937407eccff Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/1957c339-2757-4d1f-8e92-e9f71a1ce58e/cfbfe47c-0c9a-4ebf-8a41-2937407eccff/baXszB8
This commit is contained in:
1 parent
49a5d6cf2b
commit
bae218813b
4 files changed
+183
No files matched your search
@@ -0,0 +1,25 @@
|
|||||||
|
-- Migration: Création table configuration webhook BAP
|
||||||
|
-- Created: 2025-09-03T14:10:00.000Z
|
||||||
|
|
||||||
|
-- Table pour configuration webhook BAP
|
||||||
|
CREATE TABLE IF NOT EXISTS webhook_bap_config (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
name VARCHAR(100) NOT NULL DEFAULT 'Configuration BAP',
|
||||||
|
webhook_url TEXT NOT NULL,
|
||||||
|
description TEXT,
|
||||||
|
is_active BOOLEAN NOT NULL DEFAULT true,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Configuration par défaut webhook BAP
|
||||||
|
INSERT INTO webhook_bap_config (name, webhook_url, description, is_active)
|
||||||
|
VALUES (
|
||||||
|
'Configuration BAP',
|
||||||
|
'https://workflow.ffnancy.fr/webhook/a3d03176-b72f-412d-8fb9-f920b9fbab4d',
|
||||||
|
'Configuration par défaut pour l''envoi des fichiers BAP vers n8n',
|
||||||
|
true
|
||||||
|
) ON CONFLICT DO NOTHING;
|
||||||
|
|
||||||
|
-- Commentaire sur la table
|
||||||
|
COMMENT ON TABLE webhook_bap_config IS 'Configuration pour webhook BAP n8n';
|
||||||
Executable
+23
@@ -0,0 +1,23 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
// Script utilitaire pour créer une nouvelle migration
|
||||||
|
// Usage: node scripts/create-migration.js "nom de la migration"
|
||||||
|
|
||||||
|
import { createMigration } from '../server/migrations.js';
|
||||||
|
|
||||||
|
const migrationName = process.argv[2];
|
||||||
|
|
||||||
|
if (!migrationName) {
|
||||||
|
console.error('❌ Usage: node scripts/create-migration.js "nom de la migration"');
|
||||||
|
console.error(' Exemple: node scripts/create-migration.js "add user roles table"');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const filePath = createMigration(migrationName);
|
||||||
|
console.log(`✅ Migration créée avec succès: ${filePath}`);
|
||||||
|
console.log(' Éditez ce fichier pour ajouter votre SQL');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Erreur lors de la création de la migration:', error);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
@@ -2,6 +2,19 @@ import express, { type Request, Response, NextFunction } from "express";
|
|||||||
import { registerRoutes } from "./routes.js";
|
import { registerRoutes } from "./routes.js";
|
||||||
import { setupVite, serveStatic } from "./vite.js";
|
import { setupVite, serveStatic } from "./vite.js";
|
||||||
|
|
||||||
|
// Run database migrations first
|
||||||
|
if (process.env.NODE_ENV === 'production') {
|
||||||
|
console.log('🔄 [STARTUP] Running database migrations...');
|
||||||
|
try {
|
||||||
|
const { runMigrations } = await import('./migrations.js');
|
||||||
|
await runMigrations();
|
||||||
|
console.log('✅ [STARTUP] Database migrations completed');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ [STARTUP] Database migrations failed:', error);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize weather system
|
// Initialize weather system
|
||||||
console.log('🌤️ [STARTUP] Initializing weather system...');
|
console.log('🌤️ [STARTUP] Initializing weather system...');
|
||||||
const { initializeWeatherConfig } = await import('./weatherAutoConfig.js');
|
const { initializeWeatherConfig } = await import('./weatherAutoConfig.js');
|
||||||
|
|||||||
@@ -0,0 +1,122 @@
|
|||||||
|
import { sql } from 'drizzle-orm';
|
||||||
|
import { db } from './db.js';
|
||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = path.dirname(__filename);
|
||||||
|
|
||||||
|
// Table pour suivre les migrations appliquées
|
||||||
|
const createMigrationsTable = async () => {
|
||||||
|
await db.execute(sql`
|
||||||
|
CREATE TABLE IF NOT EXISTS migrations (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
filename VARCHAR(255) UNIQUE NOT NULL,
|
||||||
|
executed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
)
|
||||||
|
`);
|
||||||
|
};
|
||||||
|
|
||||||
|
interface MigrationFile {
|
||||||
|
filename: string;
|
||||||
|
sql: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function runMigrations() {
|
||||||
|
console.log('🔄 Vérification des migrations...');
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Créer la table des migrations si elle n'existe pas
|
||||||
|
await createMigrationsTable();
|
||||||
|
|
||||||
|
// Récupérer les migrations déjà appliquées
|
||||||
|
const appliedMigrations = await db.execute(sql`SELECT filename FROM migrations`);
|
||||||
|
const appliedFilenames = new Set(appliedMigrations.rows.map((row: any) => row.filename));
|
||||||
|
|
||||||
|
// Lire tous les fichiers de migration
|
||||||
|
const migrationsDir = path.join(__dirname, '..', 'migrations');
|
||||||
|
|
||||||
|
if (!fs.existsSync(migrationsDir)) {
|
||||||
|
console.log('📁 Création du dossier migrations...');
|
||||||
|
fs.mkdirSync(migrationsDir, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
const migrationFiles = fs.readdirSync(migrationsDir)
|
||||||
|
.filter(file => file.endsWith('.sql'))
|
||||||
|
.sort(); // Important : tri pour exécuter dans l'ordre
|
||||||
|
|
||||||
|
if (migrationFiles.length === 0) {
|
||||||
|
console.log('✅ Aucune migration à exécuter');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let executedCount = 0;
|
||||||
|
|
||||||
|
for (const filename of migrationFiles) {
|
||||||
|
if (appliedFilenames.has(filename)) {
|
||||||
|
console.log(`⏭️ Migration déjà appliquée: ${filename}`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`🔄 Exécution migration: ${filename}`);
|
||||||
|
|
||||||
|
const filePath = path.join(migrationsDir, filename);
|
||||||
|
const migrationSql = fs.readFileSync(filePath, 'utf8');
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Exécuter la migration dans une transaction
|
||||||
|
await db.transaction(async (tx: any) => {
|
||||||
|
// Exécuter le SQL de migration
|
||||||
|
await tx.execute(sql.raw(migrationSql));
|
||||||
|
|
||||||
|
// Marquer comme appliquée
|
||||||
|
await tx.execute(sql`
|
||||||
|
INSERT INTO migrations (filename)
|
||||||
|
VALUES (${filename})
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`✅ Migration appliquée avec succès: ${filename}`);
|
||||||
|
executedCount++;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`❌ Erreur lors de la migration ${filename}:`, error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (executedCount > 0) {
|
||||||
|
console.log(`✅ ${executedCount} migration(s) appliquée(s) avec succès`);
|
||||||
|
} else {
|
||||||
|
console.log('✅ Toutes les migrations sont déjà appliquées');
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Erreur lors de l\'exécution des migrations:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fonction pour créer une nouvelle migration
|
||||||
|
export function createMigration(name: string): string {
|
||||||
|
const timestamp = new Date().toISOString().replace(/[^\d]/g, '').slice(0, 14);
|
||||||
|
const filename = `${timestamp}_${name.toLowerCase().replace(/\s+/g, '_')}.sql`;
|
||||||
|
const migrationsDir = path.join(__dirname, '..', 'migrations');
|
||||||
|
|
||||||
|
if (!fs.existsSync(migrationsDir)) {
|
||||||
|
fs.mkdirSync(migrationsDir, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
const filePath = path.join(migrationsDir, filename);
|
||||||
|
const template = `-- Migration: ${name}
|
||||||
|
-- Created: ${new Date().toISOString()}
|
||||||
|
|
||||||
|
-- Add your SQL here
|
||||||
|
`;
|
||||||
|
|
||||||
|
fs.writeFileSync(filePath, template);
|
||||||
|
console.log(`📝 Migration créée: ${filePath}`);
|
||||||
|
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
Reference in new issue
Block a user