{
  "name": "Workflow B: Optimized User-Loan Matching",
  "nodes": [
    {
      "parameters": {
        "path": "user-loan-match",
        "options": {
          "responseData": true
        }
      },
      "name": "Trigger: New CSV Upload",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 1,
      "position": [
        -96,
        -16
      ],
      "id": "9207b73e-1a5f-4040-a164-644c7eb6ef5c"
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT\n    user_id,\n    monthly_income,\n    credit_score,\n    employment_status,\n    age\nFROM\n    users\nWHERE\n    users.created_at >= NOW() - INTERVAL '1 day';",
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        304,
        -144
      ],
      "id": "bf7e13f7-ad2c-4bd8-bd32-d76b46cd28d0",
      "name": "Execute a SQL query",
      "alwaysOutputData": true,
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT\n    id AS product_id,\n    product_name,\n    min_income,\n    min_credit_score,\n    max_amount\nFROM\n    loan_products;",
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        304,
        112
      ],
      "id": "ae8139e2-9469-4825-9df3-510d0347856a",
      "name": "Execute a SQL query1",
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "mode": "combine",
        "combineBy": "combineAll",
        "options": {}
      },
      "type": "n8n-nodes-base.merge",
      "typeVersion": 3.2,
      "position": [
        592,
        -16
      ],
      "id": "c34eb3cf-98e8-42da-a0ce-0c3021da3035",
      "name": "Merge",
      "alwaysOutputData": true
    },
    {
      "parameters": {
        "jsCode": "const matches = [];\n\n// The 'items' variable holds the array of data from the previous node (the Merge node)\nfor (const item of items) {\n  // Access data directly from the flat merged item structure\n  const user = {\n    user_id: item.json.user_id,\n    monthly_income: parseFloat(item.json.monthly_income),\n    credit_score: parseInt(item.json.credit_score)\n  };\n\n  const product = {\n    product_id: item.json.product_id,\n    // Use product-specific min_credit_score if available, otherwise default to a high standard (e.g., 700)\n    // If min_credit_score is null in the merged data, we'll use a hardcoded 700\n    product_min_credit_score: parseInt(item.json.min_credit_score) || 700, \n    max_amount: parseFloat(item.json.max_amount)\n  };\n\n  // --- Filtering Logic ---\n\n  // 1. Hardcoded Credit Score Filter: MUST be >= 700\n  if (user.credit_score < 700) {\n    continue; // User does not meet the minimum general credit score\n  }\n\n  // 2. Product-Specific Credit Score Filter (if min_credit_score was available)\n  if (user.credit_score < product.product_min_credit_score) {\n    continue; // User does not meet the product-specific credit score\n  }\n\n\n  // 3. Repayment Capacity Calculation (The 5-Year Rule)\n  const fixedExpense = 30000;\n  const repaymentMonths = 60; // 5 years\n\n  // Calculate Disposable Income after the fixed expense\n  const disposableIncome = user.monthly_income - fixedExpense;\n\n  // Calculate the required monthly payment if the user takes the MAX loan amount over 60 months\n  const maxMonthlyRepayment = product.max_amount / repaymentMonths;\n  \n  // Eligibility Condition: Disposable income must be able to cover the required monthly payment\n  const isEligibleForRepayment = disposableIncome >= maxMonthlyRepayment;\n\n  // --- Match Creation ---\n\n  if (isEligibleForRepayment) {\n    // Calculate Match Score based on the repayment surplus (buffer)\n    const bufferIncome = disposableIncome - maxMonthlyRepayment;\n    \n    // Base score (300 for meeting all criteria) + bonus points\n    const matchScore = 300 + Math.floor(bufferIncome / 500); \n\n    // Add the successful match to the output array\n    matches.push({\n      json: {\n        user_id: user.user_id,\n        product_id: product.product_id,\n        match_score: matchScore,\n        recommendation_strength: '5YR_REPAYMENT_CAPACITY_CHECK' \n      }\n    });\n  }\n}\n\nreturn matches;"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        800,
        -16
      ],
      "id": "ba42be2c-9461-42e0-bca0-e97fe20c3e7d",
      "name": "Code in JavaScript"
    },
    {
      "parameters": {
        "schema": {
          "__rl": true,
          "value": "public",
          "mode": "list",
          "cachedResultName": "public"
        },
        "table": {
          "__rl": true,
          "value": "user_loan_matches",
          "mode": "list",
          "cachedResultName": "user_loan_matches"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "is_notified": false,
            "match_score": "={{ $json.match_score }}",
            "user_id": "={{ $json.user_id }}",
            "product_id": "={{ $json.product_id }}",
            "recommendation_strength": "={{ $json.recommendation_strength }}"
          },
          "matchingColumns": [
            "id"
          ],
          "schema": [
            {
              "id": "id",
              "displayName": "id",
              "required": false,
              "defaultMatch": true,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "user_id",
              "displayName": "user_id",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "product_id",
              "displayName": "product_id",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "match_score",
              "displayName": "match_score",
              "required": true,
              "defaultMatch": false,
              "display": true,
              "type": "number",
              "canBeUsedToMatch": true
            },
            {
              "id": "is_notified",
              "displayName": "is_notified",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "boolean",
              "canBeUsedToMatch": true
            },
            {
              "id": "recommendation_strength",
              "displayName": "recommendation_strength",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "notified_at",
              "displayName": "notified_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "dateTime",
              "canBeUsedToMatch": true
            },
            {
              "id": "created_at",
              "displayName": "created_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "dateTime",
              "canBeUsedToMatch": true
            },
            {
              "id": "updated_at",
              "displayName": "updated_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "dateTime",
              "canBeUsedToMatch": true
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        1008,
        -16
      ],
      "id": "b4da7219-707d-4328-bfbf-229b0cb7e1f8",
      "name": "Insert rows in a table",
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "url": "http://localhost:5678/webhook-test/970dbc79-d5ad-4a1e-b40c-ff1db74bd830",
        "options": {
          "allowUnauthorizedCerts": true
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        1232,
        -16
      ],
      "id": "1ec8e6c0-0de8-466d-b07c-84b75c4c063d",
      "name": "HTTP Request",
      "executeOnce": true
    },
    {
      "parameters": {
        "workflowId": {
          "__rl": true,
          "value": "Z49V1WgZwnbNUmqK",
          "mode": "list",
          "cachedResultUrl": "/workflow/Z49V1WgZwnbNUmqK",
          "cachedResultName": "notification alert"
        },
        "workflowInputs": {
          "mappingMode": "defineBelow",
          "value": {},
          "matchingColumns": [],
          "schema": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": true
        },
        "options": {}
      },
      "type": "n8n-nodes-base.executeWorkflow",
      "typeVersion": 1.3,
      "position": [
        1088,
        160
      ],
      "id": "0decb02c-01c9-4241-9589-200a3b28ff24",
      "name": "Call 'notification alert'"
    }
  ],
  "connections": {
    "Trigger: New CSV Upload": {
      "main": [
        [
          {
            "node": "Execute a SQL query1",
            "type": "main",
            "index": 0
          },
          {
            "node": "Execute a SQL query",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Execute a SQL query": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Execute a SQL query1": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Merge": {
      "main": [
        [
          {
            "node": "Code in JavaScript",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code in JavaScript": {
      "main": [
        [
          {
            "node": "Insert rows in a table",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Insert rows in a table": {
      "main": [
        [
          {
            "node": "HTTP Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": true,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "207d91e7-04e7-41d6-a07b-6cfe3346e0f7",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "id": "MAO5dMccw8sbyww3",
  "tags": []
}