Surveillance en temps réel de la construction concurrentielle
Ceci est unMarket Researchworkflow d'automatisation du domainecontenant 13 nœuds.Utilise principalement des nœuds comme If, Code, Wait, EmailSend, HttpRequest. Alertes automatisées pour les projets de construction, avec notifications par e-mail et API de données
- •Peut nécessiter les informations d'identification d'authentification de l'API cible
Nœuds utilisés (13)
Catégorie
{
"id": "tAZrn9nO8QUWfGQx",
"meta": {
"instanceId": "dd69efaf8212c74ad206700d104739d3329588a6f3f8381a46a481f34c9cc281",
"templateCredsSetupCompleted": true
},
"name": "Real-Time Competitive Construction Monitoring",
"tags": [],
"nodes": [
{
"id": "878dbf6e-dc80-457d-b212-03e98c69042f",
"name": "Déclencheur Planifié",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
0,
0
],
"parameters": {
"rule": {
"interval": [
{}
]
}
},
"typeVersion": 1.1
},
{
"id": "bba4ec2c-854e-4c51-ba14-f19ab0af919c",
"name": "Déclencheur E-mail",
"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": "Vérifier l'Objet de l'E-mail",
"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": "Extraire les Informations de Localisation",
"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": "Rechercher les Données Gouvernementales",
"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": "Rechercher les Chantiers de Construction",
"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": "Traiter les Données de Construction",
"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": "Vérifier si des Projets sont Trouvés",
"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": "Générer un Rapport E-mail",
"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": "Envoyer une E-mail d'Alerte",
"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": "Envoyer un E-mail Aucun Résultat",
"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": "Attendre les Données",
"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": "Note Adhésive",
"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": {
"bba4ec2c-854e-4c51-ba14-f19ab0af919c": {
"main": [
[
{
"node": "46fdbb5a-478a-488d-ba1f-c752f1d708b9",
"type": "main",
"index": 0
}
]
]
},
"9f9e205e-a6c6-4bf0-b25b-8d608eabc294": {
"main": [
[
{
"node": "5e85f511-81ac-42bf-af01-f465531874bb",
"type": "main",
"index": 0
}
]
]
},
"878dbf6e-dc80-457d-b212-03e98c69042f": {
"main": [
[
{
"node": "af98d975-c83d-4cf6-b060-a33f8c5d3211",
"type": "main",
"index": 0
}
]
]
},
"46fdbb5a-478a-488d-ba1f-c752f1d708b9": {
"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
}
]
]
},
"3a614463-2f2d-4d28-8761-9dcb4349b653": {
"main": [
[
{
"node": "4782972d-6b57-4faf-9ce1-cedbee42ecff",
"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": "3a614463-2f2d-4d28-8761-9dcb4349b653",
"type": "main",
"index": 0
}
],
[
{
"node": "49d55c27-73f1-4436-99f9-f0e4ff2cf8ac",
"type": "main",
"index": 0
}
]
]
},
"f8ca860e-b794-4749-9fa9-bb340e955845": {
"main": [
[
{
"node": "9f9e205e-a6c6-4bf0-b25b-8d608eabc294",
"type": "main",
"index": 0
}
]
]
},
"acc6341d-273f-4534-afb7-27771759a1df": {
"main": [
[
{
"node": "f8ca860e-b794-4749-9fa9-bb340e955845",
"type": "main",
"index": 0
}
]
]
}
}
}Comment utiliser ce workflow ?
Copiez le code de configuration JSON ci-dessus, créez un nouveau workflow dans votre instance n8n et sélectionnez "Importer depuis le JSON", collez la configuration et modifiez les paramètres d'authentification selon vos besoins.
Dans quelles scénarios ce workflow est-il adapté ?
Intermédiaire - Étude de marché
Est-ce payant ?
Ce workflow est entièrement gratuit et peut être utilisé directement. Veuillez noter que les services tiers utilisés dans le workflow (comme l'API OpenAI) peuvent nécessiter un paiement de votre part.
Workflows recommandés
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.
Partager ce workflow