リアルタイム競合建築監視
これはMarket Research分野の自動化ワークフローで、13個のノードを含みます。主にIf, Code, Wait, EmailSend, HttpRequestなどのノードを使用。 メール通知とデータAPIを備えた建設プロジェクトアラートの自動化
- •ターゲットAPIの認証情報が必要な場合あり
カテゴリー
{
"id": "tAZrn9nO8QUWfGQx",
"meta": {
"instanceId": "dd69efaf8212c74ad206700d104739d3329588a6f3f8381a46a481f34c9cc281",
"templateCredsSetupCompleted": true
},
"name": "Real-Time Competitive Construction Monitoring",
"tags": [],
"nodes": [
{
"id": "878dbf6e-dc80-457d-b212-03e98c69042f",
"name": "スケジュールトリガー",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
0,
0
],
"parameters": {
"rule": {
"interval": [
{}
]
}
},
"typeVersion": 1.1
},
{
"id": "bba4ec2c-854e-4c51-ba14-f19ab0af919c",
"name": "メールトリガー",
"type": "n8n-nodes-base.emailReadImap",
"position": [
0,
180
],
"parameters": {
"options": {}
},
"credentials": {
"imap": {
"id": "zTEGYssr7MSVeCs3",
"name": "IMAP-test"
}
},
"typeVersion": 2
},
{
"id": "46fdbb5a-478a-488d-ba1f-c752f1d708b9",
"name": "Check メール Subject",
"type": "n8n-nodes-base.if",
"position": [
220,
180
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "condition1",
"operator": {
"type": "string",
"operation": "contains"
},
"leftValue": "={{ $json.subject }}",
"rightValue": "Construction Alert Request"
}
]
}
},
"typeVersion": 2
},
{
"id": "af98d975-c83d-4cf6-b060-a33f8c5d3211",
"name": "Extract Location Info",
"type": "n8n-nodes-base.code",
"position": [
440,
80
],
"parameters": {
"jsCode": "// Extract area/location from email body\nconst emailBody = $input.first().json.text || $input.first().json.html;\nconst lines = emailBody.split('\\n');\n\nlet area = '';\nlet city = '';\nlet state = '';\nlet zipcode = '';\n\n// Look for area information in email\nfor (const line of lines) {\n if (line.toLowerCase().includes('area:') || line.toLowerCase().includes('location:')) {\n area = line.split(':')[1]?.trim() || '';\n }\n if (line.toLowerCase().includes('city:')) {\n city = line.split(':')[1]?.trim() || '';\n }\n if (line.toLowerCase().includes('state:')) {\n state = line.split(':')[1]?.trim() || '';\n }\n if (line.toLowerCase().includes('zip:') || line.toLowerCase().includes('zipcode:')) {\n zipcode = line.split(':')[1]?.trim() || '';\n }\n}\n\n// If no structured data found, try to extract from general text\nif (!area && !city) {\n const addressRegex = /([A-Za-z\\s]+),\\s*([A-Z]{2})\\s*(\\d{5})?/;\n const match = emailBody.match(addressRegex);\n if (match) {\n city = match[1];\n state = match[2];\n zipcode = match[3] || '';\n }\n}\n\nreturn {\n json: {\n searchArea: area || city,\n city: city,\n state: state,\n zipcode: zipcode,\n originalEmail: $input.first().json,\n searchQuery: `${area || city} ${state} construction permits`.trim()\n }\n};"
},
"typeVersion": 2
},
{
"id": "85f1df36-93ce-4895-bbde-022ebe40a1e7",
"name": "Search Government Data",
"type": "n8n-nodes-base.httpRequest",
"position": [
660,
0
],
"parameters": {
"url": "https://api.usa.gov/jobs/search.json",
"options": {},
"sendQuery": true,
"authentication": "genericCredentialType",
"genericAuthType": "httpQueryAuth",
"queryParameters": {
"parameters": [
{
"name": "keyword",
"value": "construction permit"
},
{
"name": "location_name",
"value": "={{ $json.searchArea }}"
},
{
"name": "size",
"value": "20"
}
]
}
},
"credentials": {
"httpQueryAuth": {
"id": "xA2e6hA40RZ8bzrI",
"name": "Query Auth account - test"
}
},
"typeVersion": 4.1
},
{
"id": "acc6341d-273f-4534-afb7-27771759a1df",
"name": "Search Construction Sites",
"type": "n8n-nodes-base.httpRequest",
"position": [
660,
160
],
"parameters": {
"url": "https://www.construction.com/api/search",
"options": {
"timeout": 10000
},
"sendQuery": true,
"sendHeaders": true,
"queryParameters": {
"parameters": [
{
"name": "q",
"value": "={{ $json.searchArea }} construction projects"
},
{
"name": "type",
"value": "projects"
},
{
"name": "limit",
"value": "15"
}
]
},
"headerParameters": {
"parameters": [
{
"name": "User-Agent",
"value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
},
{
"name": "Accept",
"value": "application/json"
}
]
}
},
"typeVersion": 4.1
},
{
"id": "f8ca860e-b794-4749-9fa9-bb340e955845",
"name": "Process Construction Data",
"type": "n8n-nodes-base.code",
"position": [
900,
40
],
"parameters": {
"jsCode": "const governmentData = $input.all()[0]?.json?.results || [];\nconst constructionData = $input.all()[1]?.json?.projects || [];\nconst searchInfo = $('Extract Location Info').first().json;\n\n// Process government construction data\nconst govProjects = governmentData.map(item => ({\n title: item.position_title || 'Government Construction Project',\n location: item.locations?.[0] || searchInfo.searchArea,\n description: item.job_summary || 'No description available',\n source: 'Government Database',\n url: item.url || '#',\n startDate: item.start_date || 'TBD',\n type: 'Public Project'\n}));\n\n// Process construction industry data (fallback mock data if API fails)\nlet constructionProjects = [];\nif (constructionData.length > 0) {\n constructionProjects = constructionData.map(item => ({\n title: item.name || item.title || 'Construction Project',\n location: item.location || searchInfo.searchArea,\n description: item.description || 'Commercial construction project',\n source: 'Construction Industry',\n url: item.url || '#',\n startDate: item.start_date || 'Q2 2024',\n type: item.type || 'Private Project'\n }));\n} else {\n // Fallback mock data for demo purposes\n constructionProjects = [\n {\n title: `New Commercial Complex - ${searchInfo.searchArea}`,\n location: searchInfo.searchArea,\n description: 'Mixed-use commercial and residential development',\n source: 'Local Planning Department',\n url: '#',\n startDate: 'March 2024',\n type: 'Mixed Development'\n },\n {\n title: `Office Building Construction - ${searchInfo.city}`,\n location: `${searchInfo.city}, ${searchInfo.state}`,\n description: '5-story office building with retail space',\n source: 'Building Permits',\n url: '#',\n startDate: 'April 2024',\n type: 'Commercial'\n }\n ];\n}\n\n// Combine all projects\nconst allProjects = [...govProjects, ...constructionProjects];\n\n// Filter for recent/upcoming projects\nconst recentProjects = allProjects.filter(project => {\n const startDate = new Date(project.startDate);\n const now = new Date();\n const threeMonthsFromNow = new Date(now.getTime() + (90 * 24 * 60 * 60 * 1000));\n \n return startDate >= now || project.startDate.includes('2024') || project.startDate === 'TBD';\n});\n\nreturn {\n json: {\n searchArea: searchInfo.searchArea,\n totalProjects: recentProjects.length,\n projects: recentProjects.slice(0, 10), // Limit to top 10\n searchQuery: searchInfo.searchQuery,\n generatedAt: new Date().toISOString(),\n originalEmail: searchInfo.originalEmail\n }\n};"
},
"typeVersion": 2
},
{
"id": "5e85f511-81ac-42bf-af01-f465531874bb",
"name": "Check if Projects Found",
"type": "n8n-nodes-base.if",
"position": [
1320,
80
],
"parameters": {
"options": {},
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "condition1",
"operator": {
"type": "number",
"operation": "gt"
},
"leftValue": "={{ $json.totalProjects }}",
"rightValue": 0
}
]
}
},
"typeVersion": 2
},
{
"id": "3a614463-2f2d-4d28-8761-9dcb4349b653",
"name": "Generate メール Report",
"type": "n8n-nodes-base.code",
"position": [
1540,
0
],
"parameters": {
"jsCode": "const data = $input.first().json;\nconst projects = data.projects;\n\n// Create HTML email content\nlet htmlContent = `\n<html>\n<head>\n <style>\n body { font-family: Arial, sans-serif; margin: 20px; }\n .header { background-color: #f4f4f4; padding: 20px; border-radius: 5px; }\n .project { border: 1px solid #ddd; margin: 10px 0; padding: 15px; border-radius: 5px; }\n .project-title { color: #333; font-weight: bold; font-size: 16px; }\n .project-meta { color: #666; font-size: 12px; margin: 5px 0; }\n .project-desc { margin: 10px 0; }\n .summary { background-color: #e8f4fd; padding: 15px; border-radius: 5px; margin: 20px 0; }\n </style>\n</head>\n<body>\n <div class=\"header\">\n <h2>🏗️ Construction Project Alert Report</h2>\n <p><strong>Search Area:</strong> ${data.searchArea}</p>\n <p><strong>Report Generated:</strong> ${new Date(data.generatedAt).toLocaleString()}</p>\n </div>\n \n <div class=\"summary\">\n <h3>📊 Summary</h3>\n <p><strong>Total Projects Found:</strong> ${data.totalProjects}</p>\n <p><strong>Search Query:</strong> ${data.searchQuery}</p>\n </div>\n \n <h3>🔍 Upcoming Construction Projects</h3>\n`;\n\nif (projects.length === 0) {\n htmlContent += '<p>No upcoming construction projects found in the specified area.</p>';\n} else {\n projects.forEach((project, index) => {\n htmlContent += `\n <div class=\"project\">\n <div class=\"project-title\">${project.title}</div>\n <div class=\"project-meta\">\n 📍 Location: ${project.location} | \n 📅 Start Date: ${project.startDate} | \n 🏢 Type: ${project.type}\n </div>\n <div class=\"project-desc\">\n <strong>Description:</strong> ${project.description}\n </div>\n <div class=\"project-meta\">\n <strong>Source:</strong> ${project.source}\n </div>\n </div>\n `;\n });\n}\n\nhtmlContent += `\n <div style=\"margin-top: 30px; padding: 15px; background-color: #f9f9f9; border-radius: 5px;\">\n <h4>💡 Next Steps</h4>\n <ul>\n <li>Review each project for potential competition</li>\n <li>Contact project owners for partnership opportunities</li>\n <li>Monitor progress and timeline changes</li>\n <li>Update your competitive analysis</li>\n </ul>\n </div>\n \n <p style=\"margin-top: 30px; color: #666; font-size: 12px;\">\n This report was automatically generated by your Construction Alert System.<br>\n To modify your alert preferences, reply to this email with your requirements.\n </p>\n</body>\n</html>\n`;\n\n// Create plain text version\nlet textContent = `Construction Project Alert Report\\n\\n`;\ntextContent += `Search Area: ${data.searchArea}\\n`;\ntextContent += `Total Projects Found: ${data.totalProjects}\\n`;\ntextContent += `Report Generated: ${new Date(data.generatedAt).toLocaleString()}\\n\\n`;\n\nif (projects.length === 0) {\n textContent += 'No upcoming construction projects found in the specified area.\\n';\n} else {\n textContent += 'UPCOMING CONSTRUCTION PROJECTS:\\n';\n textContent += '=' .repeat(40) + '\\n\\n';\n \n projects.forEach((project, index) => {\n textContent += `${index + 1}. ${project.title}\\n`;\n textContent += ` Location: ${project.location}\\n`;\n textContent += ` Start Date: ${project.startDate}\\n`;\n textContent += ` Type: ${project.type}\\n`;\n textContent += ` Description: ${project.description}\\n`;\n textContent += ` Source: ${project.source}\\n\\n`;\n });\n}\n\nreturn {\n json: {\n subject: `🏗️ Construction Alert: ${data.totalProjects} Projects Found in ${data.searchArea}`,\n htmlContent: htmlContent,\n textContent: textContent,\n recipientEmail: data.originalEmail.from,\n searchArea: data.searchArea,\n projectCount: data.totalProjects\n }\n};"
},
"typeVersion": 2
},
{
"id": "4782972d-6b57-4faf-9ce1-cedbee42ecff",
"name": "Send Alert メール",
"type": "n8n-nodes-base.emailSend",
"position": [
1760,
0
],
"webhookId": "9dae36d2-91a9-4ef4-90ae-60754055afd2",
"parameters": {
"html": "={{ $json.htmlContent }}",
"options": {},
"subject": "={{ $json.subject }}",
"toEmail": "={{ $json.recipientEmail }}",
"fromEmail": "alerts@yourcompany.com"
},
"credentials": {
"smtp": {
"id": "G1kyF8cSWTZ4vouN",
"name": "SMTP -test"
}
},
"typeVersion": 2.1
},
{
"id": "49d55c27-73f1-4436-99f9-f0e4ff2cf8ac",
"name": "Send No Results メール",
"type": "n8n-nodes-base.emailSend",
"position": [
1540,
200
],
"webhookId": "5375f687-193e-403e-a599-bbba10c97977",
"parameters": {
"text": "No upcoming construction projects were found for the requested area: {{ $('Extract Location Info').first().json.searchArea }}\\n\\nSearch was triggered at: {{ new Date().toLocaleString() }}\\n\\nOriginal request from: {{ $('Extract Location Info').first().json.originalEmail.from }}",
"options": {},
"subject": "No Construction Projects Found",
"toEmail": "admin@yourcompany.com",
"fromEmail": "alerts@yourcompany.com",
"emailFormat": "text"
},
"credentials": {
"smtp": {
"id": "G1kyF8cSWTZ4vouN",
"name": "SMTP -test"
}
},
"typeVersion": 2.1
},
{
"id": "9f9e205e-a6c6-4bf0-b25b-8d608eabc294",
"name": "待機 For Data",
"type": "n8n-nodes-base.wait",
"position": [
1120,
40
],
"webhookId": "fc75279b-7f48-421a-8222-b57f48dc06e2",
"parameters": {},
"typeVersion": 1.1
},
{
"id": "e5e98309-33a4-4b60-9cd6-f51925d77d7c",
"name": "付箋",
"type": "n8n-nodes-base.stickyNote",
"position": [
220,
-360
],
"parameters": {
"width": 860,
"height": 300,
"content": "\n## **How it works**\n* **Email Trigger** - Detects new email requests with \"Construction Alert Request\" in the subject line\n* **Check Email Subject** - Validates that the email contains the correct trigger phrase\n* **Extract Location Info** - Parses the email body to extract area, city, state, and zip code information\n* **Search Government Data** - Queries government databases for public construction projects and permits\n* **Search Construction Sites** - Searches construction industry databases for private projects\n* **Process Construction Data** - Combines and filters results from both sources, removing duplicates\n* **Wait For Data** - Wait for Combines and filters results\n* **Check If Projects Found** - Determines whether to send a results report or no-results notification\n* **Generate Email Report** - Creates a professional HTML email with project details and summaries\n* **Send Alert Email** - Delivers the construction project report to the requester\n* **Send No Results Email** - Notifies when no projects are found in the specified area\n\nThe workflow also includes a **Schedule Trigger** that can run automatically on weekdays at 9 AM for regular monitoring."
},
"typeVersion": 1
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "5e298be6-7660-412d-b5bb-15136626b35d",
"connections": {
"Email Trigger": {
"main": [
[
{
"node": "Check Email Subject",
"type": "main",
"index": 0
}
]
]
},
"Wait For Data": {
"main": [
[
{
"node": "5e85f511-81ac-42bf-af01-f465531874bb",
"type": "main",
"index": 0
}
]
]
},
"Schedule Trigger": {
"main": [
[
{
"node": "af98d975-c83d-4cf6-b060-a33f8c5d3211",
"type": "main",
"index": 0
}
]
]
},
"Check Email Subject": {
"main": [
[
{
"node": "af98d975-c83d-4cf6-b060-a33f8c5d3211",
"type": "main",
"index": 0
}
]
]
},
"af98d975-c83d-4cf6-b060-a33f8c5d3211": {
"main": [
[
{
"node": "85f1df36-93ce-4895-bbde-022ebe40a1e7",
"type": "main",
"index": 0
},
{
"node": "acc6341d-273f-4534-afb7-27771759a1df",
"type": "main",
"index": 0
}
]
]
},
"Generate Email Report": {
"main": [
[
{
"node": "Send Alert Email",
"type": "main",
"index": 0
}
]
]
},
"85f1df36-93ce-4895-bbde-022ebe40a1e7": {
"main": [
[
{
"node": "f8ca860e-b794-4749-9fa9-bb340e955845",
"type": "main",
"index": 0
}
]
]
},
"5e85f511-81ac-42bf-af01-f465531874bb": {
"main": [
[
{
"node": "Generate Email Report",
"type": "main",
"index": 0
}
],
[
{
"node": "Send No Results Email",
"type": "main",
"index": 0
}
]
]
},
"f8ca860e-b794-4749-9fa9-bb340e955845": {
"main": [
[
{
"node": "Wait For Data",
"type": "main",
"index": 0
}
]
]
},
"acc6341d-273f-4534-afb7-27771759a1df": {
"main": [
[
{
"node": "f8ca860e-b794-4749-9fa9-bb340e955845",
"type": "main",
"index": 0
}
]
]
}
}
}このワークフローの使い方は?
上記のJSON設定コードをコピーし、n8nインスタンスで新しいワークフローを作成して「JSONからインポート」を選択、設定を貼り付けて認証情報を必要に応じて変更してください。
このワークフローはどんな場面に適していますか?
中級 - 市場調査
有料ですか?
このワークフローは完全無料です。ただし、ワークフローで使用するサードパーティサービス(OpenAI APIなど)は別途料金が発生する場合があります。
関連ワークフロー
Oneclick AI Squad
@oneclick-aiThe AI Squad Initiative is a pioneering effort to build, automate and scale AI-powered workflows using n8n.io. Our mission is to help individuals and businesses integrate AI agents seamlessly into their daily operations from automating tasks and enhancing productivity to creating innovative, intelligent solutions. We design modular, reusable AI workflow templates that empower creators, developers and teams to supercharge their automation with minimal effort and maximum impact.
このワークフローを共有