"fix-startup-init"
This commit is contained in:
@@ -1,32 +1,2 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
set -e
|
|
||||||
|
|
||||||
echo "▶ NotesFrais backend — démarrage"
|
|
||||||
|
|
||||||
# Attendre que PostgreSQL soit prêt (Coolify peut démarrer les conteneurs en parallèle)
|
|
||||||
MAX=30
|
|
||||||
i=0
|
|
||||||
until node -e "
|
|
||||||
const { Client } = require('pg');
|
|
||||||
const c = new Client({ connectionString: process.env.DATABASE_URL });
|
|
||||||
c.connect().then(() => { c.end(); process.exit(0); }).catch(() => process.exit(1));
|
|
||||||
" 2>/dev/null; do
|
|
||||||
i=$((i+1))
|
|
||||||
if [ $i -ge $MAX ]; then
|
|
||||||
echo "✗ PostgreSQL inaccessible après ${MAX} tentatives — abandon"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo " PostgreSQL non prêt, attente (${i}/${MAX})…"
|
|
||||||
sleep 2
|
|
||||||
done
|
|
||||||
|
|
||||||
echo "✓ PostgreSQL prêt"
|
|
||||||
|
|
||||||
# Migration (idempotente — IF NOT EXISTS sur toutes les créations)
|
|
||||||
echo "▶ Migration de la base de données…"
|
|
||||||
node dist/scripts/migrate.js
|
|
||||||
echo "✓ Migration terminée"
|
|
||||||
|
|
||||||
# Démarrage du serveur
|
|
||||||
echo "▶ Démarrage du serveur Express sur le port ${PORT:-3001}"
|
|
||||||
exec node dist/index.js
|
exec node dist/index.js
|
||||||
|
|||||||
+51
-5
@@ -4,8 +4,9 @@ import cors from 'cors';
|
|||||||
import helmet from 'helmet';
|
import helmet from 'helmet';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
|
import { Pool } from 'pg';
|
||||||
import { config } from './config';
|
import { config } from './config';
|
||||||
import { testConnection } from './db';
|
import { db, testConnection } from './db';
|
||||||
|
|
||||||
// Routes
|
// Routes
|
||||||
import authRoutes from './routes/auth';
|
import authRoutes from './routes/auth';
|
||||||
@@ -40,16 +41,36 @@ app.get('/api/health', (_req, res) => res.json({ status: 'ok', version: '1.0.0',
|
|||||||
// ─── Gestionnaire d'erreurs global ────────────────────────────
|
// ─── Gestionnaire d'erreurs global ────────────────────────────
|
||||||
app.use((err: Error, _req: express.Request, res: express.Response, _next: express.NextFunction) => {
|
app.use((err: Error, _req: express.Request, res: express.Response, _next: express.NextFunction) => {
|
||||||
console.error('[Error]', err.stack);
|
console.error('[Error]', err.stack);
|
||||||
// Include error message always (for debug) — revert to 'Erreur serveur interne' in production once stable
|
|
||||||
res.status(500).json({
|
res.status(500).json({
|
||||||
error: err.message,
|
error: err.message,
|
||||||
type: err.constructor.name,
|
type: err.constructor.name,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ─── Initialisation DB + migration (arrière-plan) ─────────────
|
||||||
|
async function runMigration(): Promise<void> {
|
||||||
|
const sqlPath = path.join(__dirname, 'migrations/001_init.sql');
|
||||||
|
const sql = fs.readFileSync(sqlPath, 'utf8');
|
||||||
|
await db.query(sql);
|
||||||
|
console.log('✅ Migration terminée');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function waitForDb(maxAttempts = 30, delayMs = 2000): Promise<void> {
|
||||||
|
for (let i = 1; i <= maxAttempts; i++) {
|
||||||
|
try {
|
||||||
|
await testConnection();
|
||||||
|
return;
|
||||||
|
} catch {
|
||||||
|
console.log(` PostgreSQL non prêt (${i}/${maxAttempts}), attente...`);
|
||||||
|
await new Promise(r => setTimeout(r, delayMs));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Error(`PostgreSQL inaccessible après ${maxAttempts} tentatives`);
|
||||||
|
}
|
||||||
|
|
||||||
// ─── Démarrage ────────────────────────────────────────────────
|
// ─── Démarrage ────────────────────────────────────────────────
|
||||||
async function start() {
|
async function start() {
|
||||||
// Créer les répertoires uploads (ici pour éviter un crash module-level)
|
// Créer les répertoires uploads
|
||||||
try {
|
try {
|
||||||
fs.mkdirSync(path.join(config.uploadsDir, 'images'), { recursive: true });
|
fs.mkdirSync(path.join(config.uploadsDir, 'images'), { recursive: true });
|
||||||
fs.mkdirSync(path.join(config.uploadsDir, 'pdfs'), { recursive: true });
|
fs.mkdirSync(path.join(config.uploadsDir, 'pdfs'), { recursive: true });
|
||||||
@@ -57,7 +78,32 @@ async function start() {
|
|||||||
console.warn('Avertissement: impossible de créer les répertoires uploads:', err.message);
|
console.warn('Avertissement: impossible de créer les répertoires uploads:', err.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
app.listen(config.port, async () => {
|
// ── Bind du port IMMÉDIATEMENT ─────────────────────────────
|
||||||
|
app.listen(config.port, () => {
|
||||||
console.log(`🚀 NotesFrais backend démarré sur le port ${config.port}`);
|
console.log(`🚀 NotesFrais backend démarré sur le port ${config.port}`);
|
||||||
console.log(` Environnement : ${config.nodeEnv}`);
|
console.log(` Environnement : ${config.nodeEnv}`);
|
||||||
console.log(` Frontend autorisé : ${
|
console.log(` Frontend autorisé : ${config.frontendUrl}`);
|
||||||
|
console.log(` DATABASE_URL: ${process.env.DATABASE_URL
|
||||||
|
? process.env.DATABASE_URL.replace(/:([^@]+)@/, ':***@')
|
||||||
|
: '[non défini — utilise défaut localhost]'}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
// ── Initialisation DB en arrière-plan ─────────────────────
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
await waitForDb();
|
||||||
|
await runMigration();
|
||||||
|
console.log('✅ Base de données prête');
|
||||||
|
} catch (err: any) {
|
||||||
|
console.error('⚠️ Initialisation DB échouée (non bloquant):', err.message);
|
||||||
|
// Le serveur continue — les routes retourneront des 500 si la DB est inaccessible
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
|
||||||
|
start().catch((err) => {
|
||||||
|
console.error('Impossible de démarrer le serveur :', err.message);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default app;
|
||||||
|
|||||||
Reference in New Issue
Block a user