import cron from "node-cron"; import fs from "fs"; import path from "path"; import { storage } from "../storage"; import { backupDatabaseToPath } from "../services/databaseBackupService"; // Local backup folder in the app root (apps/Backend/backups) const LOCAL_BACKUP_DIR = path.resolve(process.cwd(), "backups"); // Name of the USB backup subfolder the user creates on their drive const USB_BACKUP_FOLDER_NAME = "USB Backup"; function ensureLocalBackupDir() { if (!fs.existsSync(LOCAL_BACKUP_DIR)) { fs.mkdirSync(LOCAL_BACKUP_DIR, { recursive: true }); } } async function getAdminUser() { const batchSize = 100; let offset = 0; while (true) { const users = await storage.getUsers(batchSize, offset); if (!users || users.length === 0) break; const admin = users.find((u) => u.username === "admin"); if (admin) return admin; offset += batchSize; } return null; } export const startBackupCron = () => { // ============================================================ // 8 PM — Local automatic backup to apps/Backend/backups/ // ============================================================ cron.schedule("0 20 * * *", async () => { console.log("🔄 [8 PM] Running local auto-backup..."); ensureLocalBackupDir(); const admin = await getAdminUser(); if (!admin) { console.warn("No admin user found, skipping local backup."); return; } if (!admin.autoBackupEnabled) { console.log("✅ [8 PM] Auto-backup is disabled for admin, skipped."); return; } try { const filename = `dental_backup_${Date.now()}.sql`; await backupDatabaseToPath({ destinationPath: LOCAL_BACKUP_DIR, filename }); await storage.createBackup(admin.id); await storage.deleteNotificationsByType(admin.id, "BACKUP"); console.log(`✅ Local backup done → ${filename}`); } catch (err) { console.error("Local backup failed:", err); await storage.createNotification( admin.id, "BACKUP", "❌ Automatic backup failed. Please check the server backup folder." ); } console.log("✅ [8 PM] Local backup complete."); }); // ============================================================ // 9 PM — USB backup to the "USB Backup" folder on the drive // ============================================================ cron.schedule("0 21 * * *", async () => { console.log("🔄 [9 PM] Running USB backup..."); const admin = await getAdminUser(); if (!admin) { console.warn("No admin user found, skipping USB backup."); return; } if (!admin.usbBackupEnabled) { console.log("✅ [9 PM] USB backup is disabled for admin, skipped."); return; } const destination = await storage.getActiveBackupDestination(admin.id); if (!destination) { await storage.createNotification( admin.id, "BACKUP", "❌ USB backup failed: no backup destination configured." ); return; } const usbBackupPath = path.join(destination.path, USB_BACKUP_FOLDER_NAME); if (!fs.existsSync(usbBackupPath)) { await storage.createNotification( admin.id, "BACKUP", `❌ USB backup failed: folder "${USB_BACKUP_FOLDER_NAME}" not found on the drive. Make sure the USB drive is connected and the folder exists.` ); return; } try { const filename = `dental_backup_usb_${Date.now()}.sql`; await backupDatabaseToPath({ destinationPath: usbBackupPath, filename }); await storage.createBackup(admin.id); await storage.deleteNotificationsByType(admin.id, "BACKUP"); console.log(`✅ USB backup done → ${usbBackupPath}/${filename}`); } catch (err) { console.error("USB backup failed:", err); await storage.createNotification( admin.id, "BACKUP", "❌ USB backup failed. Please check the USB drive and try again." ); } console.log("✅ [9 PM] USB backup complete."); }); };