{
  "nodes": [
    {
      "id": "",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -48,
        112
      ],
      "parameters": {
        "color": 5,
        "width": 1776,
        "height": 336,
        "content": "## 2. Restore Workflows from FTP"
      },
      "typeVersion": 1
    },
    {
      "id": "",
      "name": "SUCCESS email Credentials",
      "type": "n8n-nodes-base.emailSend",
      "disabled": true,
      "position": [
        1056,
        -160
      ],
      "parameters": {
        "text": "=Credential restore from FTP \"{{ $('Init').first().json.customConfig.FTPName }}\" has been successfully executed \ud83e\udd73\n\nexitCode: {{ $json.exitCode }}\nstderr: {{ $json.stderr || \"no error\"}}\n\nSteps:\n\n1. Find FTP Last Backup: {{ $('Find Last Backup').item.json.ftpCredentialsPath }}\n\n2. Restore credentials:\n{{ $json.stdout }}",
        "options": {
          "appendAttribution": false
        },
        "subject": "=n8n SUCCESS: {{ $workflow.name }}",
        "toEmail": "={{ $env.N8N_ADMIN_EMAIL }}",
        "fromEmail": "admin <admin@example.com>",
        "emailFormat": "text"
      },
      "credentials": {
        "smtp": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "",
      "name": "List Credentials Folders",
      "type": "n8n-nodes-base.ftp",
      "position": [
        -672,
        48
      ],
      "parameters": {
        "path": "={{ $('Init').item.json.customConfig.FTP_BACKUP_FOLDER }}",
        "operation": "list"
      },
      "credentials": {
        "ftp": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "",
      "name": "Start Restore",
      "type": "n8n-nodes-base.manualTrigger",
      "notes": "CRED 1 WF\u202f0",
      "position": [
        -1104,
        48
      ],
      "parameters": {},
      "notesInFlow": true,
      "typeVersion": 1
    },
    {
      "id": "",
      "name": "List Most Recent Workflows Folder",
      "type": "n8n-nodes-base.ftp",
      "position": [
        224,
        224
      ],
      "parameters": {
        "path": "={{ $('Find Last Backup').item.json.ftpWorkflowsPath }}",
        "operation": "list"
      },
      "credentials": {
        "ftp": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "",
      "name": "Write Workflow Files To Disk",
      "type": "n8n-nodes-base.readWriteFile",
      "position": [
        848,
        224
      ],
      "parameters": {
        "options": {},
        "fileName": "={{ $('Init').first().json.workflowConfig.PROJECT_ROOT_PATH }}/{{ $('Find Last Backup').item.json.latestBackupDate }}{{ $('Init').first().json.customConfig.workflows_temp_folder}}/{{ $json.name }}",
        "operation": "write"
      },
      "typeVersion": 1
    },
    {
      "id": "",
      "name": "Write Credential Files To Disk",
      "type": "n8n-nodes-base.readWriteFile",
      "position": [
        640,
        -160
      ],
      "parameters": {
        "options": {},
        "fileName": "={{ $('Init').first().json.workflowConfig.PROJECT_ROOT_PATH }}/{{ $('Find Last Backup').item.json.latestBackupDate }}{{ $('Init').first().json.customConfig.credentials_temp_folder}}/{{ $json.name }}",
        "operation": "write"
      },
      "typeVersion": 1
    },
    {
      "id": "",
      "name": "SUCCESS email Workflows",
      "type": "n8n-nodes-base.emailSend",
      "disabled": true,
      "position": [
        1472,
        224
      ],
      "parameters": {
        "text": "=Workflows\u2019 restore from FTP \"{{ $('Init').first().json.customConfig.FTPName }}\" has been successfully executed \ud83e\udd73\n\nexitCode: {{ $json.exitCode }}\nstderr: {{ $json.stderr || \"no error\"}}\n\nSteps:\n\n1. Find Last Backup: {{ $('Find Last Backup').item.json.ftpWorkflowsPath }}\n\n2. Exclude current workflow:\n{{ $('Exclude Current Workflow From Selection').item.json.stdout }}\n\n3. Restore workflows:\n{{ $('Restore Workflows').item.json.stdout }}",
        "options": {
          "appendAttribution": false
        },
        "subject": "=n8n SUCCESS: {{ $workflow.name }}",
        "toEmail": "={{ $env.N8N_ADMIN_EMAIL }}",
        "fromEmail": "admin <admin@example.com>",
        "emailFormat": "text"
      },
      "credentials": {
        "smtp": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "",
      "name": "ERROR:\u202fFind Most Recent Credentials Folder",
      "type": "n8n-nodes-base.stopAndError",
      "position": [
        -256,
        240
      ],
      "parameters": {
        "errorMessage": "={{ $json.error }}"
      },
      "typeVersion": 1
    },
    {
      "id": "",
      "name": "Download Workflow Files",
      "type": "n8n-nodes-base.ftp",
      "notes": "Ignore Credentials sub-workflow error",
      "onError": "continueRegularOutput",
      "position": [
        432,
        224
      ],
      "parameters": {
        "path": "={{ $json.path }}",
        "options": {}
      },
      "credentials": {
        "ftp": {
          "name": "<your credential>"
        }
      },
      "notesInFlow": true,
      "typeVersion": 1
    },
    {
      "id": "",
      "name": "Download Credential Files",
      "type": "n8n-nodes-base.ftp",
      "position": [
        432,
        -160
      ],
      "parameters": {
        "path": "={{ $json.path }}",
        "options": {}
      },
      "credentials": {
        "ftp": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "",
      "name": "Filter out Credentials sub-folder",
      "type": "n8n-nodes-base.filter",
      "position": [
        640,
        224
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "",
              "operator": {
                "type": "object",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $binary.data }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "",
      "name": "Exclude Current Workflow From Selection",
      "type": "n8n-nodes-base.executeCommand",
      "position": [
        1056,
        224
      ],
      "parameters": {
        "command": "=# Remove the current workflow file from restore folder to prevent self-restoration\n# Execute this AFTER writing files to disk but BEFORE import command\n\n# Get current workflow name and clean it\nWORKFLOW_NAME=\"{{ $workflow.name }}\"\nRESTORE_FOLDER=\"{{ $('Init').first().json.workflowConfig.PROJECT_ROOT_PATH }}/{{ $('Find Last Backup').item.json.latestBackupDate }}{{ $('Init').first().json.customConfig.workflows_temp_folder}}\"\n\n# Clean the workflow name (same logic as Clean Filename node)\nCLEANED_NAME=$(echo \"$WORKFLOW_NAME\" | sed 's/[<>:\"/\\\\|?*[:cntrl:]]/_/g' | sed 's/[[:space:].]\\+/_/g' | sed 's/_\\+/_/g' | sed 's/^_\\+//;s/_\\+$//')\n\necho \"\ud83d\udd0d Current workflow: $WORKFLOW_NAME\"\necho \"\ud83e\uddf9 Cleaned name: $CLEANED_NAME\"\necho \"\ud83d\udcc2 Restore folder: $RESTORE_FOLDER\"\n\n# Find and remove file matching the current workflow name\nif [ -f \"$RESTORE_FOLDER/${CLEANED_NAME}.json\" ]; then\n  rm \"$RESTORE_FOLDER/${CLEANED_NAME}.json\"\n  echo \"\u2705 Removed current workflow file: ${CLEANED_NAME}.json\"\n  echo \"\u26a0\ufe0f This workflow will NOT be restored to prevent overwrite\"\nelse\n  echo \"\u2139\ufe0f Current workflow file not found in restore folder (already safe)\"\nfi\n\n# Count remaining files\nFILE_COUNT=$(ls -1 \"$RESTORE_FOLDER\"/*.json 2>/dev/null | wc -l)\necho \"\ud83d\udcca Remaining workflows to restore: $FILE_COUNT\""
      },
      "typeVersion": 1
    },
    {
      "id": "",
      "name": "Restore Workflows",
      "type": "n8n-nodes-base.executeCommand",
      "position": [
        1264,
        224
      ],
      "parameters": {
        "command": "=n8n import:workflow --separate --input={{ $('Init').first().json.workflowConfig.PROJECT_ROOT_PATH }}/{{ $('Find Last Backup').item.json.latestBackupDate }}{{ $('Init').first().json.customConfig.workflows_temp_folder }}"
      },
      "typeVersion": 1
    },
    {
      "id": "",
      "name": "Restore Credentials",
      "type": "n8n-nodes-base.executeCommand",
      "position": [
        848,
        -160
      ],
      "parameters": {
        "command": "=n8n import:credentials --separate --input={{ $('Init').first().json.workflowConfig.PROJECT_ROOT_PATH }}/{{ $('Find Last Backup').item.json.latestBackupDate }}{{ $('Init').first().json.customConfig.credentials_temp_folder}}"
      },
      "typeVersion": 1
    },
    {
      "id": "",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1168,
        -768
      ],
      "parameters": {
        "color": 4,
        "width": 1088,
        "height": 1216,
        "content": "## Start here\n### \u26a0 Warnings \u26a0\n\u2022 In case of full restore, restore Credentials first!\n\u2022 Any already existing credential or workflow will be overwritten\u2026\n\n### Instructions\n\u2022 Re-create your FTP credential (and optionnaly your SMTP one).\n\u2022 Manually copy this workflow to your new n8n instance.\n\u2022 Launch it and restore everything!\n\nCan be used to move your workflows to another instance \ud83d\udc4d\ud83c\udffb\n\n### Configure the \"Start Restore\" JSON according to your need\n```\n[\n  {\n    \"credentials\": true,\n    \"worflows\": false\n  }\n]\n```\n(and modify the \"notes\" too!).\n\n### Configure the \"Init\" node\n```\nconst FTP_BACKUP_FOLDER = $env.FTP_BACKUP_FOLDER || '/n8n-backups';\nconst credentials_temp_folder = '-restore-credentials';\nconst workflows_temp_folder = '-restore-workflows';\nconst FTPName = 'Your FTP Server Name';\nconst credentials = \"n8n-credentials\";\n```"
      },
      "typeVersion": 1
    },
    {
      "id": "",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -48,
        -272
      ],
      "parameters": {
        "color": 3,
        "width": 1776,
        "height": 352,
        "content": "## 1. Restore Credentials from FTP"
      },
      "typeVersion": 1
    },
    {
      "id": "",
      "name": "Restore Credentials?",
      "type": "n8n-nodes-base.if",
      "position": [
        16,
        -160
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $('Start Restore').first().json.credentials }}",
              "rightValue": "true"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "",
      "name": "Restore Workflows?",
      "type": "n8n-nodes-base.if",
      "position": [
        16,
        224
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $('Start Restore').first().json.worflows }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "",
      "name": "Init",
      "type": "n8n-nodes-base.code",
      "position": [
        -880,
        48
      ],
      "parameters": {
        "jsCode": "// YOUR_AWS_SECRET_KEY_HERE==\n// \ud83d\udcc5 LOCAL DATE/TIME INITIALIZATION\n// YOUR_AWS_SECRET_KEY_HERE==\n\nconst now = new Date();\n\n// YOUR_AWS_SECRET_KEY_HERE==\n// \ud83c\udf0d USER-DEFINED TIMEZONE CONFIGURATION\n// YOUR_AWS_SECRET_KEY_HERE==\n// \u26a0\ufe0f  IMPORTANT: This code runs on the n8n SERVER, not in your browser!\n// \u26a0\ufe0f  Configure the timezone where you want executions to be scheduled,\n//      regardless of where your n8n server is physically located.\n//\n// \ud83d\udccd Common timezone examples:\n// - 'Europe/Paris'       \u2192 Central European Time (CET/CEST)\n// - 'America/New_York'   \u2192 Eastern Time (EST/EDT)\n// - 'America/Chicago'    \u2192 Central Time (CST/CDT)\n// - 'America/Los_Angeles'\u2192 Pacific Time (PST/PDT)\n// - 'Asia/Tokyo'         \u2192 Japan Standard Time (JST)\n// - 'Asia/Shanghai'      \u2192 China Standard Time (CST)\n// - 'Australia/Sydney'   \u2192 Australian Eastern Time (AET)\n// - 'UTC'                \u2192 Coordinated Universal Time\n//\n// \ud83d\udd27 TO CONFIGURE FOR YOUR USE CASE:\n// 1. Uncomment and edit the lines below with your desired timezone\n// 2. Comment out the automatic detection line\n//\n// To use user-defined timezone instead, UNCOMMENT these lines:\n// const USER_TIMEZONE = 'Europe/Paris';  // \ud83d\udc48 EDIT THIS for your location\n// const LOCAL_TIMEZONE = USER_TIMEZONE;  // \ud83d\udc48 EDIT THIS for your location\n//\n// \ud83d\udd58 Automatic detection (uses server timezone or environment variable):\nconst LOCAL_TIMEZONE = $env.GENERIC_TIMEZONE || 'Europe/Paris';  // \ud83d\udfe2 Default fallback\n// To use user-defined timezone instead, comment out the above line\n\n// Local datetime in YYYY-MM-DD_HH-MM-SS format\nconst localDateTime = now.toLocaleString('sv-SE', { \n  timeZone: LOCAL_TIMEZONE,\n  year: 'numeric',\n  month: '2-digit',\n  day: '2-digit',\n  hour: '2-digit',\n  minute: '2-digit',\n  second: '2-digit'\n}).replace(' ', '_').replace(/:/g, '-');\n\n// Local formatted time for display\nconst localDateTimeFormatted = now.toLocaleString('sv-SE', { \n  timeZone: LOCAL_TIMEZONE,\n  year: 'numeric',\n  month: '2-digit',\n  day: '2-digit',\n  hour: '2-digit',\n  minute: '2-digit',\n  second: '2-digit'\n});\n\n// Local time HH:MM:SS format\nconst localTimeFormatted = now.toLocaleString('sv-SE', { \n  timeZone: LOCAL_TIMEZONE,\n  hour: '2-digit',\n  minute: '2-digit',\n  second: '2-digit'\n});\n\n// Local date in YYYY-MM-DD format\nconst localDate = now.toLocaleDateString('sv-SE', { timeZone: LOCAL_TIMEZONE });\n\n// Local time in French format\nconst localTimeFR = now.toLocaleString('sv-SE', { \n  timeZone: LOCAL_TIMEZONE,\n  hour: '2-digit',\n  minute: '2-digit'\n}).replace(/:/g, 'h').replace(/^0(\\d)h/, '$1h');\n\nconsole.log('\ud83d\ude80 USER-DEFINE TIMEZONE VARIABLES INITIALISED (Local timezone):');\nconsole.log(`   \ud83c\udf0d Timezone: ${LOCAL_TIMEZONE}`);\nconsole.log(`   \u2728 Now (UTC): ${now}`);\nconsole.log(`   \ud83d\udcc5 Local date/time: ${localDateTime}`);\nconsole.log(`   \ud83d\udd50 Local time: ${localDateTimeFormatted}`);\nconsole.log(`   \ud83d\udd50 Local time: ${localTimeFormatted}`);\nconsole.log(`   \ud83d\udcc5 Local date: ${localDate}`);\nconsole.log(`   \ud83d\udcc5 Local time (FR): ${localTimeFR}`);\n\n// Create structure for time data output\nconst timeData = {\n  localTimeZone:LOCAL_TIMEZONE,\n  nowDateUTC: now,\n  nowUTCstring: now.toISOString(),        // UTC for calculations\n  localDateTime: localDateTime,     // YYY-MM-DD_HH-MM-SS format\n  localDateTimeFormatted: localDateTimeFormatted, // Human readable\n  localTimeFormatted: localTimeFormatted, // Human readable\n  localDate: localDate,             // YYYY-MM-DD format\n  localTime: localTimeFR            // HHhMM format (FR)\n}\n\n// YOUR_AWS_SECRET_KEY_HERE==\n// \ud83d\udcdd WORKFLOW STANDARD CONFIGURATION\n// YOUR_AWS_SECRET_KEY_HERE==\n\nconst N8N_ADMIN_EMAIL = $env.N8N_ADMIN_EMAIL || 'user@example.com';\nconst WORKFLOW_NAME = $workflow.name;\nconst N8N_PROJECTS_DIR = $env.N8N_PROJECTS_DIR || '/files/n8n-projects-data'; // \u26a0\ufe0f Your projects\u2019 ROOT folder here\n// projects-root-folder/\n//   \u2514\u2500\u2500 Your-project-folder-name/\n//       \u251c\u2500\u2500 logs/\n//       \u251c\u2500\u2500 reports/\n//       \u251c\u2500\u2500 ...\n//       \u2514\u2500\u2500 [other project files]\nconst PROJECT_FOLDER_NAME = \"Workflow-backups\"; // \u26a0\ufe0f Your project folder\nconst PROJECT_ROOT_PATH = `${N8N_PROJECTS_DIR}/${PROJECT_FOLDER_NAME}`;\n// const N8N_MEDIA_ROOT_PATH = $env.N8N_MEDIA_SHARED || '/files/n8n-media-shared'; // \u26a0\ufe0f Your public folder, accessible from inet\n// const mediaOutputFolder = \"/output\";\n// const mediaTempFolder = \"/temp\";\n// const N8N_FILE_SERVER_PURL = $env.N8N_FILE_SERVER_PURL || 'https://files.srv815447.hstgr.cloud'; // File serve public url\n\nconst LOGS_PATH = `${PROJECT_ROOT_PATH}/logs`;\n// const logFileName = `${localDateTime2}-${WORKFLOW_NAME.replace(/[^a-zA-Z0-9]/g, '_')}_logs.json`;  // \u26a0\ufe0f Your log file name\nconst logFileName = `${localDateTime}-backup_logs.json`;  // \u26a0\ufe0f Your log file name\nconst logPathFileName = `${LOGS_PATH}/${logFileName}`;\n\n// Configuration for report generation\nconst REPORTS_PATH = `${PROJECT_ROOT_PATH}/reports`;\nconst reportFileName = `${localDateTime}-report.txt`;\nconst reportPathFileName = `${REPORTS_PATH}/${reportFileName}`;\n\n// Console output\nconsole.log('\ud83e\uddfe STANDARD WORKFLOW VARIABLES INITIALISED:');\nconsole.log(`   \ud83d\udcc1 Admin email: ${N8N_ADMIN_EMAIL}`);\nconsole.log(`   \ud83d\udcc1 Workflow name: ${WORKFLOW_NAME}`);\nconsole.log(`   \ud83d\udcc1 Projects folder: ${N8N_PROJECTS_DIR}`);\nconsole.log(`   \ud83d\udcc1 Project folder name: ${PROJECT_FOLDER_NAME}`);\nconsole.log(`   \ud83d\udcc1 Project root path: ${PROJECT_ROOT_PATH}`);\n// console.log(`   \ud83d\udcc1 Media root path: ${N8N_MEDIA_ROOT_PATH}`);\n// console.log(`   \ud83d\udcc1 File server public URL: ${N8N_FILE_SERVER_PURL}`);\nconsole.log(`   \ud83d\udcc1 Log path: ${LOGS_PATH}`);\nconsole.log(`   \ud83d\udcc1 Log file name: ${logFileName}`);\nconsole.log(`   \ud83d\udcc1 Log file path: ${logPathFileName}`);\nconsole.log(`   \ud83d\udcc1 Reports path: ${REPORTS_PATH}`);\nconsole.log(`   \ud83d\udcc1 Report file name: ${reportFileName}`);\nconsole.log(`   \ud83d\udcc1 Report file path: ${reportPathFileName}`);\n\n// Create structure for workflow configuration output\nconst workflowConfig = {\n  workflowStep: 'init',\n  N8N_ADMIN_EMAIL,\n  WORKFLOW_NAME,\n  N8N_PROJECTS_DIR,\n  PROJECT_FOLDER_NAME,\n  PROJECT_ROOT_PATH,\n  // N8N_MEDIA_ROOT_PATH,\n  // mediaOutputFolder,\n  // mediaTempFolder,\n  // N8N_FILE_SERVER_PURL,\n  LOGS_PATH,\n  logFileName,\n  logPathFileName,\n  REPORTS_PATH,\n  reportFileName,\n  reportPathFileName\n}\n\n// YOUR_AWS_SECRET_KEY_HERE==\n// \ud83d\udcdd WORKFLOW CUSTOM CONFIGURATION\n// YOUR_AWS_SECRET_KEY_HERE==\n// \u26a0\ufe0f  INSERT HERE: your workflow custom configuration variables\n\n// Base backup path using your FTP volume configuration (folder must exist)\nconst BACKUP_FOLDER = $env.N8N_BACKUP_FOLDER || '/files/n8n-backups'; // \u26a0\ufe0f Change the default value for your n8n backup folder\nconst credentials_temp_folder = '-restore-credentials';\nconst workflows_temp_folder = '-restore-workflows';\nconst FTP_BACKUP_FOLDER = $env.FTP_BACKUP_FOLDER || '/n8n-backups';\nconst FTPName = 'Your FTP Server Name';\n\nconst credentials = \"n8n-credentials\";\n\n// Console output\nconsole.log('\ud83e\uddfe CUSTOM WORKFLOW VARIABLES INITIALISED:');\nconsole.log(`   \ud83d\udcbe Backup folder: ${BACKUP_FOLDER}`);\nconsole.log('      File prefix:', localDate);\nconsole.log('      Timestamp (UTC):', now);\n\nconst customConfig = {\n  backupFolder: BACKUP_FOLDER,\n  credentials_temp_folder,\n  workflows_temp_folder,\n  FTP_BACKUP_FOLDER,\n  FTPName,\n  credentials\n}\n\n// YOUR_AWS_SECRET_KEY_HERE==\n// \ud83d\udcca OUTPUT DATA\n// YOUR_AWS_SECRET_KEY_HERE==\n\nconst initData = {\n  timeData,\n  workflowConfig,\n  customConfig\n};\n\nreturn [{ json: initData }];"
      },
      "typeVersion": 2
    },
    {
      "id": "",
      "name": "Create Temp Folder",
      "type": "n8n-nodes-base.executeCommand",
      "notes": "For credential files on server",
      "position": [
        -256,
        48
      ],
      "parameters": {
        "command": "=#!/bin/bash\n\n# Create temporary restore folders based on trigger parameters\n# This script creates folders only for selected restore options\n\n# Get configuration from Init node\nPROJECT_ROOT_PATH=\"{{ $('Init').first().json.workflowConfig.PROJECT_ROOT_PATH }}\"\nLOCAL_DATE=\"{{ $json.latestBackupDate }}\"\nCREDENTIALS_TEMP_FOLDER=\"{{ $('Init').first().json.customConfig.credentials_temp_folder }}\"\nWORKFLOWS_TEMP_FOLDER=\"{{ $('Init').first().json.customConfig.workflows_temp_folder }}\"\n\n# Get trigger parameters\nRESTORE_CREDENTIALS=\"{{ $('Start Restore').first().json.credentials }}\"\nRESTORE_WORKFLOWS=\"{{ $('Start Restore').first().json.worflows }}\"\n\necho \"\ud83d\udccb Restore parameters:\"\necho \"   \ud83d\udd11 Credentials: $RESTORE_CREDENTIALS\"\necho \"   \ud83d\udd04 Workflows: $RESTORE_WORKFLOWS\"\necho \"\"\n\nFOLDERS_CREATED=0\n\n# Create credentials temp folder if needed\nif [ \"$RESTORE_CREDENTIALS\" = \"true\" ]; then\n  CRED_PATH=\"${PROJECT_ROOT_PATH}/${LOCAL_DATE}${CREDENTIALS_TEMP_FOLDER}\"\n  mkdir -p \"$CRED_PATH\"\n  echo \"\u2705 Created credentials temp folder: $CRED_PATH\"\n  FOLDERS_CREATED=$((FOLDERS_CREATED + 1))\nfi\n\n# Create workflows temp folder if needed\nif [ \"$RESTORE_WORKFLOWS\" = \"true\" ]; then\n  WORK_PATH=\"${PROJECT_ROOT_PATH}/${LOCAL_DATE}${WORKFLOWS_TEMP_FOLDER}\"\n  mkdir -p \"$WORK_PATH\"\n  echo \"\u2705 Created workflows temp folder: $WORK_PATH\"\n  FOLDERS_CREATED=$((FOLDERS_CREATED + 1))\nfi\n\necho \"\"\necho \"\ud83d\udcca SUMMARY: $FOLDERS_CREATED folder(s) created\"\n\nif [ \"$FOLDERS_CREATED\" -eq 0 ]; then\n  echo \"\u26a0\ufe0f  No folders created (no restore option selected)\"\n  exit 1\nfi"
      },
      "notesInFlow": true,
      "typeVersion": 1
    },
    {
      "id": "",
      "name": "List Credentials Files",
      "type": "n8n-nodes-base.ftp",
      "position": [
        224,
        -160
      ],
      "parameters": {
        "path": "={{ $('Find Last Backup').item.json.ftpCredentialsPath }}",
        "operation": "list"
      },
      "credentials": {
        "ftp": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "",
      "name": "Find Last Backup",
      "type": "n8n-nodes-base.code",
      "onError": "continueErrorOutput",
      "position": [
        -464,
        48
      ],
      "parameters": {
        "jsCode": "// YOUR_AWS_SECRET_KEY_HERE==\n// \ud83d\udd0d FIND LATEST BACKUP FOLDER FROM FTP\n// YOUR_AWS_SECRET_KEY_HERE==\n// \u26a0\ufe0f CONFIGURE THIS NODE WITH:\n// SETTINGS > ON ERROR > CONTINUE (USING ERROR OUTPUT)\n\n// Extract init data from Init node\nconst initData = $('Init').first().json;\nconst { customConfig } = initData;\n\nconst FTP_BACKUP_FOLDER = customConfig.FTP_BACKUP_FOLDER;\nconst credentials = customConfig.credentials;\n\nconsole.log(`\ud83d\udd0d Searching for latest backup in FTP: ${FTP_BACKUP_FOLDER}`);\nconsole.log(`\ud83d\udcc1 Target credentials folder: ${credentials}`);\n\ntry {\n  // Get FTP listing from previous node (List FTP)\n  const ftpListing = $input.all();\n  \n  if (!ftpListing || ftpListing.length === 0) {\n    throw new Error('No FTP listing found. Please check FTP connection.');\n  }\n  \n  console.log(`\ud83d\udcc2 FTP returned ${ftpListing.length} item(s)`);\n  \n  // Filter for directories only (type 'd') with date format YYYY-MM-DD\n  const datePattern = /^\\d{4}-\\d{2}-\\d{2}$/;\n  const dateDirectories = ftpListing\n    .filter(item => {\n      const itemData = item.json;\n      // FTP node returns items with 'name' and 'type' properties\n      // type 'd' = directory, type '-' = file\n      const isDirectory = itemData.type === 'd' || itemData.type === 1; // type can be string or number\n      const matchesDateFormat = datePattern.test(itemData.name);\n      \n      if (isDirectory && matchesDateFormat) {\n        console.log(`\u2713 Found date directory: ${itemData.name}`);\n      }\n      \n      return isDirectory && matchesDateFormat;\n    })\n    .map(item => item.json.name);\n  \n  console.log(`\ud83d\udcc5 Found ${dateDirectories.length} date-formatted directories`);\n  \n  if (dateDirectories.length === 0) {\n    throw new Error('No date-formatted directories (YYYY-MM-DD) found in FTP backup folder');\n  }\n  \n  // Sort directories by date (newest first)\n  const sortedDirectories = dateDirectories.sort((a, b) => {\n    const dateA = new Date(a);\n    const dateB = new Date(b);\n    return dateB - dateA; // Descending order (newest first)\n  });\n  \n  console.log(`\ud83d\udcc5 Sorted directories (newest first): ${sortedDirectories.join(', ')}`);\n  \n  // Get the most recent directory\n  const latestBackupDate = sortedDirectories[0];\n  const ftpCredentialsPath = `${FTP_BACKUP_FOLDER}/${latestBackupDate}/${credentials}`;\n  const ftpWorkflowsPath = `${FTP_BACKUP_FOLDER}/${latestBackupDate}/`;\n  \n  console.log(`\u2705 Latest backup date: ${latestBackupDate}`);\n  console.log(`\u2705 FTP credentials path: ${ftpCredentialsPath}`);\n  \n  // Return result for next node\n  const result = {\n    latestBackupDate,\n    ftpCredentialsPath,\n    ftpWorkflowsPath,\n    FTP_BACKUP_FOLDER,\n    credentialsFolder: credentials\n  };\n  \n  return [{ json: result }];\n  \n} catch (error) {\n  console.error(`\u274c Error finding latest backup: ${error.message}`);\n  throw new Error(`Failed to find latest backup: ${error.message}`);\n}"
      },
      "typeVersion": 2
    }
  ],
  "connections": {
    "Init": {
      "main": [
        [
          {
            "node": "List Credentials Folders",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Start Restore": {
      "main": [
        [
          {
            "node": "Init",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Find Last Backup": {
      "main": [
        [
          {
            "node": "Create Temp Folder",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "ERROR:\u202fFind Most Recent Credentials Folder",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Restore Workflows": {
      "main": [
        [
          {
            "node": "SUCCESS email Workflows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Temp Folder": {
      "main": [
        [
          {
            "node": "Restore Credentials?",
            "type": "main",
            "index": 0
          },
          {
            "node": "Restore Workflows?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Restore Workflows?": {
      "main": [
        [
          {
            "node": "List Most Recent Workflows Folder",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Restore Credentials": {
      "main": [
        [
          {
            "node": "SUCCESS email Credentials",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Restore Credentials?": {
      "main": [
        [
          {
            "node": "List Credentials Files",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "List Credentials Files": {
      "main": [
        [
          {
            "node": "Download Credential Files",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download Workflow Files": {
      "main": [
        [
          {
            "node": "Filter out Credentials sub-folder",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "List Credentials Folders": {
      "main": [
        [
          {
            "node": "Find Last Backup",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download Credential Files": {
      "main": [
        [
          {
            "node": "Write Credential Files To Disk",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Write Workflow Files To Disk": {
      "main": [
        [
          {
            "node": "Exclude Current Workflow From Selection",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Write Credential Files To Disk": {
      "main": [
        [
          {
            "node": "Restore Credentials",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter out Credentials sub-folder": {
      "main": [
        [
          {
            "node": "Write Workflow Files To Disk",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "List Most Recent Workflows Folder": {
      "main": [
        [
          {
            "node": "Download Workflow Files",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Exclude Current Workflow From Selection": {
      "main": [
        [
          {
            "node": "Restore Workflows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}