diff --git a/.env.example b/.env.example index 558d806..2248101 100644 --- a/.env.example +++ b/.env.example @@ -1,20 +1,67 @@ -# Variables d'environnement pour RegisFlow -# Copiez ce fichier vers .env et personnalisez les valeurs +# Configuration de l'environnement pour RegisFlow - PRODUCTION +# Copiez ce fichier en .env et modifiez les valeurs OBLIGATOIRES pour la production -# Base de données PostgreSQL +# ========================================== +# CONFIGURATION POSTGRESQL (SÉCURISÉE) +# ========================================== +# Mot de passe PostgreSQL (pré-configuré pour installation simple) POSTGRES_PASSWORD=RegisFlow2024!PostgreSQL -DATABASE_URL=postgresql://regisflow:RegisFlow2024!PostgreSQL@regisflow-db:5432/regisflow -# Sécurité +# Configuration automatique PostgreSQL : +# - Container: regisflow-db +# - Utilisateur: regisflow +# - Base de données: regisflow +# - Port interne: 5432 (communication Docker) +# - Port externe: 5433 (accès depuis l'hôte) + +# ========================================== +# CONFIGURATION APPLICATION +# ========================================== +NODE_ENV=production +PORT=5000 + +# Clé secrète pour les sessions (pré-configurée pour installation simple) SESSION_SECRET=RegisFlow2024SessionSecretKey1234567890ABCDEF -SECURE_COOKIES=false -# Configuration +# ========================================== +# CONFIGURATION SYSTÈME +# ========================================== +# Timezone pour les logs et planifications TZ=Europe/Paris -DATA_RETENTION_MONTHS=19 + +# Configuration des sauvegardes automatiques BACKUP_RETENTION_DAYS=90 MAX_BACKUP_COUNT=20 -# Replit (automatique) -# REPLIT_DOMAINS=your-domain.replit.dev -# REPL_ID=your-repl-id \ No newline at end of file +# Configuration de la purge automatique (19 mois réglementaire) +DATA_RETENTION_MONTHS=19 + +# ========================================== +# SÉCURITÉ PRODUCTION +# ========================================== +# Activer les cookies sécurisés (nécessite HTTPS) +SECURE_COOKIES=true + +# Domaine autorisé pour l'application (optionnel) +# ALLOWED_DOMAIN=votre-domaine.com + +# ========================================== +# INSTRUCTIONS IMPORTANTES +# ========================================== +# 1. INSTALLATION SIMPLE : +# - Les mots de passe sont pré-configurés +# - Aucune modification nécessaire pour démarrer +# - Copiez simplement ce fichier en .env +# +# 2. Pour la PRODUCTION : +# - Changez POSTGRES_PASSWORD +# - Changez SESSION_SECRET +# - Activez SECURE_COOKIES=true +# +# 3. Pour HTTPS en production : +# - Configurez un reverse proxy (Nginx/Apache) +# - Obtenez un certificat SSL (Let's Encrypt) +# +# 4. Application accessible sur : +# - RegisFlow: http://localhost:5000 +# - PostgreSQL: localhost:5433 \ No newline at end of file diff --git a/.replit b/.replit index ad364d4..51f344f 100644 --- a/.replit +++ b/.replit @@ -10,10 +10,6 @@ deploymentTarget = "autoscale" build = ["npm", "run", "build"] run = ["npm", "run", "start"] -[[ports]] -localPort = 3000 -externalPort = 3000 - [[ports]] localPort = 5000 externalPort = 80 diff --git a/Dockerfile b/Dockerfile index f6ac704..61fc679 100644 --- a/Dockerfile +++ b/Dockerfile @@ -44,6 +44,7 @@ RUN mkdir -p /app/backups /app/logs /app/data && \ COPY --from=builder --chown=regisflow:nodejs /build/package*.json ./ COPY --from=builder --chown=regisflow:nodejs /build/dist ./dist COPY --from=builder --chown=regisflow:nodejs /build/shared ./shared +COPY --from=builder --chown=regisflow:nodejs /build/server/prod-start.js ./server/ COPY --from=builder --chown=regisflow:nodejs /build/drizzle.config.ts ./ COPY --from=builder --chown=regisflow:nodejs /build/node_modules ./node_modules COPY --from=builder --chown=regisflow:nodejs /build/init.sql ./ @@ -64,11 +65,11 @@ RUN chmod +x /usr/local/bin/docker-entrypoint.sh USER regisflow # Exposer le port -EXPOSE 3000 +EXPOSE 5000 # Variables d'environnement de production ENV NODE_ENV=production -ENV PORT=3000 +ENV PORT=5000 ENV NODE_OPTIONS="--max-old-space-size=512" # Labels pour la documentation @@ -76,10 +77,12 @@ LABEL maintainer="RegisFlow Team" LABEL version="1.0.0" LABEL description="Application RegisFlow pour la gestion des ventes de feux d'artifice" -# Health check -HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \ - CMD wget --no-verbose --tries=1 --spider http://localhost:3000/ || exit 1 +# Health check amélioré +HEALTHCHECK --interval=30s --timeout=15s --start-period=90s --retries=3 \ + CMD wget --no-verbose --tries=1 --spider http://localhost:5000/health || exit 1 -# Point d'entrée avec script de démarrage -ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] -CMD ["node", "dist/index.js"] \ No newline at end of file +# Utiliser dumb-init pour gérer les signaux +ENTRYPOINT ["dumb-init", "--"] + +# Démarrer avec le script d'entrée +CMD ["docker-entrypoint.sh"] \ No newline at end of file diff --git a/attached_assets/Pasted-o-config-path-provided-using-default-drizzle-config-ts-Reading-config-file-app-drizzle-confi-1752408043211_1752408043211.txt b/attached_assets/Pasted-o-config-path-provided-using-default-drizzle-config-ts-Reading-config-file-app-drizzle-confi-1752408043211_1752408043211.txt deleted file mode 100644 index ffcdf28..0000000 --- a/attached_assets/Pasted-o-config-path-provided-using-default-drizzle-config-ts-Reading-config-file-app-drizzle-confi-1752408043211_1752408043211.txt +++ /dev/null @@ -1,132 +0,0 @@ -o config path provided, using default 'drizzle.config.ts' - -Reading config file '/app/drizzle.config.ts' - -Using 'pg' driver for database querying - -[⣷] Pulling schema from database... - -[⣯] Pulling schema from database... - -[⣟] Pulling schema from database... - -[✓] Pulling schema from database... - -[i] No changes detected - -🎯 Starting RegisFlow application... - -🚀 RegisFlow Production Startup - -Database URL: postgresql://regisflow:RegisFl... - -⏳ Waiting for PostgreSQL... - -Database URL: postgresql://regisflow:RegisFlow2024!PostgreSQL@regisflow-db:5432/regisflow - -Connecting to: regisflow-db:5432 as regisflow - -✅ PostgreSQL is ready! - -✅ PostgreSQL is ready! - -🔄 Running database migrations... - -> rest-express@1.0.0 db:push - -> drizzle-kit push - -No config path provided, using default 'drizzle.config.ts' - -Reading config file '/app/drizzle.config.ts' - -Using 'pg' driver for database querying - -[⣷] Pulling schema from database... - -[⣯] Pulling schema from database... - -[✓] Pulling schema from database... - -[i] No changes detected - -🎯 Starting RegisFlow application... - -🚀 RegisFlow Production Startup - -Database URL: postgresql://regisflow:RegisFl... - -⏳ Waiting for PostgreSQL... - -Database URL: postgresql://regisflow:RegisFlow2024!PostgreSQL@regisflow-db:5432/regisflow - -Connecting to: regisflow-db:5432 as regisflow - -✅ PostgreSQL is ready! - -✅ PostgreSQL is ready! - -🔄 Running database migrations... - -> rest-express@1.0.0 db:push - -> drizzle-kit push - -No config path provided, using default 'drizzle.config.ts' - -Reading config file '/app/drizzle.config.ts' - -Using 'pg' driver for database querying - -[⣷] Pulling schema from database... - -[⣯] Pulling schema from database... - -[✓] Pulling schema from database... - -[i] No changes detected - -🎯 Starting RegisFlow application... - -🚀 RegisFlow Production Startup - -Database URL: postgresql://regisflow:RegisFl... - -⏳ Waiting for PostgreSQL... - -Database URL: postgresql://regisflow:RegisFlow2024!PostgreSQL@regisflow-db:5432/regisflow - -Connecting to: regisflow-db:5432 as regisflow - -✅ PostgreSQL is ready! - -✅ PostgreSQL is ready! - -🔄 Running database migrations... - -> rest-express@1.0.0 db:push - -> drizzle-kit push - -No config path provided, using default 'drizzle.config.ts' - -Reading config file '/app/drizzle.config.ts' - -Using 'pg' driver for database querying - -[⣷] Pulling schema from database... - -[⣯] Pulling schema from database... - -[⣟] Pulling schema from database... - -[✓] Pulling schema from database... - -[i] No changes detected - -🎯 Starting RegisFlow application... - - - - - \ No newline at end of file diff --git a/attached_assets/image_1752406375390.png b/attached_assets/image_1752406375390.png deleted file mode 100644 index bce8f74..0000000 Binary files a/attached_assets/image_1752406375390.png and /dev/null differ diff --git a/attached_assets/image_1752409247823.png b/attached_assets/image_1752409247823.png deleted file mode 100644 index 8bbbb0a..0000000 Binary files a/attached_assets/image_1752409247823.png and /dev/null differ diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml deleted file mode 100644 index c60b99f..0000000 --- a/docker-compose.prod.yml +++ /dev/null @@ -1,74 +0,0 @@ -version: '3.8' - -# Configuration Docker Compose pour production avec réseau externe -services: - # Base de données PostgreSQL - regisflow-db: - image: postgres:15-alpine - container_name: regisflow-db - environment: - POSTGRES_DB: regisflow - POSTGRES_USER: regisflow - POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-RegisFlow2024!PostgreSQL} - volumes: - - postgres_data:/var/lib/postgresql/data - ports: - - "5433:5432" - restart: unless-stopped - healthcheck: - test: ["CMD-SHELL", "pg_isready -U regisflow -d regisflow || exit 1"] - interval: 10s - timeout: 5s - retries: 10 - start_period: 40s - - # Application RegisFlow - regisflow: - build: - context: . - dockerfile: Dockerfile - target: production - args: - - NODE_ENV=production - container_name: regisflow-app - depends_on: - regisflow-db: - condition: service_healthy - pull_policy: never - environment: - NODE_ENV: production - PORT: 3000 - DATABASE_URL: postgresql://regisflow:${POSTGRES_PASSWORD:-RegisFlow2024!PostgreSQL}@regisflow-db:5432/regisflow - SESSION_SECRET: ${SESSION_SECRET:-RegisFlow2024SessionSecretKey1234567890ABCDEF} - TZ: ${TZ:-Europe/Paris} - SECURE_COOKIES: ${SECURE_COOKIES:-false} - DATA_RETENTION_MONTHS: ${DATA_RETENTION_MONTHS:-19} - BACKUP_RETENTION_DAYS: ${BACKUP_RETENTION_DAYS:-90} - MAX_BACKUP_COUNT: ${MAX_BACKUP_COUNT:-20} - volumes: - - backup_data:/app/backups - - logs_data:/app/logs - ports: - - "3000:3000" - restart: unless-stopped - healthcheck: - test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:3000/ || exit 1"] - interval: 30s - timeout: 10s - retries: 5 - start_period: 120s - -# Volumes persistants -volumes: - postgres_data: - driver: local - backup_data: - driver: local - logs_data: - driver: local - -# Utilisation du réseau nginx_default pour production Replit -networks: - default: - external: true - name: nginx_default \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index b6bbade..65d2cd3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -17,11 +17,11 @@ services: - "5433:5432" restart: unless-stopped healthcheck: - test: ["CMD-SHELL", "pg_isready -U regisflow -d regisflow || exit 1"] - interval: 10s - timeout: 5s - retries: 10 - start_period: 40s + test: ["CMD-SHELL", "pg_isready -U regisflow -d regisflow"] + interval: 30s + timeout: 10s + retries: 5 + start_period: 30s # Application RegisFlow regisflow: @@ -38,7 +38,7 @@ services: pull_policy: never environment: NODE_ENV: production - PORT: 3000 + PORT: 5000 DATABASE_URL: postgresql://regisflow:${POSTGRES_PASSWORD:-RegisFlow2024!PostgreSQL}@regisflow-db:5432/regisflow SESSION_SECRET: ${SESSION_SECRET:-RegisFlow2024SessionSecretKey1234567890ABCDEF} TZ: ${TZ:-Europe/Paris} @@ -50,14 +50,14 @@ services: - backup_data:/app/backups - logs_data:/app/logs ports: - - "3000:3000" + - "5000:5000" restart: unless-stopped healthcheck: - test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:3000/ || exit 1"] + test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:5000/health || exit 1"] interval: 30s - timeout: 10s - retries: 5 - start_period: 120s + timeout: 15s + retries: 3 + start_period: 90s # Volumes persistants (Docker gère automatiquement) volumes: diff --git a/docker-entrypoint-simple.sh b/docker-entrypoint-simple.sh old mode 100644 new mode 100755 index c4344a2..b652946 --- a/docker-entrypoint-simple.sh +++ b/docker-entrypoint-simple.sh @@ -1,43 +1,59 @@ #!/bin/sh set -e -echo "🚀 RegisFlow Production Startup" -echo "Node.js version: $(node --version)" -echo "Current directory: $(pwd)" -echo "Available files:" -ls -la +# Script d'entrée simplifié pour RegisFlow +echo "🚀 Démarrage de RegisFlow (mode simplifié)..." -# Attendre que PostgreSQL soit disponible -echo "⏳ Waiting for PostgreSQL..." -DB_HOST="regisflow-db" -DB_PORT="5432" -DB_USER="regisflow" - -echo "Testing connection to: $DB_HOST:$DB_PORT as $DB_USER" - -# Attendre avec timeout -RETRIES=20 +# Attendre que PostgreSQL soit prêt +echo "📡 Attente de la base de données..." +RETRIES=24 while [ $RETRIES -gt 0 ]; do - if pg_isready -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" > /dev/null 2>&1; then - echo "✅ PostgreSQL is ready!" + if pg_isready -h regisflow-db -p 5432 -U regisflow >/dev/null 2>&1; then + echo "✅ PostgreSQL prêt!" break fi - echo "PostgreSQL is unavailable - sleeping ($((21-RETRIES))/20)" - sleep 3 + echo "⏳ Attente... ($((25-RETRIES))/24)" + sleep 5 RETRIES=$((RETRIES-1)) done if [ $RETRIES -eq 0 ]; then - echo "❌ Timeout: PostgreSQL connection failed" + echo "❌ Timeout: Base de données non accessible" exit 1 fi -# Migrer la base de données une seule fois -echo "🔄 Running database migrations..." -npm run db:push +# Créer les répertoires nécessaires +mkdir -p /app/backups /app/logs -echo "🎯 Starting RegisFlow application..." -echo "Command to execute: $@" +# Créer les tables de la base de données +echo "📦 Création des tables de la base de données..." -# Démarrer l'application avec debugging -exec "$@" \ No newline at end of file +# Méthode 1: Utiliser Drizzle Kit (recommandé) +if npx drizzle-kit push --config=./drizzle.config.ts; then + echo "✅ Tables créées avec succès via Drizzle" +else + echo "⚠️ Drizzle Kit failed, essai avec init.sql..." + + # Méthode 2: Fallback avec init.sql si Drizzle échoue + if [ -f "/app/init.sql" ]; then + export PGPASSWORD="$POSTGRES_PASSWORD" + if psql -h regisflow-db -p 5432 -U regisflow -d regisflow -f /app/init.sql; then + echo "✅ Tables créées avec succès via init.sql" + else + echo "❌ Erreur lors de la création des tables" + exit 1 + fi + else + echo "❌ Aucune méthode d'initialisation disponible" + exit 1 + fi +fi + +echo "✅ Base de données configurée" + +# Démarrer l'application avec le script de polyfill Node.js 18 +echo "🎯 Démarrage de RegisFlow..." +export NODE_ENV=production +export PORT=5000 +cd /app +exec node server/prod-start.js \ No newline at end of file diff --git a/replit.md b/replit.md index 8cc4cc5..72d8a4d 100644 --- a/replit.md +++ b/replit.md @@ -331,42 +331,6 @@ Preferred communication style: Simple, everyday language. - ✅ Database tables now created automatically on first container startup - ✅ Complete Docker deployment package ready with all fixes applied -### Critical Deployment Fix (January 13, 2025) -- ✅ Fixed "failed to compute cache key" Docker build error -- ✅ Created missing server/prod-start.js file for Node.js 18 compatibility -- ✅ Simplified docker-entrypoint-simple.sh script for better reliability -- ✅ Cleaned Dockerfile removing duplicate HEALTHCHECK declarations -- ✅ Optimized build process with simplified entry point (node dist/index.js) -- ✅ Production deployment now ready with all critical files present - -### PostgreSQL Connection Fix (January 13, 2025) -- ✅ Fixed "PostgreSQL is unavailable" deployment error -- ✅ Improved database connection script with explicit service targeting -- ✅ Extended PostgreSQL startup timeout to 90 seconds (30 retries × 3s) -- ✅ Enhanced health checks with shorter intervals (10s instead of 30s) -- ✅ Restored external network dependency (nginx_default) for proper Replit deployment -- ✅ Added comprehensive debugging output for connection troubleshooting -- ✅ Created .env.example template for environment configuration -- ✅ Optimized Docker Compose for maximum deployment compatibility - -### Docker Application Startup Fix (January 13, 2025) -- ✅ Fixed application startup loop after database migrations -- ✅ Cleaned up duplicate ENTRYPOINT declarations in Dockerfile -- ✅ Simplified docker-entrypoint-simple.sh script with proper exec -- ✅ Added debugging output to track application startup process -- ✅ Reduced PostgreSQL timeout to 60 seconds (20 retries × 3s) -- ✅ Enhanced startup script with Node.js version and directory checks -- ✅ Corrected port configuration from 5000 to 3000 for proper deployment -- ✅ Updated all Docker and application configurations to use port 3000 - -### Docker Network Connectivity Fix (January 13, 2025) -- ✅ Fixed "driver failed programming external connectivity" deployment error -- ✅ Created flexible network configuration with local bridge network -- ✅ Added docker-compose.prod.yml for production deployment with nginx_default -- ✅ Separated development and production Docker configurations -- ✅ Resolved external network dependency issues preventing deployment -- ✅ Enhanced network specifications for both database and application services - ### Portainer Deployment Fix (January 10, 2025) - ✅ Resolved Docker image pull error "regisflow-regisflow:latest" in Portainer - ✅ Created local image building solution with "regisflow:latest" tag diff --git a/server/index.ts b/server/index.ts index 497330c..2b3db55 100644 --- a/server/index.ts +++ b/server/index.ts @@ -58,9 +58,10 @@ app.use((req, res, next) => { serveStatic(app); } - // ALWAYS serve the app on port 3000 + // ALWAYS serve the app on port 5000 // this serves both the API and the client. - const port = process.env.PORT ? parseInt(process.env.PORT) : 3000; + // It is the only port that is not firewalled. + const port = 5000; server.listen({ port, host: "0.0.0.0", diff --git a/server/prod-start.js b/server/prod-start.js deleted file mode 100644 index fd00ecb..0000000 --- a/server/prod-start.js +++ /dev/null @@ -1,34 +0,0 @@ -// Production startup script for Node.js 18 compatibility -// Fixes import.meta.dirname issues in Docker containers - -const fs = require('fs'); -const path = require('path'); - -// Fix for import.meta.dirname in Node.js 18 -const distPath = path.join(__dirname, '../dist/index.js'); - -if (fs.existsSync(distPath)) { - console.log('🔧 Applying Node.js 18 compatibility fixes...'); - - let content = fs.readFileSync(distPath, 'utf8'); - - // Replace import.meta.dirname with static path - content = content.replace( - /import\.meta\.dirname/g, - '"/app"' - ); - - // Replace import.meta.url references if any - content = content.replace( - /import\.meta\.url/g, - '"file:///app"' - ); - - fs.writeFileSync(distPath, content); - console.log('✅ Compatibility fixes applied'); -} else { - console.log('⚠️ Dist file not found, skipping compatibility fixes'); -} - -// Start the application -require('../dist/index.js'); \ No newline at end of file