Improve production stability by fixing backup directory permissions

Adjust Dockerfile to create and grant permissions for backup directories, install PostgreSQL client for backups, and update BackupService to use the correct production backup path to resolve EACCES errors.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 7c468936-2a88-4686-ac0a-84921a45222d
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/1957c339-2757-4d1f-8e92-e9f71a1ce58e/7c468936-2a88-4686-ac0a-84921a45222d/K3Lzcje
This commit is contained in:
michaelschal committed 2025-08-13 21:03:48 +00:00
1 parent 1c126fb77a
commit b079d35e3a
4 files changed
+262 -8

No files matched your search

+4 -4
View File
@@ -84,8 +84,8 @@ COPY --from=build --chown=nextjs:nodejs /app/shared ./shared
# Create symlink for public files to be accessible from dist # Create symlink for public files to be accessible from dist
RUN ln -sf /app/dist/public /app/dist/public RUN ln -sf /app/dist/public /app/dist/public
# Create uploads directory with proper permissions # Create uploads and backups directories with proper permissions
RUN mkdir -p /app/uploads && chown -R nextjs:nodejs /app/uploads RUN mkdir -p /app/uploads /app/backups && chown -R nextjs:nodejs /app/uploads /app/backups
# Switch to non-root user # Switch to non-root user
USER nextjs USER nextjs
@@ -94,9 +94,9 @@ USER nextjs
EXPOSE 3000 EXPOSE 3000
ENV PORT=3000 ENV PORT=3000
# Install wget for health check # Install wget for health check and postgresql-client for pg_dump
USER root USER root
RUN apk add --no-cache wget RUN apk add --no-cache wget postgresql-client
USER nextjs USER nextjs
# Health check # Health check
@@ -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
+1
View File
@@ -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 - **Base de données** : Table `DATABASE_BACKUPS` avec suivi complet des sauvegardes
- **Navigation** : Ajouté dans la sidebar administration pour les admins - **Navigation** : Ajouté dans la sidebar administration pour les admins
- **Compatibilité ESM** : Remplacement de `node-cron` par `setTimeout` natif pour résoudre l'erreur production - **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 ### 2025-08-13 - Optimisation performance production + correction calendrier
✅ **Résolution latence production** : ✅ **Résolution latence production** :
+29 -4
View File
@@ -15,15 +15,40 @@ export class BackupService {
private maxBackups = 10; private maxBackups = 10;
constructor() { 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.ensureBackupDirectory();
this.scheduleAutomaticBackup(); this.scheduleAutomaticBackup();
} }
private ensureBackupDirectory(): void { private ensureBackupDirectory(): void {
if (!fs.existsSync(this.backupDir)) { try {
fs.mkdirSync(this.backupDir, { recursive: true }); if (!fs.existsSync(this.backupDir)) {
console.log('📁 Backup directory created:', 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;
}
} }
} }