{
  "name": "02b — Qualification Gate",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "2-59/10 * * * *"
            }
          ]
        }
      },
      "id": "wf02b-0001",
      "name": "Every 10 Min (+2 offset)",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.1,
      "position": [
        240,
        300
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT * FROM leads.leads WHERE state = 'enriched' ORDER BY updated_at ASC LIMIT 20",
        "additionalFields": {}
      },
      "id": "wf02b-0002",
      "name": "Fetch Enriched Leads",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        460,
        300
      ]
    },
    {
      "parameters": {
        "batchSize": 1,
        "options": {}
      },
      "id": "wf02b-0003",
      "name": "Split Leads",
      "type": "n8n-nodes-base.splitInBatches",
      "typeVersion": 3,
      "position": [
        680,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "const l = $json;\n\n// English friendliness — fail-closed, 'ambiguous' = fail\nconst english_pass = (\n  l.english_friendly_verdict === 'yes' ||\n  l.hreflang_en === true ||\n  l.html_lang_en === true ||\n  l.lang_switcher_en === true ||\n  (l.en_ratio != null && parseFloat(l.en_ratio) >= 0.6)\n);\n\nreturn [{ json: { ...l, english_pass } }];"
      },
      "id": "wf02b-0004",
      "name": "English Check",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        900,
        300
      ]
    },
    {
      "parameters": {
        "conditions": {
          "conditions": [
            {
              "id": "en-pass",
              "leftValue": "={{ $json.english_pass }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "equal"
              }
            }
          ],
          "combinator": "and"
        }
      },
      "id": "wf02b-0005",
      "name": "English Pass?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        1120,
        300
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "UPDATE leads.leads SET state = 'disqualified', disqualification_reason = 'not_english_friendly', updated_at = NOW() WHERE id = $1",
        "additionalFields": {
          "queryParams": "={{ JSON.stringify([$json.id]) }}"
        }
      },
      "id": "wf02b-0006",
      "name": "Disqualify: Not English",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        1340,
        160
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "http://playwright-worker:8000/size-score",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({\n  visible_team_size: $json.visible_team_size || null,\n  unique_internal_links: $json.unique_internal_links || 0,\n  operational_complexity_signals: $json.operational_complexity_signals || [],\n  whois_reg_date: $json.whois_reg_date || null\n}) }}",
        "options": {
          "timeout": 10000
        }
      },
      "id": "wf02b-0007",
      "name": "Compute Size Score",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1340,
        420
      ]
    },
    {
      "parameters": {
        "jsCode": "const sizeResult = $json;\nconst lead = $('English Check').item.json;\nreturn [{ json: { ...lead, business_size_score: sizeResult.score, size_breakdown: sizeResult.breakdown, size_pass: sizeResult.pass } }];"
      },
      "id": "wf02b-0008",
      "name": "Attach Size Score",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1560,
        420
      ]
    },
    {
      "parameters": {
        "conditions": {
          "conditions": [
            {
              "id": "size-pass",
              "leftValue": "={{ $json.size_pass }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "equal"
              }
            }
          ],
          "combinator": "and"
        }
      },
      "id": "wf02b-0009",
      "name": "Size Pass?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        1780,
        420
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "UPDATE leads.leads SET state = 'disqualified', disqualification_reason = 'too_small', business_size_score = $1, updated_at = NOW() WHERE id = $2",
        "additionalFields": {
          "queryParams": "={{ JSON.stringify([$json.business_size_score, $json.id]) }}"
        }
      },
      "id": "wf02b-0010",
      "name": "Disqualify: Too Small",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        2000,
        280
      ]
    },
    {
      "parameters": {
        "conditions": {
          "conditions": [
            {
              "id": "fit-check",
              "leftValue": "={{ $json.score_int }}",
              "rightValue": 4,
              "operator": {
                "type": "number",
                "operation": "gte"
              }
            }
          ],
          "combinator": "and"
        }
      },
      "id": "wf02b-0011",
      "name": "Fit Score >= 4?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        2000,
        560
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "UPDATE leads.leads SET state = 'disqualified', disqualification_reason = 'low_fit_score', business_size_score = $1, updated_at = NOW() WHERE id = $2",
        "additionalFields": {
          "queryParams": "={{ JSON.stringify([$json.business_size_score, $json.id]) }}"
        }
      },
      "id": "wf02b-0012",
      "name": "Disqualify: Low Fit",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        2220,
        420
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "UPDATE leads.leads SET state = 'qualified', business_size_score = $1, updated_at = NOW() WHERE id = $2",
        "additionalFields": {
          "queryParams": "={{ JSON.stringify([$json.business_size_score, $json.id]) }}"
        }
      },
      "id": "wf02b-0013",
      "name": "Set Qualified",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        2220,
        700
      ]
    }
  ],
  "connections": {
    "Every 10 Min (+2 offset)": {
      "main": [
        [
          {
            "node": "Fetch Enriched Leads",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Enriched Leads": {
      "main": [
        [
          {
            "node": "Split Leads",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Leads": {
      "main": [
        [],
        [
          {
            "node": "English Check",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "English Check": {
      "main": [
        [
          {
            "node": "English Pass?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "English Pass?": {
      "main": [
        [
          {
            "node": "Disqualify: Not English",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Compute Size Score",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Disqualify: Not English": {
      "main": [
        [
          {
            "node": "Split Leads",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Compute Size Score": {
      "main": [
        [
          {
            "node": "Attach Size Score",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Attach Size Score": {
      "main": [
        [
          {
            "node": "Size Pass?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Size Pass?": {
      "main": [
        [
          {
            "node": "Disqualify: Too Small",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Fit Score >= 4?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Disqualify: Too Small": {
      "main": [
        [
          {
            "node": "Split Leads",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fit Score >= 4?": {
      "main": [
        [
          {
            "node": "Disqualify: Low Fit",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Set Qualified",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Disqualify: Low Fit": {
      "main": [
        [
          {
            "node": "Split Leads",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Qualified": {
      "main": [
        [
          {
            "node": "Split Leads",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  }
}
