n8n 워크플로우를 OneDrive에 백업
고급
이것은DevOps분야의자동화 워크플로우로, 29개의 노드를 포함합니다.주로 N8n, Code, Merge, Switch, ConvertToFile 등의 노드를 사용하며. 정리 및 이메일 알림 기능을 포함한 OneDrive에 n8n 워크플로 자동 백업
사전 요구사항
- •특별한 사전 요구사항 없이 가져와 바로 사용 가능합니다
사용된 노드 (29)
카테고리
워크플로우 미리보기
노드 연결 관계를 시각적으로 표시하며, 확대/축소 및 이동을 지원합니다
워크플로우 내보내기
다음 JSON 구성을 복사하여 n8n에 가져오면 이 워크플로우를 사용할 수 있습니다
{
"id": "k0dRcFrfMvlaqhT0",
"meta": {
"instanceId": "89249a8a187ba6e01e16112a0d334a3aa01d510ad8f88d223e12cc0a2a8beb6b"
},
"name": "Backup n8n workflows to Onedrive",
"tags": [],
"nodes": [
{
"id": "96aee703-bbf4-4de0-b6fb-7cf8428d5027",
"name": "Retrieve workflows",
"type": "n8n-nodes-base.n8n",
"position": [
-4592,
96
],
"parameters": {
"filters": {},
"requestOptions": {}
},
"typeVersion": 1
},
{
"id": "84b64870-e3c4-4762-9931-c5ec929c904e",
"name": "Get backupfolders",
"type": "n8n-nodes-base.microsoftOneDrive",
"position": [
-3248,
96
],
"parameters": {
"resource": "folder"
},
"typeVersion": 1
},
{
"id": "cf46cd5f-f000-40ec-a6c8-110984437c6c",
"name": "Delete old backup folder",
"type": "n8n-nodes-base.microsoftOneDrive",
"position": [
-1344,
224
],
"parameters": {
"folderId": "={{ $json.id }}\n\n",
"resource": "folder",
"operation": "delete"
},
"typeVersion": 1,
"alwaysOutputData": false
},
{
"id": "c79f2638-dd31-4c07-ad61-b25efc2919bd",
"name": "Prepare HTML Email",
"type": "n8n-nodes-base.code",
"position": [
-480,
112
],
"parameters": {
"jsCode": "// Prepare backup success email data - SAFE for any flow path\nconst backupDate = DateTime.now();\n\n// SAFE: Get folder name - always available\nlet folderName = 'Unknown';\ntry {\n folderName = $('Create new backup folder').item.json.name;\n} catch (e) {\n console.log('Could not get folder name:', e.message);\n folderName = `n8n.backup Daily ${backupDate.toFormat('yyyy-MM-dd')}`;\n}\n\n// SAFE: Get original workflow data - always available\nlet originalWorkflowData = [];\nlet totalWorkflows = 0;\ntry {\n originalWorkflowData = $('Retrieve workflows').all();\n totalWorkflows = originalWorkflowData.length;\n} catch (e) {\n console.log('Could not get workflow data:', e.message);\n}\n\n// SAFE: Get uploaded files data - always available from input\nlet uploadedFiles = [];\ntry {\n uploadedFiles = $('Upload JSON to folder').all();\n} catch (e) {\n console.log('Could not get uploaded files:', e.message);\n // Fallback: try to get from current input if this is from Upload path\n try {\n uploadedFiles = $input.all();\n } catch (e2) {\n console.log('Could not get input data either:', e2.message);\n }\n}\n\n// Calculate statistics\nconst activeWorkflows = originalWorkflowData.filter(item => {\n return item.json && item.json.active === true;\n}).length;\nconst inactiveWorkflows = totalWorkflows - activeWorkflows;\n\n// Calculate total size from uploaded files\nconst totalSizeKB = uploadedFiles.reduce((sum, item) => {\n return sum + ((item.json && item.json.size) ? item.json.size : 0);\n}, 0) / 1024;\n\n// Enhanced workflow analysis\nconst workflowsByStatus = {\n active: [],\n inactive: [],\n recentlyModified: [],\n large: []\n};\n\n// Prepare workflow list\nconst workflowList = originalWorkflowData.map(item => {\n let lastUpdated = 'Unknown';\n let lastUpdatedDate = null;\n let status = 'Inactive';\n \n // Handle date from original workflow data\n try {\n if (item.json.updatedAt) {\n const date = DateTime.fromISO(item.json.updatedAt);\n if (date.isValid) {\n lastUpdated = date.toFormat('dd/MM/yyyy HH:mm');\n lastUpdatedDate = date;\n }\n } else if (item.json.lastModifiedDateTime) {\n const date = DateTime.fromISO(item.json.lastModifiedDateTime);\n if (date.isValid) {\n lastUpdated = date.toFormat('dd/MM/yyyy HH:mm');\n lastUpdatedDate = date;\n }\n } else if (item.json.createdAt) {\n const date = DateTime.fromISO(item.json.createdAt);\n if (date.isValid) {\n lastUpdated = date.toFormat('dd/MM/yyyy HH:mm');\n lastUpdatedDate = date;\n }\n }\n } catch (error) {\n console.log('Date parsing error for workflow:', item.json.name, error);\n lastUpdated = 'Date unavailable';\n }\n \n // Use active status from original data\n if (item.json && item.json.active === true) {\n status = 'Active';\n }\n \n // Find corresponding uploaded file to get size\n const uploadedFile = uploadedFiles.find(uf => uf.json && uf.json.name === item.json.name);\n const fileSize = uploadedFile ? Math.round((uploadedFile.json.size || 0) / 1024 * 100) / 100 : 0;\n \n const workflow = {\n name: (item.json && item.json.name) ? item.json.name : 'Unnamed workflow',\n active: status === 'Active',\n updatedAt: lastUpdated,\n lastUpdatedDate: lastUpdatedDate,\n size: fileSize,\n id: (item.json && item.json.id) ? item.json.id : 'unknown'\n };\n \n // Categorize workflows for insights\n if (workflow.active) {\n workflowsByStatus.active.push(workflow);\n } else {\n workflowsByStatus.inactive.push(workflow);\n }\n \n // Check if recently modified (last 7 days)\n if (lastUpdatedDate && lastUpdatedDate > DateTime.now().minus({ days: 7 })) {\n workflowsByStatus.recentlyModified.push(workflow);\n }\n \n // Check if large workflow (>50KB)\n if (fileSize > 50) {\n workflowsByStatus.large.push(workflow);\n }\n \n return workflow;\n}).sort((a, b) => {\n // Sort by date - newest first (nulls/unknowns go to end)\n if (!a.lastUpdatedDate && !b.lastUpdatedDate) return 0;\n if (!a.lastUpdatedDate) return 1;\n if (!b.lastUpdatedDate) return -1;\n return b.lastUpdatedDate - a.lastUpdatedDate;\n});\n\n// Calculate additional insights\nconst recentlyModifiedCount = workflowsByStatus.recentlyModified.length;\nconst largeWorkflowsCount = workflowsByStatus.large.length;\nconst averageWorkflowSize = totalWorkflows > 0 ? Math.round((totalSizeKB / totalWorkflows) * 100) / 100 : 0;\n\n// FIXED: SAFE cleanup status detection - handles all possible flow paths\nlet cleanupStatus = 'Not Attempted';\nlet cleanupNote = 'Cleanup status could not be determined';\nlet cleanupIcon = '❓';\nlet cleanupColor = '#6b7280';\n\n// Try to determine cleanup status by checking which nodes were executed\ntry {\n // Method 1: Check if we came from Switch node path 1 (no cleanup needed)\n // This is determined by checking if we have Code node summary data\n const currentInput = $input.all();\n let codeNodeSummary = null;\n \n // Look for Code node summary in current input or previous nodes\n if (currentInput.length > 0 && currentInput[0].json && typeof currentInput[0].json.hasOldFolders !== 'undefined') {\n codeNodeSummary = currentInput[0].json;\n }\n \n if (codeNodeSummary) {\n if (!codeNodeSummary.hasOldFolders) {\n // Switch went to path 1 (no cleanup needed)\n cleanupStatus = 'Not Needed';\n cleanupNote = `No old backup folders found (checked ${codeNodeSummary.totalFoldersChecked || 0} folders)`;\n cleanupIcon = '✅';\n cleanupColor = '#22c55e';\n } else {\n // Switch went to path 0 (cleanup was needed), but we're now in success email\n // This means Delete was successful\n // FIXED: Count actual deleted folders from current input (from Loop Over Items)\n const deletedFoldersCount = currentInput.filter(item => item.json && item.json.id && item.json.name).length;\n cleanupStatus = 'Completed';\n cleanupNote = `Successfully cleaned up ${deletedFoldersCount} old backup folder${deletedFoldersCount > 1 ? 's' : ''}`;\n cleanupIcon = '✅';\n cleanupColor = '#22c55e';\n }\n } else {\n // Fallback: try to safely check other nodes\n try {\n // Try Code node directly (might be available)\n const codeResults = $('Filter backup folder').all();\n if (codeResults.length > 0 && codeResults[0].json) {\n const summary = codeResults[0].json;\n if (!summary.hasOldFolders) {\n cleanupStatus = 'Not Needed';\n cleanupNote = 'No old folders found';\n cleanupIcon = '✅';\n cleanupColor = '#22c55e';\n } else {\n // FIXED: Use the correct oldFoldersCount from Code node summary\n cleanupStatus = 'Completed'; \n cleanupNote = `Cleaned up ${summary.oldFoldersCount || 1} old folder${(summary.oldFoldersCount || 1) > 1 ? 's' : ''}`;\n cleanupIcon = '✅';\n cleanupColor = '#22c55e';\n }\n }\n } catch (e) {\n // Code node not accessible, use generic status\n cleanupStatus = 'Unknown';\n cleanupNote = 'Cleanup status could not be determined from current execution path';\n cleanupIcon = '❓';\n cleanupColor = '#6b7280';\n }\n }\n \n} catch (e) {\n console.log('Error determining cleanup status:', e);\n cleanupStatus = 'Unknown';\n cleanupNote = 'Error determining cleanup status: ' + e.message;\n cleanupIcon = '❓';\n cleanupColor = '#6b7280';\n}\n\n// Create beautiful enhanced HTML email\nconst htmlBody = `\n<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>n8n Backup Success</title>\n <style>\n body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; margin: 0; padding: 20px; background-color: #f5f7fa; }\n .container { max-width: 900px; margin: 0 auto; background: white; border-radius: 12px; box-shadow: 0 4px 20px rgba(0,0,0,0.1); overflow: hidden; }\n .header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 30px; text-align: center; }\n .header h1 { margin: 0; font-size: 32px; font-weight: 300; }\n .success-badge { background: #10b981; color: white; padding: 10px 20px; border-radius: 25px; display: inline-block; margin-top: 15px; font-weight: 600; font-size: 16px; }\n .content { padding: 35px; }\n .summary { background: #f8fafc; border-radius: 12px; padding: 25px; margin-bottom: 30px; }\n .stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 20px; margin-bottom: 25px; }\n .stat-card { background: white; border: 1px solid #e5e7eb; border-radius: 10px; padding: 20px; text-align: center; transition: transform 0.2s; }\n .stat-card:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0,0,0,0.1); }\n .stat-number { font-size: 28px; font-weight: bold; color: #374151; margin-bottom: 8px; }\n .stat-label { color: #6b7280; font-size: 14px; text-transform: uppercase; letter-spacing: 0.5px; }\n .stat-sublabel { color: #9ca3af; font-size: 12px; margin-top: 4px; }\n .insights-section { background: #eff6ff; border-radius: 12px; padding: 25px; margin-bottom: 30px; }\n .insight-item { background: white; border-radius: 8px; padding: 15px; margin-bottom: 10px; border-left: 4px solid #3b82f6; }\n .insight-item:last-child { margin-bottom: 0; }\n .workflows-table { width: 100%; border-collapse: collapse; margin-top: 20px; }\n .workflows-table th { background: #f9fafb; color: #374151; padding: 14px 12px; text-align: left; font-weight: 600; border-bottom: 2px solid #e5e7eb; font-size: 14px; }\n .workflows-table td { padding: 12px; border-bottom: 1px solid #f3f4f6; font-size: 14px; }\n .workflows-table tr:hover { background-color: #f9fafb; }\n .status-active { color: #10b981; font-weight: 600; }\n .status-inactive { color: #6b7280; }\n .size-large { color: #f59e0b; font-weight: 600; }\n .size-normal { color: #6b7280; }\n .footer { background: #f9fafb; padding: 25px 35px; color: #6b7280; font-size: 14px; text-align: center; }\n .folder-name { color: #4f46e5; font-weight: 600; }\n .backup-info { background: #eff6ff; border-left: 4px solid #3b82f6; padding: 20px; margin-bottom: 25px; border-radius: 0 8px 8px 0; }\n .cleanup-info { background: ${cleanupStatus === 'Failed' ? '#fee2e2' : cleanupStatus === 'Partially Completed' ? '#fef3c7' : cleanupStatus === 'Unknown' ? '#f3f4f6' : '#f0fdf4'}; border-left: 4px solid ${cleanupColor}; padding: 15px; margin-top: 15px; border-radius: 0 6px 6px 0; font-size: 14px; }\n @media (max-width: 600px) {\n .stats-grid { grid-template-columns: repeat(2, 1fr); }\n .container { margin: 10px; }\n .content { padding: 25px; }\n .workflows-table th, .workflows-table td { padding: 8px; font-size: 13px; }\n }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <div class=\"header\">\n <h1>🛡️ n8n Backup Complete</h1>\n <div class=\"success-badge\">✅ BACKUP SUCCESSFUL</div>\n </div>\n \n <div class=\"content\">\n <div class=\"backup-info\">\n <strong>📁 Backup Folder:</strong> <span class=\"folder-name\">${folderName}</span><br>\n <strong>📅 Backup Date:</strong> ${backupDate.toFormat('DDDD')}<br>\n <strong>⏰ Backup Time:</strong> ${backupDate.toFormat('HH:mm:ss ZZZZ')}<br>\n <strong>🏢 Instance:</strong> n8n\n <div class=\"cleanup-info\">\n ${cleanupIcon} <strong>Cleanup Status:</strong> ${cleanupStatus}<br>\n <span style=\"font-size: 13px; color: #4b5563;\">${cleanupNote}</span>\n </div>\n </div>\n \n <div class=\"summary\">\n <h2 style=\"margin-top: 0; color: #374151; font-size: 24px; margin-bottom: 20px;\">📊 Backup Summary</h2>\n <div class=\"stats-grid\">\n <div class=\"stat-card\">\n <div class=\"stat-number\">${totalWorkflows}</div>\n <div class=\"stat-label\">Total Workflows</div>\n </div>\n <div class=\"stat-card\">\n <div class=\"stat-number\">${activeWorkflows}</div>\n <div class=\"stat-label\">Active Workflows</div>\n <div class=\"stat-sublabel\">${totalWorkflows > 0 ? Math.round((activeWorkflows/totalWorkflows)*100) : 0}% of total</div>\n </div>\n <div class=\"stat-card\">\n <div class=\"stat-number\">${inactiveWorkflows}</div>\n <div class=\"stat-label\">Inactive Workflows</div>\n <div class=\"stat-sublabel\">${totalWorkflows > 0 ? Math.round((inactiveWorkflows/totalWorkflows)*100) : 0}% of total</div>\n </div>\n <div class=\"stat-card\">\n <div class=\"stat-number\">${Math.round(totalSizeKB * 100) / 100} KB</div>\n <div class=\"stat-label\">Total Backup Size</div>\n <div class=\"stat-sublabel\">Avg: ${averageWorkflowSize} KB per workflow</div>\n </div>\n <div class=\"stat-card\">\n <div class=\"stat-number\" style=\"color: ${cleanupColor};\">${cleanupIcon}</div>\n <div class=\"stat-label\">Cleanup Status</div>\n <div class=\"stat-sublabel\">${cleanupStatus}</div>\n </div>\n ${recentlyModifiedCount > 0 ? `\n <div class=\"stat-card\">\n <div class=\"stat-number\">${recentlyModifiedCount}</div>\n <div class=\"stat-label\">Recently Modified</div>\n <div class=\"stat-sublabel\">Last 7 days</div>\n </div>\n ` : ''}\n ${largeWorkflowsCount > 0 ? `\n <div class=\"stat-card\">\n <div class=\"stat-number\">${largeWorkflowsCount}</div>\n <div class=\"stat-label\">Large Workflows</div>\n <div class=\"stat-sublabel\">> 50 KB</div>\n </div>\n ` : ''}\n </div>\n </div>\n \n ${recentlyModifiedCount > 0 || largeWorkflowsCount > 0 ? `\n <div class=\"insights-section\">\n <h3 style=\"margin-top: 0; color: #374151; font-size: 18px; margin-bottom: 15px;\">💡 Backup Insights</h3>\n ${recentlyModifiedCount > 0 ? `\n <div class=\"insight-item\">\n <strong>🔄 Recent Activity:</strong> ${recentlyModifiedCount} workflow${recentlyModifiedCount > 1 ? 's have' : ' has'} been modified in the last 7 days, indicating active development.\n </div>\n ` : ''}\n ${largeWorkflowsCount > 0 ? `\n <div class=\"insight-item\">\n <strong>📈 Large Workflows:</strong> ${largeWorkflowsCount} workflow${largeWorkflowsCount > 1 ? 's are' : ' is'} larger than 50KB, which may indicate complex automation processes.\n </div>\n ` : ''}\n ${activeWorkflows > 0 ? `\n <div class=\"insight-item\">\n <strong>⚡ Active Operations:</strong> ${activeWorkflows} active workflow${activeWorkflows > 1 ? 's are' : ' is'} currently running and processing data automatically.\n </div>\n ` : ''}\n </div>\n ` : ''}\n \n <h3 style=\"color: #374151; margin-bottom: 15px;\">📋 Backed Up Workflows</h3>\n <div style=\"overflow-x: auto;\">\n <table class=\"workflows-table\">\n <thead>\n <tr>\n <th>Workflow Name</th>\n <th>Status</th>\n <th>Last Updated</th>\n <th>Size (KB)</th>\n </tr>\n </thead>\n <tbody>\n ${workflowList.map(wf => `\n <tr>\n <td style=\"font-weight: 500;\">${wf.name}</td>\n <td class=\"${wf.active ? 'status-active' : 'status-inactive'}\">\n ${wf.active ? '🟢 Active' : '⚪ Inactive'}\n </td>\n <td>${wf.updatedAt}</td>\n <td class=\"${wf.size > 50 ? 'size-large' : 'size-normal'}\">\n ${wf.size} KB ${wf.size > 50 ? '📊' : ''}\n </td>\n </tr>\n `).join('')}\n </tbody>\n </table>\n </div>\n </div>\n \n <div class=\"footer\">\n <p style=\"margin-bottom: 10px;\">🚀 <strong>Automated backup by n8n</strong></p>\n <p style=\"margin-bottom: 10px;\">📅 Next backup scheduled for <strong>tomorrow at 01:00 AM</strong></p>\n <p style=\"margin-bottom: 10px;\">☁️ This backup has been safely stored in <strong>Microsoft OneDrive</strong></p>\n <p style=\"margin: 0; font-size: 12px; color: #9ca3af;\">\n Backup ID: ${folderName} | Generated: ${backupDate.toISO()}\n </p>\n </div>\n </div>\n</body>\n</html>\n`;\n\n// Debug logging\nconsole.log('Safe Email Debug Info:');\nconsole.log('Total workflows:', totalWorkflows);\nconsole.log('Active workflows:', activeWorkflows);\nconsole.log('Cleanup status:', cleanupStatus, '(' + cleanupNote + ')');\nconsole.log('Uploaded files:', uploadedFiles.length);\nconsole.log('Current input length:', $input.all().length);\n\nreturn [{\n json: {\n htmlEmailBody: htmlBody,\n subject: `🛡️ n8n Daily Backup Success - ${totalWorkflows} workflows backed up (${Math.round(totalSizeKB * 100) / 100} KB)`,\n summary: {\n totalWorkflows,\n activeWorkflows,\n inactiveWorkflows,\n totalSizeKB: Math.round(totalSizeKB * 100) / 100,\n averageWorkflowSize,\n recentlyModifiedCount,\n largeWorkflowsCount,\n backupDate: backupDate.toISO(),\n folderName,\n cleanupStatus,\n cleanupNote,\n cleanupIcon\n },\n workflowList,\n insights: {\n recentlyModified: workflowsByStatus.recentlyModified.length,\n largeWorkflows: workflowsByStatus.large.length,\n activePercentage: totalWorkflows > 0 ? Math.round((activeWorkflows/totalWorkflows)*100) : 0\n }\n }\n}];"
},
"typeVersion": 2
},
{
"id": "d846405f-6dde-40a1-b96f-e23225b59eb6",
"name": "일정 트리거 Daily",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-5520,
96
],
"parameters": {
"rule": {
"interval": [
{
"triggerAtHour": 1
}
]
}
},
"typeVersion": 1.2
},
{
"id": "7e961954-d2ed-4a9d-8725-d444a1868c9f",
"name": "Send HTML Success Email",
"type": "n8n-nodes-base.microsoftOutlook",
"position": [
-80,
112
],
"webhookId": "cdac200b-7c74-455c-b68d-fda0885fac67",
"parameters": {
"subject": "={{ $json.subject }}",
"bodyContent": "={{ $json.htmlEmailBody }}",
"additionalFields": {
"bodyContentType": "html"
}
},
"typeVersion": 2
},
{
"id": "e7575c54-1134-45bc-a4ed-fe88d5d27634",
"name": "Search a folder",
"type": "n8n-nodes-base.microsoftOneDrive",
"disabled": true,
"position": [
-5216,
-272
],
"parameters": {
"query": "Daily",
"resource": "folder",
"operation": "search"
},
"typeVersion": 1
},
{
"id": "d9b6048b-49bb-4e6b-97e9-8fb0bd2b122a",
"name": "스위치 Old Folders",
"type": "n8n-nodes-base.switch",
"position": [
-2352,
96
],
"parameters": {
"rules": {
"values": [
{
"outputKey": "False",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "4efc2685-d40a-4bcd-bb19-40a50cc80b13",
"operator": {
"type": "boolean",
"operation": "false",
"singleValue": true
},
"leftValue": "={{ $json.hasOldFolders }}",
"rightValue": ""
}
]
},
"renameOutput": true
},
{
"outputKey": "True",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "832f5561-39f3-4786-8842-0adc8071ecaa",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $json.hasOldFolders }}",
"rightValue": ""
}
]
},
"renameOutput": true
}
]
},
"options": {}
},
"typeVersion": 3.2
},
{
"id": "df14e3ce-8a86-4c1d-a7a3-405f40f90d6b",
"name": "항목 반복",
"type": "n8n-nodes-base.splitInBatches",
"position": [
-1776,
240
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "af00819c-d885-4021-b693-06b9fb102112",
"name": "병합",
"type": "n8n-nodes-base.merge",
"position": [
-1008,
112
],
"parameters": {},
"typeVersion": 3.2
},
{
"id": "83e234c1-9eb7-48dc-8956-a818fa338a8f",
"name": "Create new backup folder",
"type": "n8n-nodes-base.microsoftOneDrive",
"position": [
-5056,
96
],
"parameters": {
"name": "=n8n_{{$now.format('yyyy-MM-dd')}}",
"options": {
"parentFolderId": ""
},
"resource": "folder",
"operation": "create"
},
"typeVersion": 1
},
{
"id": "b1fda1d4-c8b6-4882-95a2-048400064677",
"name": "Convert to JSON file",
"type": "n8n-nodes-base.convertToFile",
"position": [
-4160,
96
],
"parameters": {
"mode": "each",
"options": {
"format": true,
"fileName": "={{ $json.name }}"
},
"operation": "toJson"
},
"typeVersion": 1.1
},
{
"id": "ea490d15-f4d0-485e-8686-deb9044012b6",
"name": "Upload JSON to folder",
"type": "n8n-nodes-base.microsoftOneDrive",
"position": [
-3712,
96
],
"parameters": {
"parentId": "={{ $('Create new backup folder').item.json.id }}",
"binaryData": true
},
"retryOnFail": false,
"typeVersion": 1
},
{
"id": "21d3de22-1836-49cd-99b7-1fafb710294e",
"name": "필터 backup folder",
"type": "n8n-nodes-base.code",
"position": [
-2848,
96
],
"parameters": {
"jsCode": "// Filter backup folders older than 31 days - Clean version\nconst inputItems = $input.all();\nconst cutoffDate = DateTime.now().minus({ days: 31 });\n\nconsole.log('Filtering backup folders older than 31 days');\nconsole.log('Cutoff date:', cutoffDate.toISO());\nconsole.log('Total folders found:', inputItems.length);\n\n// Filter folders older than 8 days\nconst oldFolders = [];\n\n// Process each input item\ninputItems.forEach((item, index) => {\n try {\n if (item.json.lastModifiedDateTime) {\n const folderDate = DateTime.fromISO(item.json.lastModifiedDateTime);\n const isOld = folderDate < cutoffDate;\n \n console.log('Folder:', item.json.name || 'Unknown', 'Date:', folderDate.toFormat('dd/MM/yyyy'), 'Old:', isOld);\n \n if (isOld) {\n oldFolders.push(item);\n }\n }\n } catch (error) {\n console.log('Error parsing date for folder:', item.json.name, error);\n }\n});\n\nconsole.log('Old folders to delete:', oldFolders.length);\nconsole.log('Recent folders to keep:', inputItems.length - oldFolders.length);\n\nif (oldFolders.length > 0) {\n // FOUND OLD FOLDERS TO DELETE\n // Return ONLY the old folders with summary info in first item\n const result = oldFolders.map((folder, index) => {\n if (index === 0) {\n // First old folder gets summary metadata\n return {\n json: {\n id: folder.json.id,\n name: folder.json.name,\n lastModifiedDateTime: folder.json.lastModifiedDateTime,\n createdDateTime: folder.json.createdDateTime,\n size: folder.json.size,\n // Add metadata\n hasOldFolders: true,\n oldFoldersCount: oldFolders.length,\n totalFoldersChecked: inputItems.length,\n cutoffDate: cutoffDate.toISO()\n }\n };\n } else {\n // Other old folders keep original structure\n return {\n json: {\n id: folder.json.id,\n name: folder.json.name,\n lastModifiedDateTime: folder.json.lastModifiedDateTime,\n createdDateTime: folder.json.createdDateTime,\n size: folder.json.size\n }\n };\n }\n });\n \n console.log('Returning', result.length, 'OLD folders for deletion');\n return result;\n \n} else {\n // NO OLD FOLDERS FOUND\n // Return single summary item\n console.log('No old folders found - all folders are recent');\n return [{\n json: {\n hasOldFolders: false,\n oldFoldersCount: 0,\n totalFoldersChecked: inputItems.length,\n cutoffDate: cutoffDate.toISO(),\n recentFoldersCount: inputItems.length,\n message: 'All backup folders are recent - no cleanup needed'\n }\n }];\n}"
},
"typeVersion": 2
},
{
"id": "ba663fbc-67f2-47e3-a237-122aa555f7d8",
"name": "메모 - Overview",
"type": "n8n-nodes-base.stickyNote",
"position": [
-6320,
128
],
"parameters": {
"color": 3,
"width": 600,
"height": 940,
"content": "## 🗂️ Automated Workflow Backup Manager\n\n### Goal:\nThis workflow automates the process of backing up your workflows in n8n by creating a new backup folder in OneDrive. It first retrieves existing workflows, deletes old backup folders if they exist, and then generates JSON files of the current workflows. An email notification confirms successful backups, ensuring you never lose your critical configurations.\n\n### How it works:\n- 🏁 **Schedule Trigger Daily**: Run the workflow daily.\n- 🔄 **Retrieve Workflows**: Use the n8n node to collect all of your workflows.\n- 💼 **Get Backup Folders**: Check for existing backup folders in OneDrive.\n- 🗑️ **Delete Old Folder**: Remove the previous backup if it exists.\n- 📧 **Prepare HTML Email**: Craft an email template to notify of successful backup.\n- 📤 **Send HTML Success Email**: Notify you upon successful execution.\n- 📁 **Create New Backup Folder**: Generate a new folder for the current backup.\n- 📝 **Convert to JSON**: Transform workflows into JSON format for storage.\n- 📤 **Upload JSON File**: Place the newly created JSON files into OneDrive.\n\n### Parameters to Configure:\n- OneDrive folder path for backups\n- Email address for notifications\n- Daily scheduling options\n\n### Limitations / Gotchas:\n- The workflow assumes an active OneDrive account.\n- Ensure that folder permissions allow file creation and deletion.\n- Sent A email using the Outlook Node\n\n### Expected Result:\nUpon execution, you'll receive a confirmation email, and the latest workflows will be securely backed up in the designated OneDrive folder.\n\n## The green notes need action.\n- For both you need to find the Folder ID. \n- Use the Search a Folder node to find the folder ID\n"
},
"typeVersion": 1
},
{
"id": "0a3c08c4-6a18-4755-be8d-fc45103959f0",
"name": "Sticky Note - Send HTML Success Email",
"type": "n8n-nodes-base.stickyNote",
"position": [
-192,
304
],
"parameters": {
"color": 7,
"width": 380,
"height": 860,
"content": "## 📧 Send HTML Success Email \n\n### 🎯 Purpose\nSend an HTML formatted success email to a specified recipient, allowing for rich formatting and design in the email content.\n\n### 🔄 Inputs / Outputs\n- **Inputs:**\n - To: fill in your emailadres\n - Subject of the email (provided via `{{$json.subject}}`).\n - HTML content for the email body (provided via `{{$json.htmlEmailBody}}`).\n- **Outputs:**\n - Confirmation of the email sent or any errors encountered during the send process.\n\n### ⚙️ Key Fields to Configure\n- **To:** emailadress\n- **Subject:**\n - Set using `\"={{ $json.subject }}\"`.\n- **Body Content:**\n - Set using `\"={{ $json.htmlEmailBody }}\"`.\n- **Additional Fields:**\n - `bodyContentType`: Ensure it is set to `\"html\"` to properly render HTML content.\n\n### 📝 Tip / Validation\n- Verify that the `subject` and `htmlEmailBody` are populated before triggering the email to ensure that the recipient receives meaningful content.\n- Test the email format by sending a sample email to yourself to check for correct rendering of the HTML content."
},
"typeVersion": 1
},
{
"id": "46ee0eac-d1e0-4948-ad60-f729abe72f3c",
"name": "Sticky Note - Prepare HTML Email",
"type": "n8n-nodes-base.stickyNote",
"position": [
-608,
304
],
"parameters": {
"color": 7,
"width": 380,
"height": 860,
"content": "## 📧 Prepare HTML Email\n\n### 🎯 Purpose\nCreate a formatted HTML email to summarize and document the results of a successful backup process, including essential statistics and insights about workflows.\n\n### 🔄 Inputs / Outputs\n- **Inputs:** \n - Workflow data, including active and inactive workflows, and sizes of uploaded files.\n- **Outputs:**\n - An HTML formatted email body and a subject line for sending notifications about the backup.\n\n### ⚙️ Key Fields to Configure\n- **HTML Email Structure:** \n - The node builds a user-friendly email layout, including workflow statistics, insights, and cleanup status.\n- **Custom Variables in Email:**\n - Variables such as `totalWorkflows`, `activeWorkflows`, `cleanupStatus`, and `folderName` are used to populate the email dynamically.\n\n### 📝 Tip / Validation\n- Ensure that all previous nodes (like 'Retrieve workflows' and 'Upload JSON to folder') are executed successfully to provide accurate data for the email.\n- Test the email format to ensure it renders correctly across different email clients. \n- Monitor log outputs for debugging purposes, especially to check for potential data retrieval errors."
},
"typeVersion": 1
},
{
"id": "baec94aa-e4c1-4341-92aa-e787c084966e",
"name": "Sticky Note - 병합",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1040,
304
],
"parameters": {
"color": 7,
"width": 380,
"height": 540,
"content": "## 🔗 Merge \n\n### 🎯 Purpose\nCombine multiple streams of data into a single output, allowing for flexible data manipulation and processing within workflows.\n\n### 🔄 Inputs / Outputs\n- **Inputs:** \n - Multiple data streams from preceding nodes.\n- **Outputs:** \n - A single combined data stream, merging inputs based on defined criteria.\n\n### 📝 Tip / Validation\n- Ensure that the inputs you want to merge are compatible in terms of data types and structure.\n- The Merge node can be configured to use different strategies (e.g., combine all inputs, take first input only). Double-check the merging strategy based on your workflow requirements."
},
"typeVersion": 1
},
{
"id": "7c8e9e6c-aa5e-4ecb-8669-f86051cce7ab",
"name": "메모 - Delete old backup folder",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1504,
448
],
"parameters": {
"color": 7,
"width": 380,
"height": 668,
"content": "## 🗑️ Delete Old Backup Folder \n\n### 🎯 Purpose\nRemove outdated backup folders from Microsoft OneDrive to maintain organization and free up space.\n\n### 🔄 Inputs / Outputs\n- **Inputs:** \n - Folder ID of the backup to be deleted, dynamically sourced from workflow data.\n- **Outputs:** \n - Confirmation of folder deletion, if applicable.\n\n### ⚙️ Key Fields to Configure\n- **Folder ID:** \n - Specify the ID of the folder you wish to delete. It should be passed dynamically using the expression `={{ $json.id }}`.\n\n### 📝 Tip / Validation\n- Ensure that the folder ID is correct to avoid accidental deletion of important data.\n- Confirm that adequate permissions are in place for the Microsoft OneDrive account being utilized to perform the delete operation.\n- Deleted folders cannot be recovered unless a backup system is in place; use this operation with caution."
},
"typeVersion": 1
},
{
"id": "c56f7762-dcfe-4078-ba90-2d14e9a05b31",
"name": "Sticky Note - 항목 반복",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1920,
448
],
"parameters": {
"color": 7,
"width": 380,
"height": 620,
"content": "## 📁 Loop Over Items \n\n### 🎯 Purpose\nRemove old folder 1 by 1\n\n### 🔄 Inputs / Outputs\n- **Inputs:** \n - A list of items to be processed.\n- **Outputs:** \n - A series of batches, each containing a subset of the original items.\n\n### ⚙️ Key Fields to Configure\n- **Options:**\n - No specific options are specified, but batching may be adjusted by further custom configuration in connected nodes."
},
"typeVersion": 1
},
{
"id": "e4ccfaed-5fce-4b58-8757-f5883787b979",
"name": "Sticky Note - 스위치 Old Folders",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2464,
272
],
"parameters": {
"color": 7,
"width": 380,
"height": 732,
"content": "## 🔄 Switch Old Folders \n\n### 🎯 Purpose\nThis node determines the presence of old folders and routes the workflow based on that condition.\n\n### 🔄 Inputs / Outputs\n- **Inputs:** \n - Boolean input `hasOldFolders` that indicates if old folders exist.\n- **Outputs:** \n - Two distinct outputs based on the conditions:\n - **True:** If `hasOldFolders` is true.\n - **False:** If `hasOldFolders` is false.\n\n### ⚙️ Key Fields to Configure\n- **Rules:**\n - Define conditions for routing:\n - **True Condition:** Triggered when `hasOldFolders` evaluates to true.\n - **False Condition:** Triggered when `hasOldFolders` evaluates to false.\n \n### 📝 Tip / Validation\n- Ensure the input `hasOldFolders` is correctly set to a boolean value (`true` or `false`).\n- Remember to define follow-up nodes for both output paths to manage workflow logic effectively. \n- Case sensitivity settings can be adjusted if necessary, but default options typically suffice for boolean operations."
},
"typeVersion": 1
},
{
"id": "8801d8ea-a8c3-4e5d-bc7b-4c5ecd0a9822",
"name": "Sticky Note - 필터 backup folder",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2976,
272
],
"parameters": {
"color": 7,
"width": 380,
"height": 876,
"content": "## 📁 Filter Backup Folder \n\n### 🎯 Purpose\nThis node filters and identifies backup folders that are older than 31 days, allowing for effective management and cleanup of dated backups.\n- Change the \"Days\" to keep the backups longer/shorter\n\n### 🔄 Inputs / Outputs\n- **Inputs:** \n - A list of backup folders with associated metadata including `lastModifiedDateTime`.\n- **Outputs:** \n - Old backup folders for deletion or a summary message regarding folder age.\n\n### ⚙️ Key Fields to Configure\n- **inputItems:** \n - This receives folders with metadata such as `id`, `name`, `lastModifiedDateTime`, and `size`.\n \n### 📝 Tip / Validation\n- Ensure that the `lastModifiedDateTime` field is in ISO format for accurate date comparison.\n- The script will log the processing of each folder and can handle parsing errors without stopping the execution.\n- Check logs for details on filtered items, including summary information when old folders are found or when all folders are determined to be recent. \n\n### ⚠️ Gotchas\n- If no old folders are found, the output will include a message indicating that no cleanup is needed.\n- Modifications to the cutoff date can be made by adjusting the value in `DateTime.now().minus({ days: 31 })`."
},
"typeVersion": 1
},
{
"id": "8b871fe0-f8f4-48c1-9954-4ddb0a835293",
"name": "메모 - Get backupfolders",
"type": "n8n-nodes-base.stickyNote",
"position": [
-3392,
272
],
"parameters": {
"color": 4,
"width": 380,
"height": 748,
"content": "## 📁 Get backup folders \n\n## Folder ID need the be insert \n\n### 🎯 Purpose\nRetrieve a list of backuped folders from your main backup folder to remove old backups folders.\n\n### 🔄 Inputs / Outputs\n- **Inputs:** \n - Use the folder ID that you get from the \"Search a folder \"Node\n- **Outputs:** \n - A list of backup folders stored in the connected OneDrive account.\n\n### ⚙️ Key Fields to Configure\n- **Resource:** \n - Set to `\"folder\"` to specify that you are querying for folder resources.\n\n### 📝 Tip / Validation\n- Ensure that your Microsoft OneDrive account credentials are correctly configured and authorized in n8n to avoid authentication errors.\n- Check the scope of access granted to the OneDrive API to ensure you have permissions to list folders."
},
"typeVersion": 1
},
{
"id": "05e566d8-2cf1-4d6a-ae96-8800a5ba3d43",
"name": "Sticky Note - Upload JSON to folder",
"type": "n8n-nodes-base.stickyNote",
"position": [
-3824,
272
],
"parameters": {
"color": 7,
"width": 380,
"height": 876,
"content": "## 📁 Upload JSON to Folder \n\n### 🎯 Purpose\nUpload the JSON file(s) to newly create backup folder.\n\n### 🔄 Inputs / Outputs\n- **Inputs:** \n - JSON file data to be uploaded.\n - Parent folder ID where the JSON will be uploaded.\n- **Outputs:** \n - Confirmation of the uploaded file and its metadata.\n\n### ⚙️ Key Fields to Configure\n- **Parent ID:** \n - Set this to the ID of the folder where the JSON will be uploaded. It can be dynamically retrieved from another node, e.g., `={{ $('Create new backup folder').item.json.id }}`.\n- **Binary Data:** \n - Ensure this is set to true to properly upload binary JSON data.\n\n### 📝 Tip / Validation\n- Make sure the specified folder exists in OneDrive; the upload will fail if the folder is missing or inaccessible.\n- Verify that the OneDrive credentials used have sufficient permissions to upload files to the designated folder."
},
"typeVersion": 1
},
{
"id": "77768b3c-e607-4896-ba99-5f6ae71d40bc",
"name": "Sticky Note - Convert to JSON file",
"type": "n8n-nodes-base.stickyNote",
"position": [
-4288,
272
],
"parameters": {
"color": 7,
"width": 380,
"height": 876,
"content": "## 📄 Convert to JSON file \n\n### 🎯 Purpose\nConvert the workflows into a JSON file.\n\n### 🔄 Inputs / Outputs\n- **Inputs:** \n - Data to be formatted as JSON.\n- **Outputs:** \n - A JSON file generated based on the input data.\n\n### ⚙️ Key Fields to Configure\n- **Operation:** \n - Set to `toJson` (default).\n- **Mode:** \n - Specify `each` to convert each item individually.\n- **Options:**\n - **Format:** Set to `true` for pretty-printed JSON.\n - **File Name:** Use `={{ $json.name }}` to dynamically name the output file based on input data.\n"
},
"typeVersion": 1
},
{
"id": "a60decc9-42fc-465d-a89f-f552e6a84814",
"name": "메모 - Retrieve workflows",
"type": "n8n-nodes-base.stickyNote",
"position": [
-4736,
272
],
"parameters": {
"color": 7,
"width": 380,
"height": 876,
"content": "## 📁 Retrieve Workflows \n\n### 🎯 Purpose\nFetch existing workflows from n8n, enabling users to review and document their configurations easily.\n\n### 🔄 Inputs / Outputs\n- **Inputs:** \n - No specific input parameters. Filters can be applied if needed.\n- **Outputs:** \n - List of workflows available in the n8n account for documentation purposes.\n\n### ⚙️ Key Fields to Configure\n- **Filters:** \n - Apply any specific criteria to limit the workflows retrieved. However, it is optional and can be left empty for a full list.\n- **Request Options:** \n - Adjust settings related to the request (though, no specific options are outlined in this case).\n\n### 📝 Tip / Validation\n- If using filters, ensure they are accurately defined to retrieve the desired workflows.\n- Regularly check your n8n account credentials to maintain access when retrieving workflows. Any disruption may result in access issues."
},
"typeVersion": 1
},
{
"id": "52972885-4bad-4a28-b02c-fd454d97a97f",
"name": "메모 - Search a folder",
"type": "n8n-nodes-base.stickyNote",
"position": [
-5424,
-944
],
"parameters": {
"color": 2,
"width": 540,
"height": 860,
"content": "## 🔍 Search a Folder \n\n### 🎯 Purpose\nUse to find the Folder ID from your Backup folder, This folder will be used to create new daily folders \n\n### 🔄 Inputs / Outputs\n- **Inputs:** \n - **Query:** String to filter search results (e.g., \"Backup folder\").\n- **Outputs:** \n - List of folders that match the search criteria from Microsoft OneDrive.\n\n### ⚙️ Key Fields to Configure\n- **Resource:** \n - Set to \"folder\" to specify the type of resource you are searching for.\n- **Operation:** \n - Set to \"search\" to indicate the desired action.\n- **Query:** \n - Provide the search term for folder names (e.g., \"DBackup folder\").\n\n### 📝 Tip / Validation\n- Ensure that the Microsoft OneDrive credentials are correctly set up to allow access to the folder search functionality.\n- The node is currently **disabled**; enable it to search the folder ID\n- Consider potential limitations of the search functionality, such as case sensitivity or folder visibility settings."
},
"typeVersion": 1
},
{
"id": "cc5e9202-f9f3-4cac-a849-9d5f3febbf20",
"name": "메모 - Create new backup folder",
"type": "n8n-nodes-base.stickyNote",
"position": [
-5184,
272
],
"parameters": {
"color": 4,
"width": 380,
"height": 924,
"content": "## 📁 Create New Backup Folder\n\n## Folder ID need the be insert \n\n### 🎯 Purpose\nCreate a new folder in Microsoft OneDrive specifically for backing up workflow documentation.\n\n### 🔄 Inputs / Outputs\n- **Inputs:** \n - Use the folder ID that you get from the \"Search a folder\"Node\n- **Outputs:** \n - New folder ID and details for further use or confirmation.\n\n### ⚙️ Key Fields to Configure\n- **Resource:** \n - Set to `\"folder\"` to specify the type of resource being created.\n- **Operation:** \n - Set to `\"create\"` to initiate the folder creation process.\n- **Name:** \n - Dynamic name generated as `n8n_{{current_date}}` where `current_date` is formatted as `yyyy-MM-dd`.\n- **Options:** \n - **parentFolderId:** \n - Leave blank if creating in the root directory or specify an existing folder ID if needed.\n\n### 📝 Tip / Validation\n- Ensure the Microsoft OneDrive account linked has appropriate permissions to create folders.\n- Verify the folder creation pattern aligns with your backup schedule and naming conventions for better organization."
},
"typeVersion": 1
},
{
"id": "ea1105b6-5b0e-4ee6-b1d0-a8f210cce50b",
"name": "Sticky Note - 일정 트리거 Daily",
"type": "n8n-nodes-base.stickyNote",
"position": [
-5632,
272
],
"parameters": {
"color": 7,
"width": 380,
"height": 876,
"content": "## 📅 Schedule Trigger Daily \n\n### 🎯 Purpose\nTriggers the workflow daily at a specified time to ensure scheduled actions are automatically executed.\n\n### 🔄 Inputs / Outputs\n- **Inputs:** \n - None (This node operates based solely on its schedule).\n- **Outputs:** \n - A trigger signal that starts subsequent nodes in the workflow at the scheduled time.\n\n### ⚙️ Key Fields to Configure\n- **Trigger At Hour:** \n - Set to `1`, which means the workflow will be triggered daily at 1:00 AM.\n\n### 📝 Tip / Gotchas\n- Remember that the hour is based on the server's timezone settings—adjust accordingly if your workflow requires a different timezone.\n- If you need more complex scheduling (e.g., multiple trigger times), consider using additional nodes or configurations."
},
"typeVersion": 1
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "e5bb50a7-5d9c-42dd-b660-92172b5e49ae",
"connections": {
"Merge": {
"main": [
[
{
"node": "c79f2638-dd31-4c07-ad61-b25efc2919bd",
"type": "main",
"index": 0
}
]
]
},
"Loop Over Items": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 1
}
],
[
{
"node": "cf46cd5f-f000-40ec-a6c8-110984437c6c",
"type": "main",
"index": 0
}
]
]
},
"84b64870-e3c4-4762-9931-c5ec929c904e": {
"main": [
[
{
"node": "Filter backup folder",
"type": "main",
"index": 0
}
]
]
},
"c79f2638-dd31-4c07-ad61-b25efc2919bd": {
"main": [
[
{
"node": "7e961954-d2ed-4a9d-8725-d444a1868c9f",
"type": "main",
"index": 0
}
]
]
},
"96aee703-bbf4-4de0-b6fb-7cf8428d5027": {
"main": [
[
{
"node": "b1fda1d4-c8b6-4882-95a2-048400064677",
"type": "main",
"index": 0
}
]
]
},
"Switch Old Folders": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 0
}
],
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"b1fda1d4-c8b6-4882-95a2-048400064677": {
"main": [
[
{
"node": "ea490d15-f4d0-485e-8686-deb9044012b6",
"type": "main",
"index": 0
}
]
]
},
"Filter backup folder": {
"main": [
[
{
"node": "Switch Old Folders",
"type": "main",
"index": 0
}
]
]
},
"ea490d15-f4d0-485e-8686-deb9044012b6": {
"main": [
[
{
"node": "84b64870-e3c4-4762-9931-c5ec929c904e",
"type": "main",
"index": 0
}
]
]
},
"Schedule Trigger Daily": {
"main": [
[
{
"node": "83e234c1-9eb7-48dc-8956-a818fa338a8f",
"type": "main",
"index": 0
}
]
]
},
"83e234c1-9eb7-48dc-8956-a818fa338a8f": {
"main": [
[
{
"node": "96aee703-bbf4-4de0-b6fb-7cf8428d5027",
"type": "main",
"index": 0
}
]
]
},
"cf46cd5f-f000-40ec-a6c8-110984437c6c": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
}
}
}자주 묻는 질문
이 워크플로우를 어떻게 사용하나요?
위의 JSON 구성 코드를 복사하여 n8n 인스턴스에서 새 워크플로우를 생성하고 "JSON에서 가져오기"를 선택한 후, 구성을 붙여넣고 필요에 따라 인증 설정을 수정하세요.
이 워크플로우는 어떤 시나리오에 적합한가요?
고급 - 데브옵스
유료인가요?
이 워크플로우는 완전히 무료이며 직접 가져와 사용할 수 있습니다. 다만, 워크플로우에서 사용하는 타사 서비스(예: OpenAI API)는 사용자 직접 비용을 지불해야 할 수 있습니다.
관련 워크플로우 추천
n8n API와 이메일을 사용하여 주간 작업 흐름 분석 보고서 생성
n8n API와 이메일을 사용하여 주간 워크플로우 분석 보고서 생성
N8n
Set
Code
+
N8n
Set
Code
19 노드Wessel Bulte
데브옵스
고급 n8n 워크플로우와 GitHub 동기화
GitHub를 활용한 지능형 변경 감지 자동화 워크플로우 백업
If
N8n
Set
+
If
N8n
Set
38 노드Maksym Brashenko
데브옵스
자동화된 n8n 워크플로우 백업至 GitHub 및 삭제 추적
삭제 추적이 포함된 GitHub 자동화 n8n 워크플로우 백업
If
N8n
Set
+
If
N8n
Set
31 노드Marcial Ambriz
데브옵스
귀하의 워크플로우를 GitHub 저장소에 저장
매일 워크플로우 백업을 GitHub에 저장하고 Slack 알림 전송
If
N8n
Set
+
If
N8n
Set
18 노드Andrew
데브옵스
GitHub 동기화 대시보드 - V2
提交 기록과 롤백 기능을 갖춘 GitHub 워크플로우 버전 관리 대시보드
If
N8n
Set
+
If
N8n
Set
94 노드Eduard
데브옵스
TenderNed를 사용한 네덜란드 공공 조달 데이터 수집 자동화
TenderNed를 사용한 네덜란드 공공 조달 데이터 수집 자동화
Xml
Code
Merge
+
Xml
Code
Merge
28 노드Wessel Bulte
시장 조사
워크플로우 정보
난이도
고급
노드 수29
카테고리1
노드 유형10
저자
Wessel Bulte
@uuesselCybersecurity and automation consultant specializing in n8n workflows for GDPR compliance, process optimization, and business integration. Helping teams streamline operations with secure, scalable automation solutions.
외부 링크
n8n.io에서 보기 →
이 워크플로우 공유