{
"name": "容量規劃與趨勢分析",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 8 1 * *"
}
]
}
},
"id": "schedule",
"name": "每月 1 日 08:00",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.2,
"position": [240, 300]
},
{
"parameters": {
"url": "https://mo.wooo.work/api/system/db/stats",
"options": { "timeout": 30000 }
},
"id": "uat-db-stats",
"name": "UAT DB 統計",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [460, 200],
"continueOnFail": true
},
{
"parameters": {
"url": "https://momo.wooo.work/api/system/db/stats",
"options": { "timeout": 30000 }
},
"id": "gcp-db-stats",
"name": "GCP DB 統計",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [460, 400],
"continueOnFail": true
},
{
"parameters": {
"mode": "combine",
"combineBy": "combineAll",
"options": {}
},
"id": "merge",
"name": "合併結果",
"type": "n8n-nodes-base.merge",
"typeVersion": 3,
"position": [680, 300]
},
{
"parameters": {
"jsCode": "const results = $input.all();\nconst now = new Date();\nconst monthKey = now.toISOString().slice(0, 7);\n\n// 從 static data 讀取歷史數據\nconst history = $getWorkflowStaticData('global');\nif (!history.monthly) {\n history.monthly = [];\n}\n\nconst uatStats = results[0]?.json || {};\nconst gcpStats = results[1]?.json || {};\n\n// 記錄本月數據\nhistory.monthly.push({\n month: monthKey,\n uat: {\n dbSize: uatStats.database_size_mb || 0,\n connections: uatStats.connection_count || 0,\n tableCount: uatStats.table_count || 0\n },\n gcp: {\n dbSize: gcpStats.database_size_mb || 0,\n connections: gcpStats.connection_count || 0,\n tableCount: gcpStats.table_count || 0\n }\n});\n\n// 保留最近 12 個月\nif (history.monthly.length > 12) {\n history.monthly.shift();\n}\n\n// 計算成長趨勢\nconst monthsData = history.monthly;\nlet uatGrowthRate = 0;\nlet gcpGrowthRate = 0;\nlet uatPrediction = 0;\nlet gcpPrediction = 0;\n\nif (monthsData.length >= 2) {\n const lastMonth = monthsData[monthsData.length - 2];\n const thisMonth = monthsData[monthsData.length - 1];\n \n if (lastMonth.uat.dbSize > 0) {\n uatGrowthRate = ((thisMonth.uat.dbSize - lastMonth.uat.dbSize) / lastMonth.uat.dbSize * 100).toFixed(1);\n // 預測 6 個月後的大小\n uatPrediction = (thisMonth.uat.dbSize * Math.pow(1 + parseFloat(uatGrowthRate) / 100, 6)).toFixed(0);\n }\n \n if (lastMonth.gcp.dbSize > 0) {\n gcpGrowthRate = ((thisMonth.gcp.dbSize - lastMonth.gcp.dbSize) / lastMonth.gcp.dbSize * 100).toFixed(1);\n gcpPrediction = (thisMonth.gcp.dbSize * Math.pow(1 + parseFloat(gcpGrowthRate) / 100, 6)).toFixed(0);\n }\n}\n\n// 容量警告閾值\nconst DB_SIZE_WARNING = 8000; // 8GB\nconst DB_SIZE_CRITICAL = 9000; // 9GB\n\nconst uatWarning = (uatStats.database_size_mb || 0) > DB_SIZE_WARNING;\nconst gcpWarning = (gcpStats.database_size_mb || 0) > DB_SIZE_WARNING;\nconst uatPredictionWarning = parseFloat(uatPrediction) > DB_SIZE_CRITICAL;\nconst gcpPredictionWarning = parseFloat(gcpPrediction) > DB_SIZE_CRITICAL;\n\nreturn [{\n json: {\n uat: {\n currentSize: (uatStats.database_size_mb || 0) + ' MB',\n growthRate: uatGrowthRate + '%',\n prediction6m: uatPrediction + ' MB',\n warning: uatWarning,\n predictionWarning: uatPredictionWarning\n },\n gcp: {\n currentSize: (gcpStats.database_size_mb || 0) + ' MB',\n growthRate: gcpGrowthRate + '%',\n prediction6m: gcpPrediction + ' MB',\n warning: gcpWarning,\n predictionWarning: gcpPredictionWarning\n },\n historyMonths: monthsData.length,\n hasWarning: uatWarning || gcpWarning || uatPredictionWarning || gcpPredictionWarning\n }\n}];"
},
"id": "analyze",
"name": "分析趨勢",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [900, 300]
},
{
"parameters": {
"jsCode": "const data = $input.first().json;\nconst now = new Date().toLocaleString('zh-TW', { timeZone: 'Asia/Taipei' });\n\nlet message = `📈 每月容量規劃報告\\n\\n`;\n\nmessage += `🟦 UAT 環境\\n`;\nmessage += `├ 目前大小: ${data.uat.currentSize}\\n`;\nmessage += `├ 月成長率: ${data.uat.growthRate}\\n`;\nmessage += `├ 6 個月預測: ${data.uat.prediction6m}\\n`;\nif (data.uat.warning) {\n message += `└ ⚠️ 警告:接近容量上限\\n`;\n} else if (data.uat.predictionWarning) {\n message += `└ ⚠️ 預測:6 個月內可能超過容量\\n`;\n} else {\n message += `└ ✅ 容量正常\\n`;\n}\n\nmessage += `\\n🟥 GCP 環境\\n`;\nmessage += `├ 目前大小: ${data.gcp.currentSize}\\n`;\nmessage += `├ 月成長率: ${data.gcp.growthRate}\\n`;\nmessage += `├ 6 個月預測: ${data.gcp.prediction6m}\\n`;\nif (data.gcp.warning) {\n message += `└ ⚠️ 警告:接近容量上限\\n`;\n} else if (data.gcp.predictionWarning) {\n message += `└ ⚠️ 預測:6 個月內可能超過容量\\n`;\n} else {\n message += `└ ✅ 容量正常\\n`;\n}\n\nmessage += `\\n📊 歷史數據: ${data.historyMonths} 個月\\n`;\nmessage += `⏰ 報告時間: ${now}`;\n\nreturn [{ json: { message } }];"
},
"id": "format-report",
"name": "格式化報告",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [1120, 300]
},
{
"parameters": {
"url": "https://api.telegram.org/bot/sendMessage",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"chat_id\": \"5619078117\",\n \"parse_mode\": \"HTML\",\n \"text\": \"{{ $json.message }}\"\n}",
"options": {}
},
"id": "telegram",
"name": "發送報告",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [1340, 300]
}
],
"connections": {
"每月 1 日 08:00": {
"main": [
[
{ "node": "UAT DB 統計", "type": "main", "index": 0 },
{ "node": "GCP DB 統計", "type": "main", "index": 0 }
]
]
},
"UAT DB 統計": {
"main": [
[{ "node": "合併結果", "type": "main", "index": 0 }]
]
},
"GCP DB 統計": {
"main": [
[{ "node": "合併結果", "type": "main", "index": 1 }]
]
},
"合併結果": {
"main": [
[{ "node": "分析趨勢", "type": "main", "index": 0 }]
]
},
"分析趨勢": {
"main": [
[{ "node": "格式化報告", "type": "main", "index": 0 }]
]
},
"格式化報告": {
"main": [
[{ "node": "發送報告", "type": "main", "index": 0 }]
]
}
},
"settings": {
"executionOrder": "v1"
},
"staticData": null,
"tags": [],
"triggerCount": 0,
"updatedAt": "2026-02-07T17:00:00.000Z",
"versionId": "1"
}