{
  "name": "Reed Job Ingestion",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours",
              "hoursInterval": 4
            }
          ]
        }
      },
      "id": "schedule-reed",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.3,
      "position": [
        -400,
        0
      ]
    },
    {
      "parameters": {
        "jsCode": "// Reed API: GET https://www.reed.co.uk/api/1.0/search\n// Auth: Basic auth with API key as username, empty password\n// Returns: results[] with jobId, jobTitle, employerName, locationName, salary*, jobUrl, expirationDate, date, jobDescription\nconst keywords = [\n  'software engineer typescript',\n  'frontend developer typescript react',\n  'fullstack developer nextjs',\n  'software developer node',\n  'implementation engineer saas',\n  'technical support engineer',\n];\nreturn keywords.map((kw, i) => ({ json: { keyword: kw, skip: 0, page: i } }));"
      },
      "id": "keywords-reed",
      "name": "Keywords",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -176,
        0
      ]
    },
    {
      "parameters": {
        "url": "https://www.reed.co.uk/api/1.0/search",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBasicAuth",
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "keywords",
              "value": "={{ $json.keyword }}"
            },
            {
              "name": "resultsToTake",
              "value": "100"
            },
            {
              "name": "resultsToSkip",
              "value": "0"
            },
            {
              "name": "fullTime",
              "value": "true"
            },
            {
              "name": "permanent",
              "value": "true"
            }
          ]
        },
        "options": {}
      },
      "id": "fetch-reed",
      "name": "Fetch Reed Jobs",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        48,
        0
      ],
      "credentials": {
        "httpBasicAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "function stripHtml(html) {\n  return (html || '').replace(/<[^>]*>/g, ' ').replace(/&amp;/g, '&').replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&nbsp;/g, ' ').replace(/&#39;/g, \"'\").replace(/&quot;/g, '\"').replace(/\\s+/g, ' ').trim();\n}\nconst jobs = $json.results || [];\nreturn jobs.map(j => ({\n  json: {\n    source: 'reed',\n    external_id: String(j.jobId ?? ''),\n    company: (j.employerName || '').trim(),\n    title: (j.jobTitle || '').trim(),\n    location: (j.locationName || '').trim(),\n    remote: (j.jobTitle + ' ' + (j.jobDescription || '')).toLowerCase().includes('remote') ? 'remote' : 'unknown',\n    url: j.jobUrl || '',\n    description: stripHtml(j.jobDescription || '').slice(0, 8000),\n    posted_at: j.date ? new Date(j.date).toISOString() : null,\n  }\n}));"
      },
      "id": "normalize-reed",
      "name": "Normalize",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        272,
        0
      ]
    },
    {
      "parameters": {
        "jsCode": "function simpleHash(str) {\n  let hash = 0;\n  for (let i = 0; i < str.length; i++) {\n    hash = ((hash << 5) - hash) + str.charCodeAt(i);\n    hash |= 0;\n  }\n  return Math.abs(hash).toString(16).padStart(8, '0');\n}\nreturn items.map(({ json }) => {\n  const base = [json.source, json.external_id, json.company, json.title, json.url].join('|');\n  return { json: { ...json, content_hash: simpleHash(base) } };\n});"
      },
      "id": "hash-reed",
      "name": "Hash",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        496,
        0
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://matchpilot-production-a08d.up.railway.app/api/ingest",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "source",
              "value": "={{ $json.source }}"
            },
            {
              "name": "external_id",
              "value": "={{ $json.external_id }}"
            },
            {
              "name": "company",
              "value": "={{ $json.company }}"
            },
            {
              "name": "title",
              "value": "={{ $json.title }}"
            },
            {
              "name": "location",
              "value": "={{ $json.location }}"
            },
            {
              "name": "remote",
              "value": "={{ $json.remote }}"
            },
            {
              "name": "url",
              "value": "={{ $json.url }}"
            },
            {
              "name": "description",
              "value": "={{ $json.description }}"
            },
            {
              "name": "posted_at",
              "value": "={{ $json.posted_at }}"
            },
            {
              "name": "content_hash",
              "value": "={{ $json.content_hash }}"
            }
          ]
        },
        "options": {
          "timeout": 15000
        }
      },
      "id": "ingest-reed",
      "name": "Ingest",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        720,
        0
      ],
      "continueOnFail": true,
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "jsCode": "return Array.from({length: 50}, (_, i) => ({ json: { i } }));"
      },
      "id": "loop-reed",
      "name": "Loop 50",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        944,
        0
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://matchpilot-production-a08d.up.railway.app/api/worker/score",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "x-worker-secret",
              "value": "3eb2bf26e739c83044d5b6c7ea851c4e4c7e6f58afd401f267fa98f78445e6bf"
            }
          ]
        },
        "options": {
          "timeout": 60000
        }
      },
      "id": "worker-reed",
      "name": "Trigger Worker",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1168,
        0
      ],
      "continueOnFail": true,
      "onError": "continueRegularOutput"
    }
  ],
  "connections": {
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Keywords",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Keywords": {
      "main": [
        [
          {
            "node": "Fetch Reed Jobs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Reed Jobs": {
      "main": [
        [
          {
            "node": "Normalize",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize": {
      "main": [
        [
          {
            "node": "Hash",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Hash": {
      "main": [
        [
          {
            "node": "Ingest",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Ingest": {
      "main": [
        [
          {
            "node": "Loop 50",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop 50": {
      "main": [
        [
          {
            "node": "Trigger Worker",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}