AutomationFlowsAI & RAG › Score and Route Job Candidates with Mistral, Gemini, Google Sheets, and Drive

Score and Route Job Candidates with Mistral, Gemini, Google Sheets, and Drive

ByMuhammad Huzaifa Abdulahad @huzaifaaaa on n8n.io

This workflow collects candidate applications via an n8n form, extracts resume text with Mistral AI, matches the candidate to an open role stored in Google Sheets and Google Docs, scores the fit using Google Gemini, and uploads the CV and an evaluation report to…

Event trigger★★★★★ complexityAI-powered35 nodesFormForm TriggerGoogle SheetsMistral AiGoogle DocsChain LlmOutput Parser StructuredGoogle Drive
AI & RAG Trigger: Event Nodes: 35 Complexity: ★★★★★ AI nodes: yes Added:
Score and Route Job Candidates with Mistral, Gemini, Google Sheets, and Drive — n8n workflow card showing Form, Form Trigger, Google Sheets integration

This workflow corresponds to n8n.io template #17705 — we link there as the canonical source.

This workflow follows the Chainllm → Form Trigger recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "id": "RRCOFwgOq4mwrcnk",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "AI-HR Auto-Candidate selection",
  "tags": [],
  "nodes": [
    {
      "id": "a277efb0-c7bc-46e4-ac8b-a6f7974f5f7b",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2160,
        1904
      ],
      "parameters": {
        "width": 480,
        "height": 896,
        "content": "## AI-HR Auto-Candidate selection\n\n### How it works\n\nTriggered by a candidate submitting an application form containing their resume.\\nExtracts resume text and queries matching roles from Google Sheets.\\nPresents candidates with interactive selection forms to choose the position they are applying for.\\nRetrieves the full job description from Google Docs and uses Google Gemini to evaluate the candidate's fit.\\nDecides whether to shortlist the candidate based on the structured AI response.\\nUploads both the resume and AI evaluation reports to Google Drive, then triggers automated selection or rejection emails via Gmail.\n\n### Setup steps\n\n- - [ ] Create and configure Google Gemini API credentials for the LLM chat model.\n- - [ ] Connect your Google Workspace account to enable Google Sheets and Google Docs nodes.\n- - [ ] Authorize Google Drive access to organize, save, and manage candidate portfolios.\n- - [ ] Set up Gmail credentials to automatically trigger candidate communications.\n- - [ ] Prepare your Google Sheet with active jobs and ensure Google Docs contain relevant Job Descriptions.\n\n### Customization\n\nAdjust the comparison prompt in the ConstructPrompt node to modify candidate evaluation guidelines or scoring metrics.\\nChange the email templates in Gmail nodes to match your brand's candidate experience guidelines."
      },
      "typeVersion": 1
    },
    {
      "id": "b8f3e304-f24e-4476-a9e4-7d5b0cc714ab",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1600,
        2256
      ],
      "parameters": {
        "color": 7,
        "width": 416,
        "height": 320,
        "content": "## Receive application and parse resume\n\nReceives candidate application through an interactive form and uses Mistral AI to convert the resume into plain text."
      },
      "typeVersion": 1
    },
    {
      "id": "802aa1eb-9a7f-4a71-b680-e82864caedd2",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1152,
        2288
      ],
      "parameters": {
        "color": 7,
        "width": 640,
        "height": 304,
        "content": "## Query and filter active jobs\n\nFetches active job openings from Google Sheets, filters them by department, and determines if matching roles are available."
      },
      "typeVersion": 1
    },
    {
      "id": "a950951b-86ac-4547-b2cc-e40e556fec20",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -480,
        2160
      ],
      "parameters": {
        "color": 7,
        "width": 416,
        "height": 512,
        "content": "## Interactive role selection\n\nPresents the candidate with a selection form of open positions, handles success feedback, or routes to an error page if no jobs are open."
      },
      "typeVersion": 1
    },
    {
      "id": "ea2e854f-64bf-4c63-98de-3e2df7c57d86",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -32,
        2160
      ],
      "parameters": {
        "color": 7,
        "width": 416,
        "height": 320,
        "content": "## Retrieve matching job description\n\nFilters active job descriptions by the chosen role and fetches the full requirements from Google Docs."
      },
      "typeVersion": 1
    },
    {
      "id": "4b7e5550-acf1-4885-9e7b-80c6c8219cdf",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        416,
        2160
      ],
      "parameters": {
        "color": 7,
        "width": 592,
        "height": 528,
        "content": "## Perform AI candidate evaluation\n\nBuilds a detailed comparison prompt and evaluates the candidate's resume against job requirements using Google Gemini AI, outputting structured results."
      },
      "typeVersion": 1
    },
    {
      "id": "2b87fe45-58aa-4c47-a6c9-c5b4bee205b1",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1040,
        2160
      ],
      "parameters": {
        "color": 7,
        "width": 416,
        "height": 320,
        "content": "## Evaluate candidate qualification\n\nConverts structured AI output into a file format and branches the execution path based on whether the candidate is shortlisted."
      },
      "typeVersion": 1
    },
    {
      "id": "361678a7-adc9-4d99-ba91-5b5433735d67",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1488,
        1904
      ],
      "parameters": {
        "color": 7,
        "width": 864,
        "height": 496,
        "content": "## Process shortlisted applicant\n\nPrepares directories, uploads resume and evaluation insights to Google Drive, and sends a selection email via Gmail."
      },
      "typeVersion": 1
    },
    {
      "id": "f96603c8-d03d-4337-8bd6-2621885b7533",
      "name": "Sticky Note8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1488,
        2432
      ],
      "parameters": {
        "color": 7,
        "width": 864,
        "height": 496,
        "content": "## Process rejected applicant\n\nPrepares rejection data, saves applicant profile and AI feedback to Google Drive, and sends a formal rejection email via Gmail."
      },
      "typeVersion": 1
    },
    {
      "id": "97f90581-9f7d-409e-98bf-da517ea6d0ce",
      "name": "Filter Job Description by Role",
      "type": "n8n-nodes-base.code",
      "position": [
        16,
        2320
      ],
      "parameters": {
        "jsCode": "const chosenTitle = $('Show Job Selection Form').first().json[\"jobTitle\"];\nconst department = $('When Application Submitted').first().json[\"Select Department\"];\n\nconst match = $('Filter Jobs by Department').first().json.jobs.find(job =>\n  job.Role === chosenTitle && job.Department === department\n);\n\nreturn [{ json: match || {} }];"
      },
      "typeVersion": 2
    },
    {
      "id": "8e4b1b29-2e8b-4d5d-9359-266e37ae3c45",
      "name": "Show Submission Success Page",
      "type": "n8n-nodes-base.form",
      "position": [
        -208,
        2320
      ],
      "parameters": {
        "options": {
          "customCss": ":root {\n\n\t/* =========================\n\t   TYPOGRAPHY\n\t========================= */\n\n\t--font-family: \"Inter\", \"Open Sans\", sans-serif;\n\n\t--font-weight-normal:400;\n\t--font-weight-bold:700;\n\n\n\t--font-size-body:15px;\n\t--font-size-label:13px;\n\t--font-size-header:36px;\n\t--font-size-paragraph:17px;\n\n\n\n\t/* =========================\n\t   COLORS\n\t========================= */\n\n\n\t--color-background:#070707;\n\n\n\t--color-card-bg:\n\t#111111;\n\n\n\t--color-card-border:\n\t#292929;\n\n\n\t--color-card-shadow:\n\trgba(0,0,0,.7);\n\n\n\n\t--color-header:\n\t#ffffff;\n\n\n\t--color-label:\n\t#d4d4d4;\n\n\n\t--color-html-text:\n\t#b5b5b5;\n\n\n\t--color-header-subtext:\n\t#999999;\n\n\n\n\t/* Accent */\n\n\t--color-submit-btn-bg:\n\n\tlinear-gradient(\n\t\t135deg,\n\t\t#ffe259,\n\t\t#fbbf24\n\t);\n\n\n\t--color-submit-btn-text:\n\t#111;\n\n\n\n\t--color-link:\n\t#facc15;\n\n\n\t--color-focus-border:\n\t#facc15;\n\n\n\n\t/* =========================\n\t   SHAPES\n\t========================= */\n\n\n\t--border-radius-card:24px;\n\n\t--card-border-radius:24px;\n\n\n\t--border-radius-input:14px;\n\n\n\n\t/* =========================\n\t   SPACING\n\t========================= */\n\n\n\t--padding-container-top:90px;\n\n\t--padding-card:50px;\n\n\n\t--card-padding:50px;\n\n\n\n\t--margin-bottom-card:25px;\n\n\n\n\t/* =========================\n\t   DIMENSIONS\n\t========================= */\n\n\n\t--container-width:560px;\n\n\n\t--submit-btn-height:60px;\n\n\n\n\t--box-shadow-card:\n\n\t0 40px 100px rgba(0,0,0,.75);\n\n\n\n}\n\n\n\n/* =================================\n   PAGE BACKGROUND\n================================= */\n\n\nbody {\n\n\n\tbackground:\n\n\n\tradial-gradient(\n\t\tcircle at top,\n\t\trgba(250,204,21,.18),\n\t\ttransparent 35%\n\t),\n\n\n\tradial-gradient(\n\t\tcircle at bottom right,\n\t\trgba(250,204,21,.08),\n\t\ttransparent 40%\n\t),\n\n\n\t#070707;\n\n\n}\n\n\n\n/* =================================\n   COMPLETION CARD\n================================= */\n\n\nform,\n.n8n-form {\n\n\n\tbackground:\n\n\tlinear-gradient(\n\t\t145deg,\n\t\trgba(255,255,255,.06),\n\t\ttransparent\n\t),\n\t#111111;\n\n\n\n\tborder:\n\n\t1px solid #2b2b2b;\n\n\n\n\tborder-radius:\n\n\t24px;\n\n\n\n\tbox-shadow:\n\n\t0 40px 100px rgba(0,0,0,.75);\n\n\n\n\tbackdrop-filter:\n\n\tblur(20px);\n\n\n\n\tposition:relative;\n\n\n\n}\n\n\n\n/* premium gold line */\n\nform::before,\n.n8n-form::before {\n\n\n\tcontent:\"\";\n\n\n\tposition:absolute;\n\n\n\ttop:0;\n\n\n\tleft:15%;\n\n\n\tright:15%;\n\n\n\theight:3px;\n\n\n\n\tbackground:\n\n\tlinear-gradient(\n\t\t90deg,\n\t\ttransparent,\n\t\t#facc15,\n\t\ttransparent\n\t);\n\n\n\n}\n\n\n\n/* =================================\n   TITLE\n================================= */\n\n\nh1 {\n\n\n\tcolor:white !important;\n\n\n\tfont-size:36px !important;\n\n\n\tfont-weight:800;\n\n\n\n\tletter-spacing:-1px;\n\n\n\n}\n\n\n\nh1::first-letter {\n\n\n\tcolor:#facc15;\n\n\n}\n\n\n\n\n/* =================================\n   MESSAGE TEXT\n================================= */\n\n\np {\n\n\n\tcolor:#bdbdbd;\n\n\n\n\tfont-size:17px;\n\n\n\n\tline-height:1.7;\n\n\n}\n\n\n\n\n/* =================================\n   SUCCESS ICON / ELEMENTS\n================================= */\n\n\nsvg {\n\n\n\tcolor:#facc15 !important;\n\n\n}\n\n\n\n/* =================================\n   BUTTONS (if shown)\n================================= */\n\n\nbutton {\n\n\n\tbackground:\n\n\tlinear-gradient(\n\t\t135deg,\n\t\t#ffe259,\n\t\t#fbbf24\n\t);\n\n\n\n\tcolor:#111;\n\n\n\n\tborder:none;\n\n\n\n\tborder-radius:14px;\n\n\n\n\theight:60px;\n\n\n\n\tfont-size:15px;\n\n\n\n\tfont-weight:800;\n\n\n\n\ttext-transform:uppercase;\n\n\n\n\tbox-shadow:\n\n\n\t0 15px 35px rgba(250,204,21,.3);\n\n\n\n\ttransition:.25s;\n\n\n\n}\n\n\n\nbutton:hover {\n\n\n\ttransform:\n\n\ttranslateY(-3px);\n\n\n\n\tbox-shadow:\n\n\n\t0 25px 50px rgba(250,204,21,.45);\n\n\n}\n\n\n\n/* =================================\n   LINKS\n================================= */\n\n\na {\n\n\n\tcolor:#facc15;\n\n\n\tfont-weight:600;\n\n\n}\n\n\n\n/* =================================\n   MOBILE\n================================= */\n\n\n@media(max-width:640px){\n\n\n\t:root{\n\n\n\t--padding-card:28px;\n\n\t--font-size-header:28px;\n\n\n\t}\n\n\n\n}"
        },
        "operation": "completion",
        "completionTitle": "Thank you for applying!",
        "completionMessage": "Your submission has been received. Our team will review your application and get in touch with you soon."
      },
      "typeVersion": 2.5
    },
    {
      "id": "23734310-0a8e-4506-a9ba-f50122fd8552",
      "name": "Check If Jobs Available",
      "type": "n8n-nodes-base.if",
      "position": [
        -656,
        2416
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "b16e44b1-b332-4e5e-9538-feb54e18e1a7",
              "operator": {
                "type": "number",
                "operation": "gt"
              },
              "leftValue": "={{ $json.jobCount }}",
              "rightValue": 0
            }
          ]
        }
      },
      "executeOnce": false,
      "typeVersion": 2.3,
      "alwaysOutputData": false
    },
    {
      "id": "b904a787-fba2-4fef-9189-8b8f7b50c3d6",
      "name": "Filter Jobs by Department",
      "type": "n8n-nodes-base.code",
      "position": [
        -880,
        2416
      ],
      "parameters": {
        "jsCode": "const department = $('When Application Submitted').first().json[\"Select Department\"];\n\nconst filtered = $input.all().filter(item =>\n  item.json.Department === department && item.json.Status === 'OPEN'\n);\n\nreturn [{\n  json: {\n    jobs: filtered.map(item => item.json),\n    jobCount: filtered.length\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "06e2d171-4b53-486f-9ca8-d3a855fc8dd8",
      "name": "Show Job Selection Form",
      "type": "n8n-nodes-base.form",
      "position": [
        -432,
        2320
      ],
      "parameters": {
        "options": {
          "customCss": ":root {\n\n\t/* =========================\n\t   TYPOGRAPHY\n\t========================= */\n\n\t--font-family: \"Inter\", \"Space Grotesk\", \"Open Sans\", sans-serif;\n\n\t--font-weight-normal: 400;\n\t--font-weight-bold: 700;\n\n\t--font-size-body: 14px;\n\t--font-size-label: 13px;\n\t--font-size-test-notice: 12px;\n\t--font-size-input: 15px;\n\t--font-size-header: 34px;\n\t--font-size-paragraph: 15px;\n\t--font-size-link: 13px;\n\t--font-size-error: 12px;\n\n\t--font-size-html-h1:32px;\n\t--font-size-html-h2:24px;\n\t--font-size-html-h3:18px;\n\t--font-size-html-h4:16px;\n\t--font-size-html-h5:14px;\n\t--font-size-html-h6:12px;\n\n\n\n\t/* =========================\n\t   COLORS\n\t========================= */\n\n\n\t--color-background:#070707;\n\n\n\t/* Card */\n\n\t--color-card-bg:\n\trgba(18,18,18,.88);\n\n\n\t--color-card-border:\n\t#292929;\n\n\n\t--color-card-shadow:\n\trgba(0,0,0,.65);\n\n\n\n\t/* Text */\n\n\n\t--color-header:\n\t#ffffff;\n\n\n\t--color-label:\n\t#c8c8c8;\n\n\n\t--color-html-text:\n\t#b5b5b5;\n\n\n\t--color-header-subtext:\n\t#8f8f8f;\n\n\n\n\t/* Inputs */\n\n\n\t--color-input-border:\n\t#333333;\n\n\n\t--color-input-text:\n\t#ffffff;\n\n\n\t--color-focus-border:\n\t#facc15;\n\n\n\n\t/* Button */\n\n\n\t--color-submit-btn-bg:\n\n\tlinear-gradient(\n\t\t135deg,\n\t\t#ffe259,\n\t\t#fbbf24\n\t);\n\n\n\t--color-submit-btn-text:\n\t#111111;\n\n\n\n\t/* Errors */\n\n\n\t--color-error:#ef4444;\n\n\t--color-required:#facc15;\n\n\n\t--color-link:#facc15;\n\n\t--color-html-link:#facc15;\n\n\n\n\t/* =========================\n\t   SHAPES\n\t========================= */\n\n\n\t--border-radius-card:24px;\n\n\t--card-border-radius:24px;\n\n\t--border-radius-input:12px;\n\n\t--border-radius-clear-btn:50%;\n\n\n\n\t/* =========================\n\t   SPACING\n\t========================= */\n\n\n\t--padding-container-top:70px;\n\n\t--padding-card:42px;\n\n\t--card-padding:42px;\n\n\t--padding-test-notice-vertical:16px;\n\n\t--padding-test-notice-horizontal:24px;\n\n\t--margin-bottom-card:24px;\n\n\t--card-margin-bottom:24px;\n\n\t--padding-form-input:16px;\n\n\n\n\t/* =========================\n\t   DIMENSIONS\n\t========================= */\n\n\n\t--container-width:560px;\n\n\t--submit-btn-height:58px;\n\n\t--checkbox-size:19px;\n\n\n\n\t/* =========================\n\t   EFFECTS\n\t========================= */\n\n\n\t--box-shadow-card:\n\n\t0 35px 90px rgba(0,0,0,.7);\n\n\n\n\t--opacity-placeholder:.45;\n\n}\n\n\n\n/* =================================\n   BACKGROUND\n================================= */\n\n\nbody {\n\n\n\tbackground:\n\n\n\tradial-gradient(\n\t\tcircle at top left,\n\t\trgba(250,204,21,.14),\n\t\ttransparent 35%\n\t),\n\n\n\tradial-gradient(\n\t\tcircle at bottom right,\n\t\trgba(250,204,21,.08),\n\t\ttransparent 40%\n\t),\n\n\n\t#070707;\n\n}\n\n\n\n/* =================================\n   FORM CARD\n================================= */\n\n\nform {\n\n\n\tbackground:\n\n\tlinear-gradient(\n\t\t145deg,\n\t\trgba(255,255,255,.06),\n\t\ttransparent\n\t),\n\tvar(--color-card-bg);\n\n\n\n\tborder:\n\n\t1px solid #2c2c2c;\n\n\n\tbox-shadow:\n\n\tvar(--box-shadow-card),\n\tinset 0 1px rgba(255,255,255,.05);\n\n\n\n\tbackdrop-filter:\n\n\tblur(20px);\n\n\n\n\tposition:relative;\n\n}\n\n\n\n\n/* premium yellow top glow */\n\n\nform::before {\n\n\n\tcontent:\"\";\n\n\n\tposition:absolute;\n\n\ttop:0;\n\n\tleft:15%;\n\n\tright:15%;\n\n\theight:2px;\n\n\n\tbackground:\n\n\tlinear-gradient(\n\t\t90deg,\n\t\ttransparent,\n\t\t#facc15,\n\t\ttransparent\n\t);\n\n\n}\n\n\n\n/* =================================\n   HEADINGS\n================================= */\n\n\nh1,\nh2,\nh3 {\n\n\n\tcolor:#ffffff;\n\n\n\tfont-weight:700;\n\n\n\tletter-spacing:-.8px;\n\n\n}\n\n\n\n\n/* yellow accent */\n\n\nh1::first-letter {\n\n\n\tcolor:#facc15;\n\n}\n\n\n\n/* =================================\n   LABELS\n================================= */\n\n\nlabel {\n\n\n\tcolor:#d4d4d4;\n\n\n\tfont-weight:600;\n\n\n\ttext-transform:uppercase;\n\n\n\tfont-size:12px;\n\n\n\tletter-spacing:1px;\n\n\n}\n\n\n\n\n/* =================================\n   INPUTS\n================================= */\n\n\ninput,\ntextarea,\nselect {\n\n\n\tbackground:\n\n\t#111111 !important;\n\n\n\tcolor:\n\n\t#ffffff !important;\n\n\n\tborder:\n\n\t1px solid #333333;\n\n\n\tborder-radius:\n\n\t12px;\n\n\n\n\ttransition:\n\n\tall .25s ease;\n\n\n\n}\n\n\n\ninput::placeholder,\ntextarea::placeholder {\n\n\n\tcolor:#777;\n\n\n}\n\n\n\ninput:hover,\ntextarea:hover,\nselect:hover {\n\n\n\tborder-color:#555;\n\n\n}\n\n\n\n\ninput:focus,\ntextarea:focus,\nselect:focus {\n\n\n\tborder-color:#facc15;\n\n\n\tbox-shadow:\n\n\t0 0 0 4px rgba(250,204,21,.15);\n\n\n}\n\n\n\n\n/* =================================\n   FILE UPLOAD\n================================= */\n\n\ninput[type=\"file\"] {\n\n\n\tbackground:#111111 !important;\n\n\n\tborder:\n\n\t1px dashed #555;\n\n\n\n\tpadding:\n\n\t14px;\n\n\n\n\tcursor:pointer;\n\n\n\n\tcolor:#aaa !important;\n\n\n}\n\n\n\ninput[type=\"file\"]:hover {\n\n\n\tborder-color:#facc15;\n\n\n}\n\n\n\n\ninput[type=\"file\"]::file-selector-button {\n\n\n\tbackground:\n\n\tlinear-gradient(\n\t\t135deg,\n\t\t#ffe259,\n\t\t#fbbf24\n\t);\n\n\n\n\tcolor:#111;\n\n\n\n\tborder:none;\n\n\n\tborder-radius:10px;\n\n\n\tpadding:10px 18px;\n\n\n\tmargin-right:14px;\n\n\n\tfont-weight:700;\n\n\n\tcursor:pointer;\n\n\n\ttransition:.2s;\n\n\n\n}\n\n\n\ninput[type=\"file\"]::file-selector-button:hover {\n\n\n\ttransform:\n\n\ttranslateY(-2px);\n\n\n\n\tbox-shadow:\n\n\t0 8px 20px rgba(250,204,21,.35);\n\n\n}\n\n\n\n\n\n/* =================================\n   BUTTON\n================================= */\n\n\nbutton {\n\n\n\theight:\n\n\t58px;\n\n\n\tborder-radius:\n\n\t14px;\n\n\n\tbackground:\n\n\tlinear-gradient(\n\t\t135deg,\n\t\t#ffe259,\n\t\t#fbbf24\n\t);\n\n\n\n\tcolor:#111;\n\n\n\tfont-size:15px;\n\n\n\tfont-weight:800;\n\n\n\tletter-spacing:.8px;\n\n\n\ttext-transform:uppercase;\n\n\n\n\tborder:none;\n\n\n\n\tbox-shadow:\n\n\n\t0 15px 35px rgba(250,204,21,.25);\n\n\n\n\ttransition:\n\n\tall .25s ease;\n\n\n\n}\n\n\n\nbutton:hover {\n\n\n\ttransform:\n\n\ttranslateY(-3px);\n\n\n\n\tbox-shadow:\n\n\n\t0 20px 45px rgba(250,204,21,.4);\n\n\n}\n\n\n\nbutton:active {\n\n\n\ttransform:\n\n\ttranslateY(1px);\n\n\n}\n\n\n\n/* =================================\n   LINKS\n================================= */\n\n\na {\n\n\n\tcolor:#facc15;\n\n\n\tfont-weight:600;\n\n\n}\n\n\n\n/* =================================\n   CHECKBOX\n================================= */\n\n\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n\n\n\taccent-color:#facc15;\n\n\n}\n\n\n\n/* =================================\n   MOBILE\n================================= */\n\n\n@media(max-width:640px){\n\n\n\t:root{\n\n\n\t--padding-card:24px;\n\n\t--card-padding:24px;\n\n\t--font-size-header:26px;\n\n\n\t}\n\n\n}"
        },
        "defineForm": "json",
        "jsonOutput": "={{ [\n  {\n    fieldLabel: \"Select the job role you are applying for\",\n    fieldName: \"jobTitle\",\n    fieldType: \"dropdown\",\n    fieldOptions: { values: $json.jobs.map(item => ({ option: item.Role })) },\n    requiredField: true\n  }\n] }}"
      },
      "notesInFlow": false,
      "typeVersion": 2.5
    },
    {
      "id": "8c5cd23d-9cc3-47ec-9d80-7c2592926424",
      "name": "Show No Jobs Available Page",
      "type": "n8n-nodes-base.form",
      "position": [
        -432,
        2512
      ],
      "parameters": {
        "operation": "completion",
        "respondWith": "showText",
        "responseText": "<div style=\"\n    max-width:580px;\n    margin:70px auto;\n    padding:50px 35px;\n    text-align:center;\n    font-family:Inter,Arial,sans-serif;\n    background:\n        linear-gradient(\n            145deg,\n            rgba(255,255,255,0.06),\n            transparent\n        ),\n        #111111;\n    border:1px solid #2a2a2a;\n    border-radius:26px;\n    box-shadow:\n        0 40px 100px rgba(0,0,0,.65);\n    position:relative;\n    overflow:hidden;\n\">\n\n\n    <!-- Gold top glow -->\n    <div style=\"\n        position:absolute;\n        top:0;\n        left:15%;\n        right:15%;\n        height:3px;\n        background:\n        linear-gradient(\n            90deg,\n            transparent,\n            #facc15,\n            transparent\n        );\n    \"></div>\n\n\n\n    <!-- Icon -->\n\n    <div style=\"\n        width:90px;\n        height:90px;\n        margin:0 auto 25px;\n        border-radius:50%;\n        display:flex;\n        align-items:center;\n        justify-content:center;\n        background:\n        radial-gradient(\n            circle,\n            rgba(250,204,21,.25),\n            rgba(250,204,21,.05)\n        );\n        border:1px solid rgba(250,204,21,.35);\n        font-size:45px;\n        box-shadow:\n        0 15px 40px rgba(250,204,21,.15);\n    \">\n        \u2728\n    </div>\n\n\n\n    <!-- Heading -->\n\n    <h1 style=\"\n        font-size:34px;\n        font-weight:800;\n        color:#ffffff;\n        margin:0 0 18px;\n        letter-spacing:-1px;\n    \">\n        Thank You For Your Interest\n    </h1>\n\n\n\n    <!-- Main Message -->\n\n    <p style=\"\n        font-size:17px;\n        color:#b8b8b8;\n        line-height:1.8;\n        margin:0 auto 30px;\n        max-width:460px;\n    \">\n        We appreciate your interest in joining our team.\n        There are currently no open positions available\n        in this department.\n    </p>\n\n\n\n    <!-- Divider -->\n\n    <div style=\"\n        width:80%;\n        height:1px;\n        margin:35px auto;\n        background:\n        linear-gradient(\n            90deg,\n            transparent,\n            #333333,\n            transparent\n        );\n    \">\n    </div>\n\n\n\n    <!-- Secondary Message -->\n\n    <div style=\"\n        padding:20px;\n        background:#171717;\n        border-radius:16px;\n        border:1px solid #272727;\n        margin-bottom:30px;\n    \">\n\n        <p style=\"\n            font-size:15px;\n            color:#9ca3af;\n            line-height:1.7;\n            margin:0;\n        \">\n            New opportunities are added regularly.\n            We encourage you to check back soon or\n            explore other available roles.\n        </p>\n\n    </div>\n\n\n\n    <!-- CTA -->\n\n    <a href=\"#\" style=\"\n        display:inline-flex;\n        align-items:center;\n        justify-content:center;\n        padding:15px 30px;\n        border-radius:999px;\n        background:\n        linear-gradient(\n            135deg,\n            #ffe259,\n            #fbbf24\n        );\n        color:#111111;\n        text-decoration:none;\n        font-size:15px;\n        font-weight:800;\n        letter-spacing:.3px;\n        box-shadow:\n        0 15px 35px rgba(250,204,21,.25);\n        transition:.3s;\n    \">\n        View Other Opportunities \u2192\n    </a>\n\n\n\n    <!-- Footer -->\n\n    <p style=\"\n        margin-top:35px;\n        font-size:13px;\n        color:#666666;\n    \">\n        We appreciate your time and interest in our company.\n    </p>\n\n\n</div>"
      },
      "typeVersion": 2.5
    },
    {
      "id": "cec2c892-113c-4d5c-b003-5443b643fffa",
      "name": "When Application Submitted",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        -1552,
        2416
      ],
      "parameters": {
        "options": {
          "customCss": ":root {\n\n\t/* =========================\n\t   TYPOGRAPHY\n\t========================= */\n\n\t--font-family: \"Space Grotesk\", \"Inter\", \"Helvetica Neue\", Arial, sans-serif;\n\n\t--font-weight-normal: 400;\n\t--font-weight-bold: 700;\n\n\t--font-size-body: 15px;\n\t--font-size-label: 13px;\n\t--font-size-input: 16px;\n\t--font-size-header: 36px;\n\t--font-size-paragraph: 16px;\n\t--font-size-link: 14px;\n\n\n\t/* =========================\n\t   COLORS\n\t========================= */\n\n\n\t--color-background: #0b0d10;\n\n\n\t--color-card-bg: #15181d;\n\n\t--color-card-border: #282d35;\n\n\t--color-card-shadow:\n\t\trgba(0,0,0,.55);\n\n\n\n\t--color-header: #f8fafc;\n\n\t--color-label: #a5acb8;\n\n\t--color-html-text: #cbd5e1;\n\n\t--color-header-subtext: #8992a2;\n\n\n\n\t--color-input-border: #303641;\n\n\t--color-input-text: #f8fafc;\n\n\t--color-focus-border: #f59e0b;\n\n\n\n\t--color-submit-btn-bg:\n\n\tlinear-gradient(\n\t\t135deg,\n\t\t#fbbf24,\n\t\t#f59e0b\n\t);\n\n\n\t--color-submit-btn-text: #18120a;\n\n\n\n\t--color-error:#ef4444;\n\n\t--color-required:#f97316;\n\n\n\n\t/* =========================\n\t   SHAPE\n\t========================= */\n\n\n\t--border-radius-card:24px;\n\n\t--card-border-radius:24px;\n\n\t--border-radius-input:12px;\n\n\t--border-radius-clear-btn:50%;\n\n\n\n\t/* =========================\n\t   SPACING\n\t========================= */\n\n\n\t--padding-container-top:70px;\n\n\t--padding-card:42px;\n\n\t--card-padding:42px;\n\n\t--margin-bottom-card:24px;\n\n\t--card-margin-bottom:24px;\n\n\t--padding-form-input:15px;\n\n\n\n\t/* =========================\n\t   SIZE\n\t========================= */\n\n\n\t--container-width:560px;\n\n\t--submit-btn-height:56px;\n\n\t--checkbox-size:18px;\n\n\n\t--box-shadow-card:\n\n\t0 35px 80px rgba(0,0,0,.55);\n\n\n\t--opacity-placeholder:.45;\n\n}\n\n\n\n/* =================================\n   BACKGROUND\n================================= */\n\n\nbody {\n\n\tbackground:\n\n\tradial-gradient(\n\t\tcircle at 10% 10%,\n\t\trgba(245,158,11,.12),\n\t\ttransparent 35%\n\t),\n\n\tradial-gradient(\n\t\tcircle at 90% 90%,\n\t\trgba(59,130,246,.10),\n\t\ttransparent 40%\n\t),\n\n\t#0b0d10;\n\n}\n\n\n\n/* =================================\n   CARD\n================================= */\n\n\nform {\n\n\n\tbackground:\n\n\tlinear-gradient(\n\t\t145deg,\n\t\trgba(255,255,255,.04),\n\t\ttransparent 45%\n\t),\n\n\tvar(--color-card-bg);\n\n\n\tborder:\n\n\t1px solid var(--color-card-border);\n\n\n\tbox-shadow:\n\n\tvar(--box-shadow-card);\n\n\n\n}\n\n\n\n/* =================================\n   HEADINGS\n================================= */\n\n\nh1,\nh2,\nh3 {\n\n\tcolor:\n\n\t#f8fafc;\n\n\tletter-spacing:\n\n\t-0.7px;\n\n}\n\n\n\n/* =================================\n   LABELS\n================================= */\n\n\nlabel {\n\n\tcolor:\n\n\t#a5acb8;\n\n\n\tfont-weight:\n\n\t600;\n\n\n\tfont-size:\n\n\t13px;\n\n\n\ttext-transform:\n\n\tuppercase;\n\n\n\tletter-spacing:\n\n\t.8px;\n\n}\n\n\n\n/* =================================\n   INPUTS\n================================= */\n\n\ninput,\ntextarea,\nselect {\n\n\n\tbackground:\n\n\t#0f1115 !important;\n\n\n\tcolor:\n\n\t#f8fafc !important;\n\n\n\tborder:\n\n\t1px solid #303641;\n\n\n\tborder-radius:\n\n\t12px;\n\n\n\ttransition:\n\n\tall .25s ease;\n\n}\n\n\n\ninput::placeholder,\ntextarea::placeholder {\n\n\n\tcolor:\n\n\t#77808d;\n\n}\n\n\n\ninput:hover,\ntextarea:hover,\nselect:hover {\n\n\n\tborder-color:\n\n\t#4b5563;\n\n}\n\n\n\ninput:focus,\ntextarea:focus,\nselect:focus {\n\n\n\tborder-color:\n\n\t#f59e0b;\n\n\n\tbox-shadow:\n\n\t0 0 0 4px rgba(245,158,11,.15);\n\n}\n\n\n\n/* Autofill fix */\n\ninput:-webkit-autofill,\ninput:-webkit-autofill:hover,\ninput:-webkit-autofill:focus {\n\n\n\t-webkit-text-fill-color:\n\n\t#f8fafc !important;\n\n\n\tbox-shadow:\n\n\t0 0 0 1000px #0f1115 inset !important;\n\n}\n\n\n\n/* =================================\n   FILE UPLOAD\n================================= */\n\n\ninput[type=\"file\"] {\n\n\n\tbackground:\n\n\t#0f1115 !important;\n\n\n\tborder:\n\n\t1px dashed #3b4250;\n\n\n\tpadding:\n\n\t12px;\n\n\n\tcursor:\n\n\tpointer;\n\n\n}\n\n\n\ninput[type=\"file\"]::file-selector-button {\n\n\n\tbackground:\n\n\tlinear-gradient(\n\t\t135deg,\n\t\t#fbbf24,\n\t\t#f59e0b\n\t);\n\n\n\tcolor:\n\n\t#18120a;\n\n\n\tborder:\n\n\tnone;\n\n\n\tborder-radius:\n\n\t10px;\n\n\n\tpadding:\n\n\t10px 16px;\n\n\n\tmargin-right:\n\n\t14px;\n\n\n\tfont-weight:\n\n\t700;\n\n\n\tcursor:\n\n\tpointer;\n\n\n}\n\n\n\ninput[type=\"file\"]::file-selector-button:hover {\n\n\n\tfilter:\n\n\tbrightness(1.1);\n\n}\n\n\n\n/* =================================\n   BUTTON\n================================= */\n\n\nbutton {\n\n\n\theight:\n\n\t56px;\n\n\n\tbackground:\n\n\tlinear-gradient(\n\t\t135deg,\n\t\t#fbbf24,\n\t\t#f59e0b\n\t);\n\n\n\tcolor:\n\n\t#18120a;\n\n\n\tborder:\n\n\tnone;\n\n\n\tborder-radius:\n\n\t14px;\n\n\n\tfont-weight:\n\n\t700;\n\n\n\tfont-size:\n\n\t15px;\n\n\n\ttext-transform:\n\n\tuppercase;\n\n\n\tletter-spacing:\n\n\t.7px;\n\n\n\tbox-shadow:\n\n\t0 12px 25px rgba(245,158,11,.25);\n\n\n\ttransition:\n\n\tall .25s ease;\n\n}\n\n\n\nbutton:hover {\n\n\n\ttransform:\n\n\ttranslateY(-2px);\n\n\n\tbox-shadow:\n\n\t0 18px 35px rgba(245,158,11,.35);\n\n}\n\n\n\nbutton:active {\n\n\n\ttransform:\n\n\ttranslateY(1px);\n\n}\n\n\n\n/* =================================\n   CHECKBOX / RADIO\n================================= */\n\n\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n\n\n\taccent-color:\n\n\t#f59e0b;\n\n}\n\n\n\n/* =================================\n   LINKS\n================================= */\n\n\na {\n\n\n\tcolor:\n\n\t#fbbf24;\n\n\n}\n\n\n\n/* =================================\n   MOBILE\n================================= */\n\n\n@media(max-width:640px){\n\n\n\t:root {\n\n\n\t--padding-card:24px;\n\n\t--card-padding:24px;\n\n\t--font-size-header:28px;\n\n\t}\n\n}",
          "appendAttribution": false
        },
        "formTitle": "Candidate Form",
        "formFields": {
          "values": [
            {
              "fieldLabel": "Name",
              "placeholder": "Name",
              "requiredField": true
            },
            {
              "fieldType": "email",
              "fieldLabel": "Email",
              "placeholder": "Email",
              "requiredField": true
            },
            {
              "fieldType": "file",
              "fieldLabel": "CV",
              "multipleFiles": false,
              "requiredField": true,
              "acceptFileTypes": ".pdf, .docx"
            },
            {
              "fieldType": "dropdown",
              "fieldLabel": "Select Department",
              "fieldOptions": {
                "values": [
                  {
                    "option": "Finance"
                  },
                  {
                    "option": "Engineering"
                  },
                  {
                    "option": "Call Center"
                  },
                  {
                    "option": "Sale"
                  }
                ]
              },
              "requiredField": true
            }
          ]
        },
        "formDescription": "Please ,fill the required fields , and we'll get in touch with you soon !"
      },
      "typeVersion": 2.2
    },
    {
      "id": "fc7f34df-0356-4a1c-a0c3-c1e2a7330b24",
      "name": "Fetch Job Roles from Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "maxTries": 5,
      "position": [
        -1104,
        2416
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1XgHQzF9xuWfH1N5_Vhdvk9Jq5QyZXonSeThYGgH9FRg/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1XgHQzF9xuWfH1N5_Vhdvk9Jq5QyZXonSeThYGgH9FRg",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1XgHQzF9xuWfH1N5_Vhdvk9Jq5QyZXonSeThYGgH9FRg/edit?usp=drivesdk",
          "cachedResultName": "Job_Roles"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "retryOnFail": true,
      "typeVersion": 4.7,
      "alwaysOutputData": false,
      "waitBetweenTries": 5000
    },
    {
      "id": "be17be93-ad23-442b-8fc2-6cc27f409225",
      "cid": "Ikx1Y2FzIFBleXJpbiI",
      "name": "Extract Resume with Mistral",
      "type": "n8n-nodes-base.mistralAi",
      "notes": "\u00a9 2025 Lucas Peyrin",
      "creator": "Lucas Peyrin",
      "position": [
        -1328,
        2416
      ],
      "parameters": {
        "options": {},
        "binaryProperty": "={{ Object.keys($('When Application Submitted').last().binary)[0] }}"
      },
      "credentials": {
        "mistralCloudApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "c5843a91-b574-42bf-8efb-44add5bee535",
      "name": "Fetch Job Description from Docs",
      "type": "n8n-nodes-base.googleDocs",
      "position": [
        240,
        2320
      ],
      "parameters": {
        "operation": "get",
        "documentURL": "={{ $json.JD_Link }}"
      },
      "credentials": {
        "googleDocsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "3bee5f70-72c2-4392-b954-24befbbdf5cb",
      "name": "Construct AI Evaluation Prompt",
      "type": "n8n-nodes-base.code",
      "position": [
        464,
        2320
      ],
      "parameters": {
        "jsCode": "const resumeText = $('Extract Resume with Mistral').first().json.extractedText;\nconst jdText = $('Fetch Job Description from Docs').first().json.content;\nconst candidateName = $('When Application Submitted').first().json.Name;\nconst role = $('Show Job Selection Form').first().json.jobTitle;\n\nconst prompt = `\nYou are an expert technical recruiter and ATS screening assistant.\n\nYour task is to evaluate a candidate's resume against the provided job description and produce a strict JSON evaluation.\n\nIMPORTANT RULES:\n- Evaluate ONLY using evidence explicitly present in the resume.\n- Never assume a skill, experience, responsibility, or qualification exists because it is common for the role.\n- If a requirement is not mentioned in the resume, treat it as missing.\n- Do not reward technologies that are only implied.\n- Be objective and conservative in scoring.\n- Do not include personal opinions or bias.\n\n\nROLE:\n${role}\n\nCANDIDATE NAME:\n${candidateName}\n\nJOB DESCRIPTION:\n${jdText}\n\nRESUME:\n${resumeText}\n\n\nINPUT DOCUMENT VALIDATION:\n\nBefore performing any scoring, first verify that the provided RESUME is actually a candidate resume/CV.\n\nA valid CV must contain evidence of a candidate profile, such as:\n- Candidate name or personal details\n- Work experience, internships, freelance work, or professional projects\n- Employment dates, duration, roles, achievements, or responsibilities\n- Education, certifications, or academic background\n- Skills connected to the candidate's own experience\n\nInvalid documents include:\n- Technical documentation\n- Software architecture documents\n- Product requirement documents\n- Project proposals\n- Tutorials\n- Articles\n- Job descriptions\n- Random text\n- Documents containing only technology names without candidate history\n\nIMPORTANT:\n- Do not consider a document a CV only because it contains programming languages, frameworks, cloud platforms, or technical keywords.\n- A list of technologies, system designs, architecture diagrams, or project descriptions without candidate ownership/history is not sufficient evidence of candidate skills or experience.\n- Do not evaluate technical documents, project specifications, or documentation as if they represent candidate experience.\n\nIf the RESUME is invalid:\n\nReturn the required JSON structure with:\n- overallScore: 0\n- experienceScore: 0\n- technicalSkillsScore: 0\n- responsibilitiesScore: 0\n- educationScore: 0\n- softSkillsScore: 0\n- matchedSkills: []\n- candidateSkills: []\n- missingMandatorySkills: []\n- missingPreferredSkills: []\n- candidateExperienceYears: 0\n\ncandidateSummary:\n\"Invalid resume document provided.\"\n\nreason:\n\"Evaluation stopped because the uploaded document does not contain sufficient evidence of a candidate resume, employment history, education, or professional background.\"\n\n\nSCORING INSTRUCTIONS:\n\nFirst, identify the scoring weights from the job description.\n\nIf the JD contains custom weights, use those weights.\n\nIf no weights are provided, use:\n\n- Experience: 25%\n- Technical Skills: 40%\n- Responsibilities Match: 20%\n- Education: 5%\n- Soft Skills: 10%\n\n\nGENERAL SCORE CALIBRATION:\n\nUse these scoring ranges:\n\n90-100:\nExceptional match. Candidate clearly exceeds or fully satisfies the requirement with strong evidence.\n\n75-89:\nStrong match. Candidate satisfies most requirements with minor gaps.\n\n60-74:\nModerate match. Candidate satisfies some requirements but has noticeable gaps.\n\n40-59:\nWeak match. Limited evidence or partial alignment.\n\n0-39:\nPoor match. Requirement is mostly missing.\n\n\nSCORING GUIDELINES:\n\nExperience Score:\n- Compare required years of experience against proven experience in the resume.\n- Only count professional experience, internships, or projects if explicitly relevant.\n- Do not count education duration as experience.\n- Do not overestimate experience from projects alone.\n\n\nTechnical Skills Score:\n- Compare mandatory and preferred skills from the JD against the resume.\n- Mandatory skills should have higher impact.\n- Only mark a JD skill as matched if it is explicitly mentioned or clearly demonstrated in the resume.\n- Do not include related technologies as substitutes.\n- Example: Node.js does not imply Next.js.\n- Example: React does not imply React Native.\n- Equivalent demonstrated experience is allowed.\n- Example: \"resolved production issues\" demonstrates debugging ability.\n\n\nResponsibilities Score:\n- Compare each responsibility independently against evidence from the resume.\n- Similar wording alone is not enough.\n- Require meaningful evidence through projects, achievements, ownership, or delivered work.\n- Consider measurable impact and real responsibilities.\n\n\nEducation Score:\n- Evaluate education relevance and completion status separately.\n- A degree currently in progress in the required field should receive strong credit.\n- Reduce score only because the degree is incomplete, not because it is irrelevant.\n- Do not heavily penalize education when the JD marks it as preferred.\n\n\nSoft Skills Score:\n- Score only based on evidence such as leadership, mentoring, collaboration, communication, teamwork, client interaction, or ownership.\n- Do not infer soft skills only from job titles.\n\n\nSKILL EXTRACTION RULES:\n\nmatchedSkills:\n- Include only skills from the JOB DESCRIPTION that are found in the resume.\n- This is used for JD matching and scoring.\n\ncandidateSkills:\n- Extract ALL technical skills, programming languages, frameworks, libraries, databases, cloud platforms, infrastructure tools, security tools, testing tools, methodologies, and technologies explicitly mentioned in the resume.\n- Do not limit this list to JD requirements.\n- Do not infer technologies that are not present.\n- Preserve important categories such as backend, frontend, cloud, databases, testing, security, and infrastructure.\n\n\nSTRICT MISSING EVIDENCE HANDLING:\n\nIf the resume does not provide explicit evidence for a required category, score that category as 0.\n\nExamples:\n- If no professional experience is mentioned, experienceScore must be 0.\n- If no JD-required technical skills are explicitly found in the resume, technicalSkillsScore must be 0.\n- If no responsibilities from the JD are demonstrated in the resume, responsibilitiesScore must be 0.\n- If education information is missing, educationScore must be 0.\n- If no evidence of communication, teamwork, leadership, ownership, collaboration, or client interaction exists, softSkillsScore must be 0.\n\nWhen assigning a score of 0:\n- Do not leave the reason empty.\n- Clearly explain that the score is 0 because no explicit evidence was found in the resume.\n- Do not penalize based on assumptions or missing formatting.\n- A missing skill, qualification, or responsibility must always be treated as unavailable evidence.\n\nExamples of valid reasons:\n- \"Technical Skills Score is 0 because the resume does not explicitly mention any of the required technologies from the job description.\"\n- \"Experience Score is 0 because the resume does not provide evidence of relevant professional experience.\"\n- \"Soft Skills Score is 0 because the resume does not include evidence of collaboration, leadership, communication, or ownership.\"\n\nThe evaluator must never give partial credit for assumed knowledge, related technologies, job titles, or industry expectations.\n\n\nOUTPUT RULES:\n\nCRITICAL:\n- Return ONLY raw JSON.\n- Do NOT use markdown formatting.\n- Do NOT wrap JSON inside code blocks.\n- The first character must be {\n- The last character must be }\n\n\nReturn exactly this JSON structure:\n\n{\n  \"overallScore\": 0,\n  \"experienceScore\": 0,\n  \"technicalSkillsScore\": 0,\n  \"responsibilitiesScore\": 0,\n  \"educationScore\": 0,\n  \"softSkillsScore\": 0,\n\n  \"matchedSkills\": [],\n  \"candidateSkills\": [],\n\n  \"missingMandatorySkills\": [],\n  \"missingPreferredSkills\": [],\n\n  \"candidateExperienceYears\": 0,\n\n  \"candidateSummary\": \"\",\n  \"reason\": \"\"\n}\n\n\nAdditional requirements:\n- Scores must be numbers between 0 and 100.\n- matchedSkills must only contain JD skills found in the resume.\n- candidateSkills must contain all explicitly mentioned resume skills.\n- missingMandatorySkills must only contain mandatory JD requirements missing from the resume.\n- missingPreferredSkills must only contain preferred JD requirements missing from the resume.\n- candidateSummary should briefly describe the candidate's profile, expertise, and experience level.\n- reason must explain the score using evidence from the resume.\n`;\n\nreturn { json: { prompt } };"
      },
      "typeVersion": 2
    },
    {
      "id": "553a94bf-4f50-4b53-8e9b-7ccb2d450e7a",
      "name": "Evaluate Candidate LLM Chain",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "maxTries": 5,
      "position": [
        688,
        2320
      ],
      "parameters": {
        "text": "={{ $json.prompt }}",
        "batching": {},
        "promptType": "define",
        "hasOutputParser": true
      },
      "retryOnFail": true,
      "typeVersion": 1.9,
      "waitBetweenTries": 5000
    },
    {
      "id": "e887d116-b5a0-46cd-be39-3954ed8f8d4d",
      "name": "If Candidate Shortlisted",
      "type": "n8n-nodes-base.if",
      "position": [
        1312,
        2320
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "8b61b63e-d52d-49f0-937e-7c7b0bee41bf",
              "operator": {
                "type": "number",
                "operation": "gte"
              },
              "leftValue": "={{ Number($('Evaluate Candidate LLM Chain').item.json.output.overallScore) }}",
              "rightValue": "={{ Number($('Filter Job Description by Role').item.json.Min_Score) }}"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "34f29c88-f5d9-4ce2-9278-6fd61191718c",
      "name": "Prepare Shortlist Assets",
      "type": "n8n-nodes-base.code",
      "position": [
        1536,
        2128
      ],
      "parameters": {
        "jsCode": "const folders = {\n  Engineering: \"1ESgh92tBTuU6EeAPN_iyMomRw9fB5iJ7\",\n  Finance: \"1IkzOcy-uVo6196_2V0CsqNzl3Wq4t5lh\",\n  Sale: \"11Dc8zbV4QOzKpdVo2j0aXsk0_wwDf2wv\",\n  CallCenter: \"11Dc8zbV4QOzKpdVo2j0aXsk0_wwDf2wv\"\n};\n\nconst application = $('When Application Submitted').first();\nconst department = application.json[\"Select Department\"];\nconst candidateName = application.json.Name;\nconst candidateMail = application.json.Email\n\n// Read evaluation JSON from binary file\nconst evaluationBinary = $('Convert AI Results to File').first().binary;\nconst binaryKey = Object.keys(evaluationBinary)[0];\n\nconst jsonBuffer = await this.helpers.getBinaryDataBuffer(0, binaryKey);\nconst evaluationData = JSON.parse(jsonBuffer.toString());\n\nconst candidate = evaluationData[0]?.output || {};\n\nconst formatList = (items, prefix = \"\u2022\") =>\n  items?.length\n    ? items.map(item => `${prefix} ${item}`).join(\"\\n\")\n    : \"None\";\n\nconst report = `\n=========================================\nCANDIDATE EVALUATION REPORT\n=========================================\n\nCandidate Name:\n${candidateName}\n\nCandidate Gmail:\n${candidateMail}\n\n=========================================\nEVALUATION SUMMARY\n=========================================\n\nOverall Match Score:\n${candidate.overallScore ?? \"N/A\"}/100\n\nQualification Status:\nShortlisted for Initial Interview\n\nMandatory Requirements:\n${\n  candidate.missingMandatorySkills?.length\n    ? `Missing ${candidate.missingMandatorySkills.length} requirement(s)`\n    : \"All Mandatory Requirements Met\"\n}\n\nPreferred Requirements:\n${\n  candidate.missingPreferredSkills?.length\n    ? `${candidate.missingPreferredSkills.length} Preferred Skill Gap(s) Identified`\n    : \"All Preferred Requirements Met\"\n}\n\n=========================================\nSCORING BREAKDOWN\n=========================================\n\nTechnical Skills Score:\n${candidate.technicalSkillsScore ?? \"N/A\"}/100\n\nExperience Score:\n${candidate.experienceScore ?? \"N/A\"}/100\n\nResponsibilities Score:\n${candidate.responsibilitiesScore ?? \"N/A\"}/100\n\nEducation Score:\n${candidate.educationScore ?? \"N/A\"}/100\n\nSoft Skills Score:\n${candidate.softSkillsScore ?? \"N/A\"}/100\n\n\n=========================================\nEXPERIENCE\n=========================================\n\nRelevant Experience:\n${candidate.candidateExperienceYears ?? \"N/A\"} Years\n\n\n=========================================\nPROFESSIONAL SUMMARY\n=========================================\n\n${candidate.candidateSummary || \"No summary available.\"}\n\n\n=========================================\nJOB REQUIREMENTS MATCH\n=========================================\n\nMatched Skills (${candidate.matchedSkills?.length || 0})\n\n${formatList(candidate.matchedSkills, \"\u2713\")}\n\n\n=========================================\nCOMPLETE SKILL INVENTORY\n=========================================\n\nTotal Skills Identified:\n${candidate.candidateSkills?.length || 0}\n\n${formatList(candidate.candidateSkills)}\n\n\n=========================================\nSKILL GAPS\n=========================================\n\nMissing Mandatory Skills:\n\n${formatList(candidate.missingMandatorySkills)}\n\n\nMissing Preferred Skills:\n\n${formatList(candidate.missingPreferredSkills)}\n\n\n=========================================\nAI EVALUATION REASONING\n=========================================\n\n${candidate.reason || \"No evaluation reasoning available.\"}\n\n\n=========================================\nRECRUITER NOTES\n=========================================\n\nStrength Areas:\n\n${formatList(candidate.matchedSkills)}\n\n\nAreas Requiring Attention:\n\n${formatList(candidate.missingPreferredSkills)}\n\n\n=========================================\nSCREENING RESULT\n=========================================\n\nThe candidate met the qualification criteria used during\nthe automated screening process and has been included in\nthe shortlist for recruiter review.\n\nOverall Match Score:\n${candidate.overallScore ?? \"N/A\"}/100\n\nRelevant Experience:\n${candidate.candidateExperienceYears ?? \"N/A\"} Years\n\nMandatory Skill Gaps:\n${candidate.missingMandatorySkills?.length || 0}\n\nPreferred Skill Gaps:\n${candidate.missingPreferredSkills?.length || 0}\n\n\n=========================================\nEND OF REPORT\n=========================================\n`.trim();\n\n\nreturn [\n  {\n    json: {\n      folderId: folders[department],\n      binary: application.binary,\n      report\n    }\n  }\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "e94ca3ff-b140-417a-8030-e9455d8573b7",
      "name": "Convert AI Results to File",
      "type": "n8n-nodes-base.convertToFile",
      "position": [
        1088,
        2320
      ],
      "parameters": {
        "options": {},
        "operation": "toJson",
        "binaryPropertyName": "={{ $('When Application Submitted').item.json.Name + '-Evaluation.json' }}"
      },
      "typeVersion": 1.1
    },
    {
      "id": "e57be14b-e388-4788-b0b3-6cede3ee3b88",
      "name": "Structure Evaluation Output",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        880,
        2544
      ],
      "parameters": {
        "jsonSchemaExample": "{\n  \"overallScore\": 0,\n  \"experienceScore\": 0,\n  \"technicalSkillsScore\": 0,\n  \"responsibilitiesScore\": 0,\n  \"educationScore\": 0,\n  \"softSkillsScore\": 0,\n  \"matchedSkills\": [],\n  \"candidateSkills\": [],\n  \"missingMandatorySkills\": [],\n  \"missingPreferredSkills\": [],\n  \"candidateExperienceYears\": 0,\n  \"candidateSummary\": \"\",\n  \"reason\": \"\"\n}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "2bac521a-cbfc-48e4-83cd-b9b3782ff982",
      "name": "Convert Shortlist Insights to File",
      "type": "n8n-nodes-base.convertToFile",
      "position": [
        1760,
        2032
      ],
      "parameters": {
        "options": {},
        "operation": "toText",
        "sourceProperty": "report",
        "binaryPropertyName": "report"
      },
      "typeVersion": 1.1
    },
    {
      "id": "fd68cf14-ff90-4cf8-ac0f-43c50b1c35e8",
      "name": "Prepare Rejection Assets",
      "type": "n8n-nodes-base.code",
      "position": [
        1536,
        2656
      ],
      "parameters": {
        "jsCode": "const rejectedDriveFolder = {\n  CallCenter: \"1SdmHlq07PxBIqiHQHSUaKDCCra0HpVTW\",\n  Finance: \"1cgqr0QbWLgABaue_wldc_iVqj5aDNrR5\",\n  Sale: \"1HVyG5hHOeSQu_7srB85JcApVSjKYOVrR\",\n  Engineering: \"1mPR66TfzjaRkYQHPuSy-_mbQbKE3NETb\"\n};\n\nconst application = $('When Application Submitted').first();\nconst department = application.json[\"Select Department\"];\nconst candidateName = application.json.Name;\n\n\n// Read evaluation JSON\nconst evaluationBinary = $('Convert AI Results to File').first().binary;\nconst binaryKey = Object.keys(evaluationBinary)[0];\n\nconst jsonBuffer = await this.helpers.getBinaryDataBuffer(0, binaryKey);\nconst evaluationData = JSON.parse(jsonBuffer.toString());\n\nconst candidate = evaluationData[0]?.output || {};\n\nconst formatList = (items, prefix = \"\u2022\") =>\n  items?.length\n    ? items.map(item => `${prefix} ${item}`).join(\"\\n\")\n    : \"None\";\n\n\nconst report = `\n=========================================\nCANDIDATE EVALUATION REPORT\n=========================================\n\nCandidate Name:\n${candidateName}\n\n=========================================\nEVALUATION SUMMARY\n=========================================\n\nOverall Match Score:\n${candidate.overallScore ?? \"N/A\"}/100\n\nQualification Status:\nNot Selected for Initial Interview\n\n=========================================\nSCORING BREAKDOWN\n=========================================\n\nTechnical Skills Score:\n${candidate.technicalSkillsScore ?? \"N/A\"}/100\n\nExperience Score:\n${candidate.experienceScore ?? \"N/A\"}/100\n\nResponsibilities Score:\n${candidate.responsibilitiesScore ?? \"N/A\"}/100\n\nEducation Score:\n${candidate.educationScore ?? \"N/A\"}/100\n\nSoft Skills Score:\n${candidate.softSkillsScore ?? \"N/A\"}/100\n\n\n=========================================\nEXPERIENCE\n=========================================\n\nRelevant Experience:\n${candidate.candidateExperienceYears ?? \"N/A\"} Years\n\n\n=========================================\nPROFESSIONAL SUMMARY\n=========================================\n\n${candidate.candidateSummary || \"No summary available.\"}\n\n\n=========================================\nIDENTIFIED SKILLS\n=========================================\n\nMatched Skills:\n\n${formatList(candidate.matchedSkills, \"\u2713\")}\n\n\nComplete Skill Inventory:\n\nTotal Skills Identified:\n${candidate.candidateSkills?.length || 0}\n\n${formatList(candidate.candidateSkills)}\n\n\n=========================================\nSKILL GAPS\n=========================================\n\nMissing Mandatory Skills:\n\n${formatList(candidate.missingMandatorySkills)}\n\n\nMissing Preferred Skills:\n\n${formatList(candidate.missingPreferredSkills)}\n\n\n=========================================\nAI EVALUATION REASONING\n=========================================\n\n${candidate.reason || \"No evaluation reasoning available.\"}\n\n\n=========================================\nSCREENING RESULT\n=========================================\n\nThe candidate did not meet the required criteria for\nprogression to the next stage of the recruitment process.\n\nEvaluation Summary:\n\nOverall Match Score:\n${candidate.overallScore ?? \"N/A\"}/100\n\nRelevant Experience:\n${candidate.candidateExperienceYears ?? \"N/A\"} Years\n\nMandatory Skill Gaps:\n${candidate.missingMandatorySkills?.length || 0}\n\nPreferred Skill Gaps:\n${candidate.missingPreferredSkills?.length || 0}\n\n\n=========================================\nEND OF REPORT\n=========================================\n`.trim();\n\n\nreturn [\n  {\n    json: {\n      folderId: rejectedDriveFolder[department],\n      binary: application.binary,\n      report\n    }\n  }\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "0623d99e-8ebe-4ada-a89c-1af2906ed43b",
      "name": "Convert Rejection Insights to File",
      "type": "n8n-nodes-base.convertToFile",
      "position": [
        1760,
        2560
      ],
      "parameters": {
        "options": {},
        "operation": "toText",
        "sourceProperty": "report",
        "binaryPropertyName": "report"
      },
      "typeVersion": 1.1
    },
    {
      "id": "0fc0ae0f-5e29-4a5e-850f-90531f25d69f",
      "name": "Upload Shortlist Insights to Drive",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        1984,
        2032
      ],
      "parameters": {
        "name": "={{ $('When Application Submitted').first().json.Name }}-Evaluation-Report.txt",
        "driveId": {
          "__rl": true,
          "mode": "url",
          "value": "https://drive.google.com/drive/folders/1MdFbAqgLdXjAxdBtuEAGBy8O9LLj0-2Y",
          "__regex": "https:\\/\\/drive\\.google\\.com(?:\\/.*|)\\/folders\\/([0-9a-zA-Z\\-_]+)(?:\\/.*|)"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Prepare Shortlist Assets').item.json.folderId }}"
        },
        "inputDataFieldName": "report"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "9472323e-16b6-4f3f-8422-b28013fb825e",
      "name": "Upload Shortlist Resume to Drive",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        1760,
        2224
      ],
      "parameters": {
        "name": "={{ $('When Application Submitted').item.json.CV.filename }}",
        "driveId": {
          "__rl": true,
          "mode": "url",
          "value": "https://drive.google.com/drive/folders/1MdFbAqgLdXjAxdBtuEAGBy8O9LLj0-2Y"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.folderId }}"
        },
        "inputDataFieldName": "={{ $json.binary.CV }}"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "374f8d4b-51e4-4990-9f66-213d09d21705",
      "name": "Upload Rejection Insights to Drive",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        1984,
        2560
      ],
      "parameters": {
        "name": "={{ $('When Application Submitted').first().json.Name }}-Evaluation-Report.txt",
        "driveId": {
          "__rl": true,
          "mode": "url",
          "value": "https://drive.google.com/drive/folders/1MdFbAqgLdXjAxdBtuEAGBy8O9LLj0-2Y",
          "__regex": "https:\\/\\/drive\\.google\\.com(?:\\/.*|)\\/folders\\/([0-9a-zA-Z\\-_]+)(?:\\/.*|)"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Prepare Rejection Assets').item.json.folderId }}"
        },
        "inputDataFieldName": "report"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "9f3e8344-4d10-4ac5-9d07-f6b8eb8dff5e",
      "name": "Upload Rejection Resume to Drive",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        1760,
        2752
      ],
      "parameters": {
        "name": "={{ $('When Application Submitted').item.json.CV.filename }}",
        "driveId": {
          "__rl": true,
          "mode": "url",
          "value": "https://drive.google.com/drive/folders/1MdFbAqgLdXjAxdBtuEAGBy8O9LLj0-2Y"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.folderId }}"
        },
        "inputDataFieldName": "={{ $json.binary.CV }}"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "f9f22117-bf61-44ce-8a5f-a67d634bca75",
      "name": "Google Gemini Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        640,
        2544
      ],
      "parameters": {
        "options": {},
        "modelName": "models/gemini-3.6-flash"
      },
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      },
      "notesInFlow": false,
      "typeVersion": 1.1
    },
    {
      "id": "d1044b7e-3f5a-4251-99a3-1d981f27c87e",
      "name": "Send Shortlist Email",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2208,
        2032
      ],
      "parameters": {
        "sendTo": "={{ $('When Application Submitted').item.json.Email }}",
        "message": "<div style=\"font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; color: #333;\">          <h2 style=\"color: #2563eb;\">Congratulations! \ud83c\udf89</h2>      <p>Dear Candidate,</p>      <p>         Thank you for your interest in joining <strong>Fixit Consult Tech</strong>.     </p>      <p>         We are pleased to inform you that your appli

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This workflow collects candidate applications via an n8n form, extracts resume text with Mistral AI, matches the candidate to an open role stored in Google Sheets and Google Docs, scores the fit using Google Gemini, and uploads the CV and an evaluation report to…

Source: https://n8n.io/workflows/17705/ — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

This workflow is perfect for graphic designers, creative agencies, marketing teams, or freelancers who regularly use AI-generated images in their projects. It's specifically beneficial for teams that

Google Sheets, Google Drive, HTTP Request +5
AI & RAG

n8n Graphic Design Team. Uses googleSheets, googleDrive, httpRequest, outputParserStructured. Event-driven trigger; 37 nodes.

Google Sheets, Google Drive, HTTP Request +5
AI & RAG

Automate your lead intake, scoring, and outreach pipeline. This workflow collects leads from forms, enriches and scores them using Relevance AI, routes them by quality, and triggers the right follow-u

Form Trigger, HTTP Request, Chain Llm +6
AI & RAG

N8N Workflows. Uses formTrigger, agent, googleDrive, httpRequest. Event-driven trigger; 24 nodes.

Form Trigger, Agent, Google Drive +8
AI & RAG

This n8n workflow template automates the process of collecting and analyzing Twitter (X) posts for any public profile, then generates a clean, AI-powered summary including key metrics, interests, and

Form Trigger, Google Gemini Chat, Output Parser Structured +4