revert: remove auto-init database feature

- Remove auto-init-db.js script
- Restore original index.js without database initialization

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
soufiane 2025-12-04 01:24:19 +01:00
parent 83b74ee0c1
commit 5eba6de570
2 changed files with 3 additions and 385 deletions

View File

@ -7,7 +7,6 @@ import config from "./src/config/env.js";
import { pool } from "./db.js"; import { pool } from "./db.js";
import { errorHandler } from "./src/middleware/errorHandler.js"; import { errorHandler } from "./src/middleware/errorHandler.js";
import { metricsMiddleware } from "./src/middleware/metrics.js"; import { metricsMiddleware } from "./src/middleware/metrics.js";
import { initDatabase } from "./scripts/auto-init-db.js";
// Import routes // Import routes
import authRoutes from "./src/routes/auth.routes.js"; import authRoutes from "./src/routes/auth.routes.js";
@ -108,19 +107,7 @@ export default app;
// Lancement serveur (seulement si pas importé par les tests) // Lancement serveur (seulement si pas importé par les tests)
if (process.env.NODE_ENV !== 'test') { if (process.env.NODE_ENV !== 'test') {
const PORT = config.server.port; const PORT = config.server.port;
app.listen(PORT, "0.0.0.0", () => {
// Initialiser la base de données avant de lancer le serveur console.log(`🚀 Backend lancé sur 0.0.0.0:${PORT}`);
initDatabase() });
.then(() => {
app.listen(PORT, "0.0.0.0", () => {
console.log(`🚀 Backend lancé sur 0.0.0.0:${PORT}`);
});
})
.catch((error) => {
console.error('❌ Erreur lors de l\'initialisation de la base de données:', error);
// Lancer le serveur quand même pour permettre le debug
app.listen(PORT, "0.0.0.0", () => {
console.log(`🚀 Backend lancé sur 0.0.0.0:${PORT} (sans init DB) ⚠️`);
});
});
} }

View File

@ -1,369 +0,0 @@
/**
* Script d'auto-initialisation de la base de données
* Appelé automatiquement au démarrage du backend
*
* Ce script vérifie si les tables existent et les crée si nécessaire
* Il crée également les comptes admin/employé et génère les 500,000 tickets
*/
import { readFileSync } from 'fs';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
import bcrypt from 'bcrypt';
import { pool } from '../db.js';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const SALT_ROUNDS = 10;
const TOTAL_TICKETS = 500000;
const BATCH_SIZE = 5000;
const PRIZE_DISTRIBUTION = {
'INFUSEUR': { percentage: 0.60, name: 'Infuseur à thé' },
'THE_GRATUIT': { percentage: 0.20, name: 'Thé détox/infusion 100g' },
'THE_SIGNATURE': { percentage: 0.10, name: 'Thé signature 100g' },
'COFFRET_DECOUVERTE': { percentage: 0.06, name: 'Coffret découverte 39€' },
'COFFRET_PRESTIGE': { percentage: 0.04, name: 'Coffret prestige 69€' }
};
/**
* Vérifie si les tables existent dans la base de données
*/
async function tablesExist() {
try {
const result = await pool.query(`
SELECT COUNT(*) as count
FROM information_schema.tables
WHERE table_schema = 'public'
AND table_name IN ('users', 'prizes', 'tickets', 'game_settings')
`);
return parseInt(result.rows[0].count) === 4;
} catch (error) {
console.error('❌ Erreur lors de la vérification des tables:', error.message);
return false;
}
}
/**
* Vérifie si les tickets ont été générés
*/
async function ticketsExist() {
try {
const result = await pool.query('SELECT COUNT(*) as count FROM tickets');
return parseInt(result.rows[0].count) >= TOTAL_TICKETS;
} catch (error) {
return false;
}
}
/**
* Vérifie si les utilisateurs admin/employé existent
*/
async function usersExist() {
try {
const result = await pool.query(`
SELECT COUNT(*) as count FROM users
WHERE email IN ('admin@thetiptop.com', 'employee1@thetiptop.com')
`);
return parseInt(result.rows[0].count) >= 2;
} catch (error) {
return false;
}
}
/**
* Crée les tables à partir du schema.sql
*/
async function createTables() {
console.log('📦 Création des tables...');
const schemaPath = join(__dirname, '..', 'database', 'schema.sql');
const schema = readFileSync(schemaPath, 'utf-8');
await pool.query(schema);
console.log('✅ Tables créées avec succès');
}
/**
* Crée les utilisateurs par défaut (admin, employés)
*/
async function createDefaultUsers() {
console.log('👥 Création des utilisateurs par défaut...');
const adminPassword = await bcrypt.hash('Admin123!', SALT_ROUNDS);
const employeePassword = await bcrypt.hash('Employee123!', SALT_ROUNDS);
// Admin
await pool.query(
`INSERT INTO users (email, password, first_name, last_name, phone, role, is_verified)
VALUES ($1, $2, $3, $4, $5, 'ADMIN', TRUE)
ON CONFLICT (email) DO UPDATE SET
password = EXCLUDED.password,
role = 'ADMIN',
is_verified = TRUE`,
['admin@thetiptop.com', adminPassword, 'Admin', 'Principal', '+33123456789']
);
console.log(' ✅ Admin créé: admin@thetiptop.com');
// Employé 1
await pool.query(
`INSERT INTO users (email, password, first_name, last_name, phone, role, is_verified)
VALUES ($1, $2, $3, $4, $5, 'EMPLOYEE', TRUE)
ON CONFLICT (email) DO UPDATE SET
password = EXCLUDED.password,
role = 'EMPLOYEE',
is_verified = TRUE`,
['employee1@thetiptop.com', employeePassword, 'Marie', 'Dupont', '+33198765432']
);
console.log(' ✅ Employé créé: employee1@thetiptop.com');
// Employé 2
await pool.query(
`INSERT INTO users (email, password, first_name, last_name, phone, role, is_verified)
VALUES ($1, $2, $3, $4, $5, 'EMPLOYEE', TRUE)
ON CONFLICT (email) DO UPDATE SET
password = EXCLUDED.password,
role = 'EMPLOYEE',
is_verified = TRUE`,
['employee2@thetiptop.com', employeePassword, 'Pierre', 'Martin', '+33187654321']
);
console.log(' ✅ Employé créé: employee2@thetiptop.com');
console.log('✅ Utilisateurs créés avec succès');
}
/**
* Génère un code de ticket unique
*/
function generateCode() {
const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
let code = 'TT';
for (let i = 0; i < 8; i++) {
code += chars[Math.floor(Math.random() * chars.length)];
}
return code;
}
/**
* Génère les 500,000 tickets
*/
async function generateTickets() {
console.log('🎫 Génération des 500,000 tickets...');
const prizesResult = await pool.query('SELECT id, name, type FROM prizes');
const prizes = {};
prizesResult.rows.forEach(p => prizes[p.type] = p);
// Calculer la distribution
const distribution = {};
let total = 0;
for (const [type, config] of Object.entries(PRIZE_DISTRIBUTION)) {
const count = Math.floor(TOTAL_TICKETS * config.percentage);
distribution[type] = count;
total += count;
}
// Ajuster si nécessaire
if (total < TOTAL_TICKETS) {
distribution['INFUSEUR'] += (TOTAL_TICKETS - total);
}
// Afficher la distribution
console.log(' 📊 Distribution:');
for (const [type, count] of Object.entries(distribution)) {
console.log(` - ${type}: ${count.toLocaleString('fr-FR')} tickets`);
}
// Générer les tickets
let generated = 0;
const start = Date.now();
for (const [type, count] of Object.entries(distribution)) {
const prize = prizes[type];
if (!prize) {
console.log(` ⚠️ Lot "${type}" introuvable, ignoré`);
continue;
}
for (let i = 0; i < count; i += BATCH_SIZE) {
const batch = Math.min(BATCH_SIZE, count - i);
const values = [];
for (let j = 0; j < batch; j++) {
const code = generateCode();
values.push(`('${code}', '${prize.id}', NULL)`);
}
const query = `INSERT INTO tickets (code, prize_id, status) VALUES ${values.join(', ')}`;
await pool.query(query);
generated += batch;
// Afficher la progression tous les 50,000 tickets
if (generated % 50000 === 0) {
console.log(` 📈 Progression: ${generated.toLocaleString('fr-FR')} / ${TOTAL_TICKETS.toLocaleString('fr-FR')}`);
}
}
}
const duration = ((Date.now() - start) / 1000).toFixed(2);
console.log(`${generated.toLocaleString('fr-FR')} tickets générés en ${duration}s`);
}
/**
* Applique les migrations (newsletter, email campaigns, etc.)
*/
async function applyMigrations() {
console.log('🔄 Application des migrations...');
try {
// Add is_active column to users if not exists
await pool.query(`
ALTER TABLE users ADD COLUMN IF NOT EXISTS is_active BOOLEAN DEFAULT TRUE
`);
console.log(' ✅ Colonne is_active ajoutée à users');
// Newsletter table
await pool.query(`
CREATE TABLE IF NOT EXISTS newsletters (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) UNIQUE NOT NULL,
is_subscribed BOOLEAN DEFAULT TRUE,
subscribed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
unsubscribed_at TIMESTAMP,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`);
console.log(' ✅ Table newsletters créée');
// Email templates table
await pool.query(`
CREATE TABLE IF NOT EXISTS email_templates (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(255) NOT NULL,
subject VARCHAR(500) NOT NULL,
html_content TEXT NOT NULL,
text_content TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`);
console.log(' ✅ Table email_templates créée');
// Email campaigns table
await pool.query(`
CREATE TABLE IF NOT EXISTS email_campaigns (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(255) NOT NULL,
template_id UUID REFERENCES email_templates(id),
status VARCHAR(50) DEFAULT 'DRAFT',
scheduled_at TIMESTAMP,
sent_at TIMESTAMP,
total_recipients INTEGER DEFAULT 0,
sent_count INTEGER DEFAULT 0,
failed_count INTEGER DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`);
console.log(' ✅ Table email_campaigns créée');
// Email campaign recipients table
await pool.query(`
CREATE TABLE IF NOT EXISTS email_campaign_recipients (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
campaign_id UUID REFERENCES email_campaigns(id) ON DELETE CASCADE,
email VARCHAR(255) NOT NULL,
status VARCHAR(50) DEFAULT 'PENDING',
sent_at TIMESTAMP,
error_message TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`);
console.log(' ✅ Table email_campaign_recipients créée');
// Grand prize draws table
await pool.query(`
CREATE TABLE IF NOT EXISTS grand_prize_draws (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
winner_id UUID REFERENCES users(id),
draw_date TIMESTAMP NOT NULL,
prize_description TEXT,
is_claimed BOOLEAN DEFAULT FALSE,
claimed_at TIMESTAMP,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`);
console.log(' ✅ Table grand_prize_draws créée');
console.log('✅ Migrations appliquées avec succès');
} catch (error) {
console.log(' ⚠️ Certaines migrations existent déjà:', error.message);
}
}
/**
* Fonction principale d'initialisation
*/
export async function initDatabase() {
console.log('\n🚀 ========================================');
console.log(' AUTO-INITIALISATION DE LA BASE DE DONNÉES');
console.log(' ========================================\n');
try {
// 1. Vérifier si les tables existent
const hasTables = await tablesExist();
if (!hasTables) {
console.log('📋 Tables non trouvées, création en cours...\n');
await createTables();
} else {
console.log('✅ Tables déjà existantes\n');
}
// 2. Vérifier si les utilisateurs existent
const hasUsers = await usersExist();
if (!hasUsers) {
console.log('👥 Utilisateurs non trouvés, création en cours...\n');
await createDefaultUsers();
} else {
console.log('✅ Utilisateurs déjà existants\n');
}
// 3. Vérifier si les tickets existent
const hasTickets = await ticketsExist();
if (!hasTickets) {
console.log('🎫 Tickets non trouvés, génération en cours...\n');
await generateTickets();
} else {
console.log('✅ Tickets déjà générés\n');
}
// 4. Appliquer les migrations
await applyMigrations();
console.log('\n✨ ========================================');
console.log(' BASE DE DONNÉES INITIALISÉE AVEC SUCCÈS');
console.log(' ========================================');
console.log('\n🔐 Comptes disponibles:');
console.log(' Admin: admin@thetiptop.com / Admin123!');
console.log(' Employé 1: employee1@thetiptop.com / Employee123!');
console.log(' Employé 2: employee2@thetiptop.com / Employee123!\n');
return true;
} catch (error) {
console.error('\n❌ Erreur lors de l\'initialisation:', error.message);
console.error(error.stack);
return false;
}
}
// Si exécuté directement (pas importé)
if (process.argv[1] === fileURLToPath(import.meta.url)) {
initDatabase()
.then(() => process.exit(0))
.catch(() => process.exit(1));
}