{
  "id": "tAZrn9nO8QUWfGQx",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Real-Time Competitive Construction Monitoring",
  "tags": [],
  "nodes": [
    {
      "id": "878dbf6e-dc80-457d-b212-03e98c69042f",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        0,
        0
      ],
      "parameters": {
        "rule": {
          "interval": [
            {}
          ]
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "bba4ec2c-854e-4c51-ba14-f19ab0af919c",
      "name": "Email Trigger",
      "type": "n8n-nodes-base.emailReadImap",
      "position": [
        0,
        180
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "imap": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "46fdbb5a-478a-488d-ba1f-c752f1d708b9",
      "name": "Check Email 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": {
          "name": "<your credential>"
        }
      },
      "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 Email 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>\ud83c\udfd7\ufe0f 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>\ud83d\udcca 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>\ud83d\udd0d 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        \ud83d\udccd Location: ${project.location} | \n        \ud83d\udcc5 Start Date: ${project.startDate} | \n        \ud83c\udfe2 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>\ud83d\udca1 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: `\ud83c\udfd7\ufe0f 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 Email",
      "type": "n8n-nodes-base.emailSend",
      "position": [
        1760,
        0
      ],
      "parameters": {
        "html": "={{ $json.htmlContent }}",
        "options": {},
        "subject": "={{ $json.subject }}",
        "toEmail": "={{ $json.recipientEmail }}",
        "fromEmail": "user@example.com"
      },
      "credentials": {
        "smtp": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "49d55c27-73f1-4436-99f9-f0e4ff2cf8ac",
      "name": "Send No Results Email",
      "type": "n8n-nodes-base.emailSend",
      "position": [
        1540,
        200
      ],
      "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": "user@example.com",
        "fromEmail": "user@example.com",
        "emailFormat": "text"
      },
      "credentials": {
        "smtp": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "9f9e205e-a6c6-4bf0-b25b-8d608eabc294",
      "name": "Wait For Data",
      "type": "n8n-nodes-base.wait",
      "position": [
        1120,
        40
      ],
      "parameters": {},
      "typeVersion": 1.1
    },
    {
      "id": "e5e98309-33a4-4b60-9cd6-f51925d77d7c",
      "name": "Sticky Note",
      "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,
  "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": "Check if Projects Found",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Extract Location Info",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Email Subject": {
      "main": [
        [
          {
            "node": "Extract Location Info",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Location Info": {
      "main": [
        [
          {
            "node": "Search Government Data",
            "type": "main",
            "index": 0
          },
          {
            "node": "Search Construction Sites",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Email Report": {
      "main": [
        [
          {
            "node": "Send Alert Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Search Government Data": {
      "main": [
        [
          {
            "node": "Process Construction Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check if Projects Found": {
      "main": [
        [
          {
            "node": "Generate Email Report",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Send No Results Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Process Construction Data": {
      "main": [
        [
          {
            "node": "Wait For Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Search Construction Sites": {
      "main": [
        [
          {
            "node": "Process Construction Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}