diff --git a/Dockerfile b/Dockerfile index 3b5b314..576f7a4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -84,8 +84,8 @@ COPY --from=build --chown=nextjs:nodejs /app/shared ./shared # Create symlink for public files to be accessible from dist RUN ln -sf /app/dist/public /app/dist/public -# Create uploads directory with proper permissions -RUN mkdir -p /app/uploads && chown -R nextjs:nodejs /app/uploads +# Create uploads and backups directories with proper permissions +RUN mkdir -p /app/uploads /app/backups && chown -R nextjs:nodejs /app/uploads /app/backups # Switch to non-root user USER nextjs @@ -94,9 +94,9 @@ USER nextjs EXPOSE 3000 ENV PORT=3000 -# Install wget for health check +# Install wget for health check and postgresql-client for pg_dump USER root -RUN apk add --no-cache wget +RUN apk add --no-cache wget postgresql-client USER nextjs # Health check diff --git a/attached_assets/Pasted--Host-Administration-User-related-Environment-related-Registries-Logs-Notific-1755118963207_1755118963207.txt b/attached_assets/Pasted--Host-Administration-User-related-Environment-related-Registries-Logs-Notific-1755118963207_1755118963207.txt new file mode 100644 index 0000000..d523f54 --- /dev/null +++ b/attached_assets/Pasted--Host-Administration-User-related-Environment-related-Registries-Logs-Notific-1755118963207_1755118963207.txt @@ -0,0 +1,228 @@ + + +Host + +Administration + +User-related + + +Environment-related + +Registries + +Logs + +Notifications + +Settings + +New version available 2.27.9 +DismissSee what's new +Community Edition +2.27.6 LTS +Containers>logiflow-logiflow-1>Logs +Container logs + + +admin +Log viewer settings +Auto-refresh logs +Wrap lines +Display timestamps +Fetch +All logs +Search +Filter... +Lines +100 +Actions + + + + + path: '/app/backups' + +} + +Node.js v20.19.4 + +🔗 Database initialization: { + + NODE_ENV: 'production', + + isProduction: true, + + hasDbUrl: true, + + dbHost: 'logiflow-db' + +} + +🐳 PRODUCTION: Using standard PostgreSQL + +✅ PostgreSQL connection test successful + +🔗 Database initialization: { + + NODE_ENV: 'production', + + isProduction: true, + + hasDbUrl: true, + + dbHost: 'logiflow-db:5432' + +} + +✅ Using DatabaseStorage (production PostgreSQL) + + node:fs:1372 + + const result = binding.mkdir( + + ^ + +Error: EACCES: permission denied, mkdir '/app/backups' + + at Object.mkdirSync (node:fs:1372:26) + + at BackupService.ensureBackupDirectory (file:///app/dist/index.js:3147:10) + + at new BackupService (file:///app/dist/index.js:3142:10) + + at file:///app/dist/index.js:3283:21 + + at process.processTicksAndRejections (node:internal/process/task_queues:95:5) { + + errno: -13, + + code: 'EACCES', + + syscall: 'mkdir', + + path: '/app/backups' + +} + +Node.js v20.19.4 + +🔗 Database initialization: { + + NODE_ENV: 'production', + + isProduction: true, + + hasDbUrl: true, + + dbHost: 'logiflow-db' + +} + +🐳 PRODUCTION: Using standard PostgreSQL + +✅ PostgreSQL connection test successful + +🔗 Database initialization: { + + NODE_ENV: 'production', + + isProduction: true, + + hasDbUrl: true, + + dbHost: 'logiflow-db:5432' + +} + +✅ Using DatabaseStorage (production PostgreSQL) + + node:fs:1372 + + const result = binding.mkdir( + + ^ + +Error: EACCES: permission denied, mkdir '/app/backups' + + at Object.mkdirSync (node:fs:1372:26) + + at BackupService.ensureBackupDirectory (file:///app/dist/index.js:3147:10) + + at new BackupService (file:///app/dist/index.js:3142:10) + + at file:///app/dist/index.js:3283:21 + + at process.processTicksAndRejections (node:internal/process/task_queues:95:5) { + + errno: -13, + + code: 'EACCES', + + syscall: 'mkdir', + + path: '/app/backups' + +} + +Node.js v20.19.4 + +🔗 Database initialization: { + + NODE_ENV: 'production', + + isProduction: true, + + hasDbUrl: true, + + dbHost: 'logiflow-db' + +} + +🐳 PRODUCTION: Using standard PostgreSQL + +✅ PostgreSQL connection test successful + +🔗 Database initialization: { + + NODE_ENV: 'production', + + isProduction: true, + + hasDbUrl: true, + + dbHost: 'logiflow-db:5432' + +} + +✅ Using DatabaseStorage (production PostgreSQL) + + node:fs:1372 + + const result = binding.mkdir( + + ^ + +Error: EACCES: permission denied, mkdir '/app/backups' + + at Object.mkdirSync (node:fs:1372:26) + + at BackupService.ensureBackupDirectory (file:///app/dist/index.js:3147:10) + + at new BackupService (file:///app/dist/index.js:3142:10) + + at file:///app/dist/index.js:3283:21 + + at process.processTicksAndRejections (node:internal/process/task_queues:95:5) { + + errno: -13, + + code: 'EACCES', + + syscall: 'mkdir', + + path: '/app/backups' + +} + +Node.js v20.19.4 \ No newline at end of file diff --git a/replit.md b/replit.md index eaa00fa..3f717b6 100644 --- a/replit.md +++ b/replit.md @@ -27,6 +27,7 @@ La plateforme fournit une gestion robuste des flux de travail de livraison avec - **Base de données** : Table `DATABASE_BACKUPS` avec suivi complet des sauvegardes - **Navigation** : Ajouté dans la sidebar administration pour les admins - **Compatibilité ESM** : Remplacement de `node-cron` par `setTimeout` natif pour résoudre l'erreur production +- **Permissions Docker** : Correction permissions `/app/backups` et installation `postgresql-client` pour `pg_dump` ### 2025-08-13 - Optimisation performance production + correction calendrier ✅ **Résolution latence production** : diff --git a/server/backupService.ts b/server/backupService.ts index d74f80b..b4f2170 100644 --- a/server/backupService.ts +++ b/server/backupService.ts @@ -15,15 +15,40 @@ export class BackupService { private maxBackups = 10; constructor() { - this.backupDir = path.join(process.cwd(), 'backups'); + // Use /app/backups in production (with proper permissions), or use env variable + const isProduction = process.env.NODE_ENV === 'production'; + this.backupDir = isProduction + ? process.env.BACKUP_DIR || '/app/backups' + : path.join(process.cwd(), 'backups'); + this.ensureBackupDirectory(); this.scheduleAutomaticBackup(); } private ensureBackupDirectory(): void { - if (!fs.existsSync(this.backupDir)) { - fs.mkdirSync(this.backupDir, { recursive: true }); - console.log('📁 Backup directory created:', this.backupDir); + try { + if (!fs.existsSync(this.backupDir)) { + fs.mkdirSync(this.backupDir, { recursive: true }); + console.log('📁 Backup directory created:', this.backupDir); + } + } catch (error) { + console.error('❌ Failed to create backup directory:', error); + // Fallback to /tmp if current directory fails + if (this.backupDir !== '/tmp/backups') { + this.backupDir = '/tmp/backups'; + console.log('🔄 Falling back to /tmp/backups'); + try { + if (!fs.existsSync(this.backupDir)) { + fs.mkdirSync(this.backupDir, { recursive: true }); + console.log('📁 Fallback backup directory created:', this.backupDir); + } + } catch (fallbackError) { + console.error('❌ Failed to create fallback directory:', fallbackError); + throw fallbackError; + } + } else { + throw error; + } } }