AutomationFlowsSlack & Telegram › V2.1 Career-bot-workflow

V2.1 Career-bot-workflow

V2.1 Career-Bot-Workflow. Uses telegram, httpRequest, readWriteFile, googleDrive. Scheduled trigger; 33 nodes.

Cron / scheduled trigger★★★★★ complexity33 nodesTelegramHTTP RequestRead Write FileGoogle DriveGoogle Sheets
Slack & Telegram Trigger: Cron / scheduled Nodes: 33 Complexity: ★★★★★ Added:

This workflow follows the Google Drive → Google Sheets 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
{
  "name": "My workflow",
  "nodes": [
    {
      "parameters": {
        "jsCode": "// \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0432\u0441\u0435 \u0432\u0430\u043a\u0430\u043d\u0441\u0438\u0438 \u043f\u043e\u0441\u043b\u0435 \u0440\u0430\u043d\u0436\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f\nconst items = $input.all();\nconst result = [];\n\n// \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u0430\u0442\u044b \u0432 YYYY-MM-DD\nfunction formatDate(date) {\n    const d = new Date(date);\n    const year = d.getFullYear();\n    const month = String(d.getMonth() + 1).padStart(2, '0');\n    const day = String(d.getDate()).padStart(2, '0');\n    return `${year}-${month}-${day}`;\n}\n\n// \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u0440\u0430\u0441\u0447\u0451\u0442\u0430 \u0434\u0435\u0434\u043b\u0430\u0439\u043d\u0430 (+3 \u0434\u043d\u044f)\nfunction getDeadline() {\n    const date = new Date();\n    date.setDate(date.getDate() + 3);\n    return formatDate(date);\n}\n\n// \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044f employment_type\nfunction getEmploymentType(employment) {\n    const employmentMap = {\n        'full': 'fulltime',\n        'part': 'parttime',\n        'intern': 'intern',\n        '\u0441\u0442\u0430\u0436\u0438\u0440\u043e\u0432\u043a\u0430': 'intern',\n        'project': 'fulltime',\n        'volunteer': 'intern'\n    };\n    const empLower = (employment || '').toLowerCase();\n    return employmentMap[empLower] || 'fulltime';\n}\n\n// \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430\nfunction getSource(source) {\n    if (source === 'hh.ru') return 'hh';\n    if (source === '\u0425\u0430\u0431\u0440 \u041a\u0430\u0440\u044c\u0435\u0440\u0430') return 'habr';\n    return source || 'unknown';\n}\n\n// \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043e\u0431\u044a\u044f\u0441\u043d\u0435\u043d\u0438\u044f \u0440\u0435\u0439\u0442\u0438\u043d\u0433\u0430\nfunction getMatchReason(title, content, rating) {\n    const reasons = [];\n    const titleLower = (title || '').toLowerCase();\n    const contentLower = (content || '').toLowerCase();\n    \n    const keywords = {\n        'AI/\u043d\u0435\u0439\u0440\u043e\u0441\u0435\u0442\u0438': ['\u0438\u0438', '\u043d\u0435\u0439\u0440\u043e\u0441\u0435\u0442', '\u0438\u0441\u043a\u0443\u0441\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u043b\u043b\u0435\u043a\u0442', 'gpt', 'ai'],\n        'no-code/low-code': ['no-code', 'nocode', 'low-code', 'lowcode'],\n        '\u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u044f': ['\u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446', '\u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446', '\u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442', 'robotics'],\n        '\u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u043c\u0438': ['project', 'pm', 'agile', 'scrum', '\u043a\u0430\u043d\u0431\u0430\u043d', 'waterfall'],\n        '\u043f\u043e\u0437\u0438\u0446\u0438\u044f (\u0441\u0442\u0430\u0436\u0451\u0440/\u043f\u043e\u043c\u043e\u0449\u043d\u0438\u043a)': ['\u0441\u0442\u0430\u0436\u0435\u0440', '\u043f\u043e\u043c\u043e\u0449\u043d\u0438\u043a', '\u043c\u043b\u0430\u0434\u0448\u0438\u0439', 'junior', 'trainee', '\u0430\u0441\u0441\u0438\u0441\u0442\u0435\u043d\u0442']\n    };\n    \n    for (const [category, words] of Object.entries(keywords)) {\n        for (const word of words) {\n            if (titleLower.includes(word)) {\n                reasons.push(`${category} (+3 \u0431\u0430\u043b\u043b\u0430 \u0432 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0438)`);\n                break;\n            } else if (contentLower.includes(word)) {\n                reasons.push(`${category} (+1 \u0431\u0430\u043b\u043b \u0432 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0438)`);\n                break;\n            }\n        }\n    }\n    \n    if (reasons.length === 0) {\n        return `\u0421\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u0439 \u043f\u043e \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u043c \u0441\u043b\u043e\u0432\u0430\u043c \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u043e. \u0420\u0435\u0439\u0442\u0438\u043d\u0433: ${rating}`;\n    }\n    \n    return `\u0420\u0435\u0439\u0442\u0438\u043d\u0433: ${rating}\\n\\n\u2705 ${reasons.slice(0, 3).join('\\n\u2705 ')}`;\n}\n\n// \u041e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u043a\u0430\u0436\u0434\u0443\u044e \u0432\u0430\u043a\u0430\u043d\u0441\u0438\u044e\nfor (const item of items) {\n    const v = item.json;\n    const createdAt = formatDate(new Date());\n    const deadline = getDeadline();\n    \n    // \u0421\u043e\u0437\u0434\u0430\u0451\u043c \u0438\u043c\u044f \u0444\u0430\u0439\u043b\u0430: \u0412\u0430\u043a\u0430\u043d\u0441\u0438\u044f - \u041a\u043e\u043c\u043f\u0430\u043d\u0438\u044f - \u0414\u0414-\u041c\u041c-\u0413\u0413\u0413\u0413.md\n    const safeRole = (v.title || '\u0412\u0430\u043a\u0430\u043d\u0441\u0438\u044f')\n        .replace(/[<>:\"/\\\\|?*]/g, '') // \u0423\u0434\u0430\u043b\u044f\u0435\u043c \u043d\u0435\u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u044b\u0435 \u0441\u0438\u043c\u0432\u043e\u043b\u044b\n        .substring(0, 50);\n    const safeCompany = (v.author || '\u041d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0430\u044f \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u044f')\n        .replace(/[<>:\"/\\\\|?*]/g, '')\n        .substring(0, 30);\n    const dateStr = createdAt.split('-').reverse().join('-'); // 2025-04-12 \u2192 12-04-2025\n    const fileName = `${safeRole} - ${safeCompany} - ${dateStr}.md`;\n    \n    // \u0424\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u0437\u0430\u043c\u0435\u0442\u043a\u0438\n    const noteContent = `---\ncompany: ${safeCompany}\nrole: ${safeRole}\nstatus: \u0432_\u0430\u043d\u0430\u043b\u0438\u0437\u0435\nsalary: ${v.salary || ''}\nlink: ${v.link || ''}\nexternal_id: ${v.id || v.external_id || ''}\ndeadline: ${deadline}\nsource: ${getSource(v.source)}\nlocation: ${v.city || ''}\nemployment_type: ${getEmploymentType(v.employment_type)}\nparsedByBot: false\nmatchScore: ${v.rating || 0}\ntags: vacancy\ncreatedAt: ${createdAt}\n---\n\n**\u041a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0439:**\n- [ ] \u0420\u0430\u0437\u0431\u043e\u0440 \u0432\u0430\u043a\u0430\u043d\u0441\u0438\u0438 \u043f\u0440\u043e\u0432\u0435\u0434\u0451\u043d?\n- **\u0414\u0430\u0442\u0430 \u043e\u0442\u043a\u043b\u0438\u043a\u0430:** \n\n## \u041f\u043e\u0447\u0435\u043c\u0443 \u0431\u043e\u0442 \u0432\u044b\u0431\u0440\u0430\u043b \u044d\u0442\u0443 \u0432\u0430\u043a\u0430\u043d\u0441\u0438\u044e\n\n${getMatchReason(v.title, v.content, v.rating || 0)}\n\n**\u0421\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0435 \u0437\u0430\u043c\u0435\u0442\u043a\u0438:**\n- [[\u0414\u0430\u0448\u0431\u043e\u0440\u0434 - \u0412\u0430\u043a\u0430\u043d\u0441\u0438\u0438 \u043f\u043e \u0441\u0442\u0430\u0442\u0443\u0441\u0443]]\n- [[\u0421\u043f\u0438\u0441\u043e\u043a \u0440\u0435\u0437\u044e\u043c\u0435]]\n`;\n    \n    result.push({\n        json: {\n            fileName: fileName,\n            content: noteContent,\n            filePath: `Career-project-v1.0/02 - \u041f\u041e\u0418\u0421\u041a \u0420\u0410\u0411\u041e\u0422\u042b/01 - \u0412\u0430\u043a\u0430\u043d\u0441\u0438\u0438/${fileName}`,\n            vacancy: v\n        }\n    });\n}\n\nreturn result;"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1168,
        1072
      ],
      "id": "2f0f89c9-983c-4741-afb2-88412083ec42",
      "name": "\u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u0441 Obsidian Code in JavaScript1"
    },
    {
      "parameters": {
        "jsCode": "const items = $input.all();\nconst result = [];\n\nfor (const item of items) {\n    result.push({\n        json: item.json,\n        binary: {\n            data: {\n                data: Buffer.from(item.json.content, 'utf8'),\n                mimeType: 'text/markdown',\n                fileName: item.json.fileName\n            }\n        }\n    });\n}\n\nreturn result;"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1392,
        1072
      ],
      "id": "8260f1db-6560-4802-8b4c-4a88b464207a",
      "name": "\u041f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0432 \u0431\u0438\u043d\u0430\u0440\u043d\u044b\u0439 \u0444\u043e\u0440\u043c\u0430\u0442 Code in JavaScript"
    },
    {
      "parameters": {
        "jsCode": "const items = $input.all();\n\nfor (let i = 0; i < items.length; i++) {\n    console.log('=== Item', i, '===');\n    console.log('json.fileName:', items[i].json.fileName);\n    console.log('json.filePath:', items[i].json.filePath);\n    console.log('binary:', items[i].binary ? 'present' : 'missing');\n    if (items[i].binary) {\n        console.log('binary.data:', items[i].binary.data ? 'present' : 'missing');\n        console.log('binary.data.fileName:', items[i].binary.data?.fileName);\n    }\n}\n\nreturn items;"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1616,
        1072
      ],
      "id": "0ee7879e-eb07-49ff-9135-22cd75ce9bf6",
      "name": "Code in JavaScript1"
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {}
          ]
        }
      },
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.3,
      "position": [
        80,
        336
      ],
      "id": "c992a21d-84d9-4c8a-8e35-d86bdeae16d0",
      "name": "Schedule Trigger"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": false,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "27324b60-597a-4281-84f4-106a317f6672",
              "leftValue": "={{ $json.content }}",
              "rightValue": "\u0431\u0435\u0437 \u043e\u043f\u044b\u0442\u0430",
              "operator": {
                "type": "string",
                "operation": "contains"
              }
            },
            {
              "id": "0e08c5ff-207d-459e-ab6d-f65ccfd4c61c",
              "leftValue": "={{ $json.content }}",
              "rightValue": "\u041d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0439",
              "operator": {
                "type": "string",
                "operation": "contains"
              }
            },
            {
              "id": "641bea01-d7b5-41ac-a359-f61e0b6e2256",
              "leftValue": "={{ $json.content }}",
              "rightValue": "\u0441\u0442\u0430\u0436\u0435\u0440 project",
              "operator": {
                "type": "string",
                "operation": "contains"
              }
            },
            {
              "id": "0697eb7b-f966-401c-94ba-8ddfb97b75e1",
              "leftValue": "={{ $json.content }}",
              "rightValue": "\u043f\u043e\u043c\u043e\u0449\u043d\u0438\u043a \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432",
              "operator": {
                "type": "string",
                "operation": "contains"
              }
            },
            {
              "id": "5b49fdcd-00a4-4770-b455-9f0856091ea1",
              "leftValue": "={{ $json.content }}",
              "rightValue": "project manager",
              "operator": {
                "type": "string",
                "operation": "contains"
              }
            },
            {
              "id": "a8115d79-3cd1-4094-a85c-5f2dc5889705",
              "leftValue": "={{ $json.content }}",
              "rightValue": "\u0430\u0441\u0441\u0438\u0441\u0442\u0435\u043d\u0442",
              "operator": {
                "type": "string",
                "operation": "contains"
              }
            }
          ],
          "combinator": "or"
        },
        "options": {
          "ignoreCase": true
        }
      },
      "type": "n8n-nodes-base.filter",
      "typeVersion": 2.2,
      "position": [
        832,
        -240
      ],
      "id": "9e0b1ce1-80e8-4705-bc01-85fb7debb526",
      "name": "Filter \u043e\u043f\u044b\u0442 \u0440\u0430\u0431\u043e\u0442\u044b"
    },
    {
      "parameters": {
        "maxItems": 5
      },
      "type": "n8n-nodes-base.limit",
      "typeVersion": 1,
      "position": [
        1184,
        208
      ],
      "id": "bfd65729-60c7-4e89-abc2-5655731bfeea",
      "name": "Limit"
    },
    {
      "parameters": {
        "chatId": "673215399",
        "text": "={{ $json.message }}",
        "additionalFields": {
          "parse_mode": "Markdown"
        }
      },
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [
        1744,
        208
      ],
      "id": "67a7acb7-a21b-4b3b-9540-346e824f97b3",
      "name": "Send a text message",
      "executeOnce": true,
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": false,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "5aac1461-34f4-4dce-b2c5-72950ff0a2b6",
              "leftValue": "={{ $json.content }}",
              "rightValue": "\u0443\u0434\u0430\u043b\u0435\u043d\u043d\u043e",
              "operator": {
                "type": "string",
                "operation": "contains"
              }
            },
            {
              "id": "641bea01-d7b5-41ac-a359-f61e0b6e2256",
              "leftValue": "={{ $json.content }}",
              "rightValue": "\u0433\u0438\u0431\u0440\u0438\u0434",
              "operator": {
                "type": "string",
                "operation": "contains"
              }
            },
            {
              "id": "606c001a-19cb-4222-93fc-60cb3d392a58",
              "leftValue": "={{ $json.content }}",
              "rightValue": "\u041c\u043e\u0441\u043a\u0432\u0430",
              "operator": {
                "type": "string",
                "operation": "contains"
              }
            }
          ],
          "combinator": "or"
        },
        "options": {
          "ignoreCase": true
        }
      },
      "type": "n8n-nodes-base.filter",
      "typeVersion": 2.2,
      "position": [
        1024,
        -240
      ],
      "id": "5e67ed90-ca2b-4d98-acc0-77ee808cf276",
      "name": "Filter \u0444\u043e\u0440\u043c\u0430\u0442 \u0440\u0430\u0431\u043e\u0442\u044b"
    },
    {
      "parameters": {
        "jsCode": "const items = $input.all();\nconst result = [];\n\nfor (const item of items) {\n    const data = item.json;\n    \n    // \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u0447\u0442\u043e \u043e\u0442\u0432\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0432\u0430\u043a\u0430\u043d\u0441\u0438\u0438\n    if (data.items && Array.isArray(data.items)) {\n        for (const vacancy of data.items) {\n            // \u0424\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 \u0432\u0430\u043a\u0430\u043d\u0441\u0438\u0438 \u0432 \u0442\u043e\u043c \u0436\u0435 \u0444\u043e\u0440\u043c\u0430\u0442\u0435, \u0447\u0442\u043e \u0438 \u043e\u0442 \u0425\u0430\u0431\u0440\u0430\n            result.push({\n                json: {\n                    title: vacancy.name,\n                    description: vacancy.snippet?.requirement || vacancy.snippet?.responsibility || '',\n                    author: vacancy.employer?.name || '\u041d\u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u0430',\n                    link: vacancy.alternate_url,\n                    id: vacancy.id,\n                    city: vacancy.area?.name || '',\n                    salary: vacancy.salary ? `${vacancy.salary.from || ''} ${vacancy.salary.to || ''} ${vacancy.salary.currency || ''}`.trim() : '\u043d\u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u0430',\n                    content: (vacancy.name + ' ' + (vacancy.snippet?.requirement || '') + ' ' + (vacancy.snippet?.responsibility || '')).toLowerCase(),\n                    source: 'hh.ru'\n                }\n            });\n        }\n    }\n}\n\nreturn result;"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        624,
        512
      ],
      "id": "c57f9b0d-db8f-42b8-9f30-aaf049afd908",
      "name": "Code in JavaScript3"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": false,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "27324b60-597a-4281-84f4-106a317f6672",
              "leftValue": "={{ $json.content }}",
              "rightValue": "\u0431\u0435\u0437 \u043e\u043f\u044b\u0442\u0430",
              "operator": {
                "type": "string",
                "operation": "contains"
              }
            },
            {
              "id": "0e08c5ff-207d-459e-ab6d-f65ccfd4c61c",
              "leftValue": "={{ $json.content }}",
              "rightValue": "\u041d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0439",
              "operator": {
                "type": "string",
                "operation": "contains"
              }
            },
            {
              "id": "641bea01-d7b5-41ac-a359-f61e0b6e2256",
              "leftValue": "={{ $json.content }}",
              "rightValue": "\u0441\u0442\u0430\u0436\u0435\u0440 project",
              "operator": {
                "type": "string",
                "operation": "contains"
              }
            },
            {
              "id": "0697eb7b-f966-401c-94ba-8ddfb97b75e1",
              "leftValue": "={{ $json.content }}",
              "rightValue": "\u043f\u043e\u043c\u043e\u0449\u043d\u0438\u043a \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432",
              "operator": {
                "type": "string",
                "operation": "contains"
              }
            },
            {
              "id": "5b49fdcd-00a4-4770-b455-9f0856091ea1",
              "leftValue": "={{ $json.content }}",
              "rightValue": "project manager",
              "operator": {
                "type": "string",
                "operation": "contains"
              }
            },
            {
              "id": "a8115d79-3cd1-4094-a85c-5f2dc5889705",
              "leftValue": "={{ $json.content }}",
              "rightValue": "\u0430\u0441\u0441\u0438\u0441\u0442\u0435\u043d\u0442",
              "operator": {
                "type": "string",
                "operation": "contains"
              }
            }
          ],
          "combinator": "or"
        },
        "options": {
          "ignoreCase": true
        }
      },
      "type": "n8n-nodes-base.filter",
      "typeVersion": 2.2,
      "position": [
        832,
        512
      ],
      "id": "bf86f3cd-9b0e-43e3-9b28-f3de39604f60",
      "name": "Filter \u043e\u043f\u044b\u0442 \u0440\u0430\u0431\u043e\u0442\u044b1"
    },
    {
      "parameters": {},
      "type": "n8n-nodes-base.merge",
      "typeVersion": 3.2,
      "position": [
        416,
        208
      ],
      "id": "c76b0e9d-f87c-44a5-9165-dfe53c0375ea",
      "name": "Merge"
    },
    {
      "parameters": {
        "url": "https://career.habr.com/vacancies/rss",
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "q",
              "value": "project manager \u043f\u043e\u043c\u043e\u0449\u043d\u0438\u043a \u043c\u043b\u0430\u0434\u0448\u0438\u0439 \u0441\u0442\u0430\u0436\u0435\u0440"
            }
          ]
        },
        "options": {
          "batching": {
            "batch": {
              "batchSize": 1
            }
          },
          "response": {
            "response": {
              "responseFormat": "text"
            }
          }
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        432,
        -240
      ],
      "id": "0418e733-8765-4476-80c2-899e3411b5cd",
      "name": "HTTP Request \u0425\u0430\u0431\u0440",
      "notesInFlow": false
    },
    {
      "parameters": {
        "url": "https://api.hh.ru/vacancies",
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "text",
              "value": "project manager \u043f\u043e\u043c\u043e\u0449\u043d\u0438\u043a \u043c\u043b\u0430\u0434\u0448\u0438\u0439 \u0441\u0442\u0430\u0436\u0435\u0440"
            }
          ]
        },
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "User-Agent",
              "value": "MyVacancyBot/1.0 (Avramenkovi07@gmail.com)"
            }
          ]
        },
        "options": {
          "response": {
            "response": {
              "responseFormat": "json"
            }
          }
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        416,
        512
      ],
      "id": "9cec67c1-3ab2-4b15-8bd8-b5e98cd09551",
      "name": "HTTP Request3 hh"
    },
    {
      "parameters": {
        "url": "https://api.hh.ru/vacancies",
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "text",
              "value": "project manager \u043f\u043e\u043c\u043e\u0449\u043d\u0438\u043a \u0441\u0442\u0430\u0436\u0435\u0440 \u043c\u043b\u0430\u0434\u0448\u0438\u0439 \u0430\u0441\u0441\u0438\u0441\u0442\u0435\u043d\u0442"
            },
            {
              "name": "area",
              "value": "1"
            },
            {
              "name": "experience",
              "value": "noExperience"
            },
            {
              "name": "employment",
              "value": "full"
            },
            {
              "name": "schedule",
              "value": "remote"
            },
            {
              "name": "per_page",
              "value": "20"
            }
          ]
        },
        "options": {
          "response": {
            "response": {
              "responseFormat": "json"
            }
          }
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        304,
        1072
      ],
      "id": "c57e6ca6-3076-4cee-a0cf-87f9695abb51",
      "name": "HTTP Request"
    },
    {
      "parameters": {
        "jsCode": "// \u041a\u043e\u0434 \u0434\u043b\u044f Node \"Code\"\nconst items = $input.all();\nconst newItems = [];\n\n// \u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u0441\u043b\u043e\u0432\u0430 \u0434\u043b\u044f \u0440\u0430\u043d\u0436\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f (\u0447\u0435\u043c \u0431\u043e\u043b\u044c\u0448\u0435, \u0442\u0435\u043c \u043b\u0443\u0447\u0448\u0435)\nconst keywords = [\n    '\u0438\u0438', '\u043d\u0435\u0439\u0440\u043e\u0441\u0435\u0442', '\u0438\u0441\u043a\u0443\u0441\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u043b\u043b\u0435\u043a\u0442', 'gpt', // AI\n    'no-code', 'nocode', 'low-code', // No-code\n    '\u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446', '\u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446', '\u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442', // \u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u044f\n    '\u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d', 'project', 'pm', 'agile', 'scrum', '\u043a\u0430\u043d\u0431\u0430\u043d', // \u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435\n    '\u0441\u0442\u0430\u0436\u0435\u0440', '\u043f\u043e\u043c\u043e\u0449\u043d\u0438\u043a', '\u043c\u043b\u0430\u0434\u0448\u0438\u0439', 'junior', 'trainee' // \u0414\u0443\u0431\u043b\u0435\u0440\u044b \u043f\u043e\u0437\u0438\u0446\u0438\u0438\n];\n\nfor (const item of items) {\n    let rating = 0;\n    const content = item.json.content ? item.json.content.toLowerCase() : '';\n    const title = item.json.title ? item.json.title.toLowerCase() : '';\n\n    // \u0418\u0449\u0435\u043c \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u0441\u043b\u043e\u0432\u0430 \u0432 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0438 \u0438 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0438\n    for (const word of keywords) {\n        // \u0414\u0430\u0435\u043c \u0431\u043e\u043b\u044c\u0448\u0435 \u0431\u0430\u043b\u043b\u043e\u0432 \u0437\u0430 \u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u0435 \u0432 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0438\n        if (title.includes(word)) {\n            rating += 3;\n        } else if (content.includes(word)) {\n            rating += 1;\n        }\n    }\n\n    // \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0440\u0435\u0439\u0442\u0438\u043d\u0433 \u0432 \u0434\u0430\u043d\u043d\u044b\u0435\n    newItems.push({\n        json: {\n            ...item.json,\n            rating: rating // \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043f\u043e\u043b\u0435 \u0441 \u0440\u0435\u0439\u0442\u0438\u043d\u0433\u043e\u043c\n        }\n    });\n}\n\n// \u0421\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u043f\u043e \u0443\u0431\u044b\u0432\u0430\u043d\u0438\u044e \u0440\u0435\u0439\u0442\u0438\u043d\u0433\u0430 (\u043e\u0442 \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u043a \u043c\u0435\u043d\u044c\u0448\u0438\u043c)\nnewItems.sort((a, b) => b.json.rating - a.json.rating);\n\nreturn newItems;"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        736,
        1072
      ],
      "id": "85c536b2-52ca-4c95-93b9-c75a854205db",
      "name": "Code in JavaScript \u0420\u0430\u043d\u0436\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u04352"
    },
    {
      "parameters": {
        "jsCode": "// \u041a\u043e\u0434 \u0434\u043b\u044f \u0440\u0430\u043d\u0436\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0432\u0430\u043a\u0430\u043d\u0441\u0438\u0439 hh.ru\nconst items = $input.all();\nconst newItems = [];\n\n// \u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u0441\u043b\u043e\u0432\u0430 \u0434\u043b\u044f \u0440\u0430\u043d\u0436\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f (\u0442\u0435 \u0436\u0435, \u0447\u0442\u043e \u0438 \u0434\u043b\u044f \u0425\u0430\u0431\u0440\u0430)\nconst keywords = [\n    '\u0438\u0438', '\u043d\u0435\u0439\u0440\u043e\u0441\u0435\u0442', '\u0438\u0441\u043a\u0443\u0441\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u043b\u043b\u0435\u043a\u0442', 'gpt', // AI\n    'no-code', 'nocode', 'low-code', // No-code\n    '\u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446', '\u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446', '\u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442', // \u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u044f\n    '\u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d', 'project', 'pm', 'agile', 'scrum', '\u043a\u0430\u043d\u0431\u0430\u043d', // \u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435\n    '\u0441\u0442\u0430\u0436\u0435\u0440', '\u043f\u043e\u043c\u043e\u0449\u043d\u0438\u043a', '\u043c\u043b\u0430\u0434\u0448\u0438\u0439', 'junior', 'trainee', '\u0430\u0441\u0441\u0438\u0441\u0442\u0435\u043d\u0442' // \u0414\u0443\u0431\u043b\u0435\u0440\u044b \u043f\u043e\u0437\u0438\u0446\u0438\u0438\n];\n\nfor (const item of items) {\n    let rating = 0;\n    \n    // \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 item.json (\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u043e\u0441\u043b\u0435 \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430 hh.ru)\n    const title = item.json.title ? item.json.title.toLowerCase() : '';\n    const description = item.json.description ? item.json.description.toLowerCase() : '';\n    const content = (title + ' ' + description).toLowerCase();\n    \n    // \u0418\u0449\u0435\u043c \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u0441\u043b\u043e\u0432\u0430 \u0432 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0438 \u0438 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0438\n    for (const word of keywords) {\n        // \u0414\u0430\u0435\u043c \u0431\u043e\u043b\u044c\u0448\u0435 \u0431\u0430\u043b\u043b\u043e\u0432 \u0437\u0430 \u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u0435 \u0432 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0438\n        if (title.includes(word)) {\n            rating += 3;\n        } \n        // \u0418\u0449\u0435\u043c \u0432 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0438\n        if (description.includes(word)) {\n            rating += 1;\n        }\n    }\n    \n    // \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0440\u0435\u0439\u0442\u0438\u043d\u0433 \u0432 \u0434\u0430\u043d\u043d\u044b\u0435\n    newItems.push({\n        json: {\n            ...item.json,\n            rating: rating\n        }\n    });\n}\n\n// \u0421\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u043f\u043e \u0443\u0431\u044b\u0432\u0430\u043d\u0438\u044e \u0440\u0435\u0439\u0442\u0438\u043d\u0433\u0430\nnewItems.sort((a, b) => b.json.rating - a.json.rating);\n\nreturn newItems;"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        512,
        1072
      ],
      "id": "fbd51649-f448-4f2a-9715-d323981506a6",
      "name": "Code in JavaScript \u0420\u0430\u043d\u0436\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u04353"
    },
    {
      "parameters": {
        "url": "https://api.hh.ru/vacancies",
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "text",
              "value": "junior project manager"
            }
          ]
        },
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "User-Agent",
              "value": "MyCareerBot/1.0 (Avramenkovi07@gmail.com)"
            }
          ]
        },
        "options": {
          "response": {
            "response": {
              "responseFormat": "json"
            }
          }
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        96,
        1072
      ],
      "id": "cbf5ea9d-6582-4bf9-bd70-c671756afe45",
      "name": "HH Test"
    },
    {
      "parameters": {
        "operation": "write",
        "fileName": "=test.md\n",
        "options": {
          "append": false
        }
      },
      "type": "n8n-nodes-base.readWriteFile",
      "typeVersion": 1.1,
      "position": [
        976,
        1072
      ],
      "id": "fd62b6f9-0bc2-47a2-9fd9-e98d9f0b4cfd",
      "name": "Read/Write Files from Disk"
    },
    {
      "parameters": {
        "operation": "createFromText",
        "content": "={{$json.content}}",
        "name": "={{$json.fileName}}",
        "driveId": {
          "__rl": true,
          "value": "My Drive",
          "mode": "list",
          "cachedResultName": "My Drive",
          "cachedResultUrl": "https://drive.google.com/drive/my-drive"
        },
        "folderId": {
          "__rl": true,
          "value": "1_k0IoJeVzf124hO5MPg-oV75Kv-Djfo4",
          "mode": "id"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        1616,
        512
      ],
      "id": "b30093a5-9bb9-4fe9-9abf-7ca9730ed7db",
      "name": "Create file from text",
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430 XML \u0432 JSON (\u0440\u0443\u0447\u043d\u043e\u0439 \u043f\u0430\u0440\u0441\u0435\u0440)\nfunction parseXMLToJSON(xmlText) {\n    const result = {\n        items: []\n    };\n    \n    try {\n        // \u0418\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u043c \u0432\u0441\u0435 item'\u044b \u0438\u0437 XML\n        const itemRegex = /<item>([\\s\\S]*?)<\\/item>/g;\n        const items = [];\n        let match;\n        \n        while ((match = itemRegex.exec(xmlText)) !== null) {\n            items.push(match[1]);\n        }\n        \n        // \u041f\u0430\u0440\u0441\u0438\u043c \u043a\u0430\u0436\u0434\u044b\u0439 item\n        for (const itemXml of items) {\n            const item = {};\n            \n            // \u0418\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u043c title\n            const titleMatch = itemXml.match(/<title>([\\s\\S]*?)<\\/title>/);\n            if (titleMatch) item.title = titleMatch[1].replace(/<!\\[CDATA\\[|\\]\\]>/g, '').trim();\n            \n            // \u0418\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u043c description\n            const descMatch = itemXml.match(/<description>([\\s\\S]*?)<\\/description>/);\n            if (descMatch) item.description = descMatch[1].replace(/<!\\[CDATA\\[|\\]\\]>/g, '').trim();\n            \n            // \u0418\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u043c author\n            const authorMatch = itemXml.match(/<author>([\\s\\S]*?)<\\/author>/);\n            if (authorMatch) item.author = authorMatch[1].replace(/<!\\[CDATA\\[|\\]\\]>/g, '').trim();\n            \n            // \u0418\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u043c link\n            const linkMatch = itemXml.match(/<link>([\\s\\S]*?)<\\/link>/);\n            if (linkMatch) item.link = linkMatch[1].trim();\n            \n            // \u0418\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u043c guid (\u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 ID)\n            const guidMatch = itemXml.match(/<guid>([\\s\\S]*?)<\\/guid>/);\n            if (guidMatch) item.id = guidMatch[1].trim();\n            \n            // \u0418\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u043c pubDate\n            const dateMatch = itemXml.match(/<pubDate>([\\s\\S]*?)<\\/pubDate>/);\n            if (dateMatch) item.pubDate = dateMatch[1].trim();\n            \n            // \u0418\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u043c \u0433\u043e\u0440\u043e\u0434 \u0438\u0437 title \u0438\u043b\u0438 description\n            const cityMatch = item.title?.match(/\\((.*?)\\)/) || item.description?.match(/\\((.*?)\\)/);\n            if (cityMatch) item.city = cityMatch[1];\n            \n            // \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0435\u043d\u0442 \u0434\u043b\u044f \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u0438\n            item.content = (item.title || '') + ' ' + (item.description || '');\n            \n            result.items.push(item);\n        }\n    } catch (e) {\n        console.error('\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430 XML:', e);\n    }\n    \n    return result;\n}\n\n// \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0432\u0445\u043e\u0434\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435\nconst inputData = $input.all();\n\n// \u0417\u0434\u0435\u0441\u044c \u0431\u0443\u0434\u0435\u0442 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\nlet allVacancies = [];\n\n// \u041e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u043a\u0430\u0436\u0434\u044b\u0439 \u0432\u0445\u043e\u0434\u043d\u043e\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\nfor (const item of inputData) {\n    // \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c XML \u0442\u0435\u043a\u0441\u0442 \u0438\u0437 \u043f\u043e\u043b\u044f data\n    const xmlText = item.json.data;\n    \n    if (xmlText && typeof xmlText === 'string') {\n        // \u041f\u0430\u0440\u0441\u0438\u043c XML \u0432 JSON\n        const parsed = parseXMLToJSON(xmlText);\n        allVacancies = allVacancies.concat(parsed.items);\n    }\n}\n\n// \u041f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u043c \u043c\u0430\u0441\u0441\u0438\u0432 \u0432\u0430\u043a\u0430\u043d\u0441\u0438\u0439 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442, \u043f\u043e\u043d\u044f\u0442\u043d\u044b\u0439 n8n\nreturn allVacancies.map(vacancy => ({ json: vacancy }));"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        624,
        -240
      ],
      "id": "f1a99ea5-2b60-4491-9797-18a35d8937bb",
      "name": "\u041a\u043e\u0434 \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430 \u0425\u0430\u0431\u0440 Code in JavaScript"
    },
    {
      "parameters": {
        "jsCode": "return $input.all().map(item => {\n  const v = item.json;\n  const createdAt = new Date().toISOString().split('T')[0];\n  // \u0427\u0438\u0441\u0442\u0438\u043c \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u043e\u0442 \u0441\u043f\u0435\u0446\u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432 \u0434\u043b\u044f \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 \u0438\u043c\u0435\u043d\u0438 \u0444\u0430\u0439\u043b\u0430\n  const cleanTitle = (v.title || v.role || 'vacancy').replace(/[/\\\\?%*:|\"<>\u00ab\u00bb]/g, '');\n  // \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0435 \u0438\u043c\u044f \u0444\u0430\u0439\u043b\u0430\n  item.json.fileName = `\u0422\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f ${cleanTitle} - ${createdAt}.md`;\n  return item;\n});\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        624,
        208
      ],
      "id": "e743609f-6d59-411a-9250-097e095f1ca6",
      "name": "Code in JavaScript Deduplication"
    },
    {
      "parameters": {
        "jsCode": "// \u0423\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0439 \u043a\u043e\u0434 \u0440\u0430\u043d\u0436\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u043b\u044f \u043b\u044e\u0431\u044b\u0445 \u0432\u0430\u043a\u0430\u043d\u0441\u0438\u0439\nconst items = $(\"Code in JavaScript Deduplication\").all();\nconst newItems = [];\n\nconst keywords = [\n    '\u0438\u0438', '\u043d\u0435\u0439\u0440\u043e\u0441\u0435\u0442', '\u0438\u0441\u043a\u0443\u0441\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u043b\u043b\u0435\u043a\u0442', 'gpt',\n    'no-code', 'nocode', 'low-code',\n    '\u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446', '\u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446', '\u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442',\n    '\u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d', 'project', 'pm', 'agile', 'scrum', '\u043a\u0430\u043d\u0431\u0430\u043d',\n    '\u0441\u0442\u0430\u0436\u0435\u0440', '\u043f\u043e\u043c\u043e\u0449\u043d\u0438\u043a', '\u043c\u043b\u0430\u0434\u0448\u0438\u0439', 'junior', 'trainee', '\u0430\u0441\u0441\u0438\u0441\u0442\u0435\u043d\u0442'\n];\n\nfor (const item of items) {\n    let rating = 0;\n    \n    // \u0423\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0442\u0435\u043a\u0441\u0442\u0430 \u0434\u043b\u044f \u0430\u043d\u0430\u043b\u0438\u0437\u0430\n    let fullText = '';\n    \n    // \u0415\u0441\u043b\u0438 \u0435\u0441\u0442\u044c \u043f\u043e\u043b\u0435 content (\u043a\u0430\u043a \u0443 \u0425\u0430\u0431\u0440\u0430)\n    if (item.json.content) {\n        fullText = item.json.content.toLowerCase();\n    } \n    // \u0415\u0441\u043b\u0438 \u0435\u0441\u0442\u044c title \u0438 description (\u043a\u0430\u043a \u0443 hh.ru)\n    else {\n        const title = item.json.title ? item.json.title.toLowerCase() : '';\n        const description = item.json.description ? item.json.description.toLowerCase() : '';\n        fullText = title + ' ' + description;\n    }\n    \n    // \u0410\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u0442\u0435\u043a\u0441\u0442\n    for (const word of keywords) {\n        if (fullText.includes(word)) {\n            // \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u0435\u0441\u0442\u044c \u043b\u0438 \u0441\u043b\u043e\u0432\u043e \u0432 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0438 (\u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0431\u043e\u043d\u0443\u0441)\n            const title = item.json.title ? item.json.title.toLowerCase() : '';\n            if (title.includes(word)) {\n                rating += 3;\n            } else {\n                rating += 1;\n            }\n        }\n    }\n    \n    newItems.push({\n        json: {\n            ...item.json, // \u0412\u043e\u0442 \u044d\u0442\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442 \u0438 id, \u0438 row_index, \u0438 \u0432\u0441\u0451 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0435\n            rating: rating\n        }\n    });\n}\n\nnewItems.sort((a, b) => b.json.rating - a.json.rating);\n\nreturn newItems;"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        976,
        208
      ],
      "id": "ac370298-8eed-44a5-b47a-17aaadf6a1cd",
      "name": "Code in JavaScript Ranging"
    },
    {
      "parameters": {
        "jsCode": "// \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u044d\u043a\u0440\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u043f\u0435\u0446\u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432 MarkdownV2\nfunction escapeMarkdown(text) {\n  if (!text) return '';\n  const specialChars = ['_', '*', '[', ']', '(', ')', '~', '`', '>', '#', '+', '-', '=', '|', '{', '}', '.', '!'];\n  let escaped = String(text);\n  for (const char of specialChars) {\n    escaped = escaped.replace(new RegExp('\\\\' + char, 'g'), '\\\\' + char);\n  }\n  return escaped;\n}\n\n// 1. \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0422\u041e\u041f-5 \u0432\u0430\u043a\u0430\u043d\u0441\u0438\u0439 \u043f\u043e\u0441\u043b\u0435 \u0440\u0430\u043d\u0436\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f\nconst allItems = $(\"Code in JavaScript Ranging\").all();\n\n// 2. \u0424\u0438\u043b\u044c\u0442\u0440\u0443\u0435\u043c: \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u041d\u0415\u0422 \u0432 \u0431\u0430\u0437\u0435 (\u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0447\u0435\u0440\u0435\u0437 \u0443\u0437\u0435\u043b IF)\n// \u041c\u044b \u0438\u0449\u0435\u043c \u0432\u0430\u043a\u0430\u043d\u0441\u0438\u0438, \u0433\u0434\u0435 row_index \u043d\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d (\u0437\u043d\u0430\u0447\u0438\u0442 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0435 \u0438\u0445 \u043d\u0435 \u043d\u0430\u0448\u043b\u0438)\nconst newItems = allItems.filter(item => {\n  try {\n    // \u041f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0441 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0432 \u0443\u0437\u043b\u0435 IF\n    // \u0415\u0441\u043b\u0438 \u0432 IF \u0434\u043b\u044f \u044d\u0442\u043e\u0439 \u0432\u0430\u043a\u0430\u043d\u0441\u0438\u0438 row_index \u043f\u0443\u0441\u0442\u043e\u0439 \u2014 \u043e\u043d\u0430 \u043d\u043e\u0432\u0430\u044f\n    return !item.json.row_index; \n  } catch (e) {\n    return true; // \u0415\u0441\u043b\u0438 \u0447\u0442\u043e-\u0442\u043e \u043f\u043e\u0448\u043b\u043e \u043d\u0435 \u0442\u0430\u043a, \u043b\u0443\u0447\u0448\u0435 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0432\u0430\u043a\u0430\u043d\u0441\u0438\u044e\n  }\n});\n\n// \u0415\u0441\u043b\u0438 \u041d\u041e\u0412\u042b\u0425 \u0432\u0430\u043a\u0430\u043d\u0441\u0438\u0439 \u043d\u0435\u0442, \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0433\u0440\u0443\u0441\u0442\u043d\u044b\u0439 \u0441\u043c\u0430\u0439\u043b\u0438\u043a\nconst items = $input.all();\n// \u0415\u0441\u043b\u0438 \u044d\u0442\u043e \u043d\u0430\u0448\u0430 \"\u0437\u0430\u0433\u043b\u0443\u0448\u043a\u0430\"\nif (items[0].json.isNew === false) {\n  return [{\n    json: {\n      message: \"\ud83d\ude14 *\u0421\u0435\u0433\u043e\u0434\u043d\u044f \u043d\u043e\u0432\u044b\u0445 \u0432\u0430\u043a\u0430\u043d\u0441\u0438\u0439 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u043e\\\\.*\\n\u041e\u0442\u0434\u044b\u0445\u0430\u0435\u043c \u0438 \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0441\u0438\u043b\u044b\\\\!\"\n    }\n  }];\n}\n\n// \u0424\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u0442\u0435\u043a\u0441\u0442 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\nlet messageText = \"\ud83d\ude80 *\u0414\u0430\u0439\u0434\u0436\u0435\u0441\u0442 \u043d\u043e\u0432\u044b\u0445 \u0432\u0430\u043a\u0430\u043d\u0441\u0438\u0439 \" + escapeMarkdown(new Date().toLocaleDateString('ru-RU')) + \"*\\n\\n\";\n\nfor (let i = 0; i < newItems.length; i++) {\n  const item = newItems[i].json;\n  const title = escapeMarkdown(item.title || '\u0411\u0435\u0437 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f');\n  const author = escapeMarkdown(item.author || '\u041d\u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u0430');\n  let description = escapeMarkdown(item.content || item.description || '');\n  \n  description = description.replace(/\\n/g, ' ').substring(0, 150);\n  if (description.length === 150) description += '...';\n\n  messageText += `*${i + 1}\\\\. ${title}*\\n`;\n  messageText += `\ud83c\udfe2 ${author}\\n`;\n  messageText += `\u2b50 \u0420\u0435\u0439\u0442\u0438\u043d\u0433: ${item.rating || 0}\\n`;\n  messageText += `\ud83d\udcdd ${description}\\n`;\n\n  if (item.source === 'hh.ru') {\n    messageText += `\ud83d\udccc \u0418\u0441\u0442\u043e\u0447\u043d\u0438\u043a: HeadHunter\\n`;\n  } else {\n    messageText += `\ud83d\udccc \u0418\u0441\u0442\u043e\u0447\u043d\u0438\u043a: \u0425\u0430\u0431\u0440 \u041a\u0430\u0440\u044c\u0435\u0440\u0430\\n`;\n  }\n\n  const link = item.link || '';\n  messageText += `\ud83d\udd17 [\u041f\u0435\u0440\u0435\u0439\u0442\u0438 \u043a \u0432\u0430\u043a\u0430\u043d\u0441\u0438\u0438](${link})\\n`;\n\n  if (i < newItems.length - 1) {\n    messageText += `\\n---\\n\\n`;\n  }\n}\n\nreturn [{ json: { message: messageText } }];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1568,
        208
      ],
      "id": "287f0d65-9c72-414d-aa21-c99d976d14b0",
      "name": "Code in JavaScript2 Forming a message"
    },
    {
      "parameters": {
        "jsCode": "// 1. \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u0432\u0445\u043e\u0434\u044f\u0449\u0435\u0433\u043e \u0443\u0437\u043b\u0430\nconst items = $(\"Code in JavaScript Deduplication\").all();\nconst result = [];\n\n// --- \u0412\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 ---\nfunction formatDate(date) {\n  const d = new Date(date);\n  return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;\n}\n\nfunction getEmploymentType(employment) {\n  const map = { 'full': 'fulltime', 'part': 'parttime', 'intern': 'intern', 'project': 'fulltime' };\n  return map[(employment || '').toLowerCase()] || 'fulltime';\n}\n\nfunction getSource(source) {\n  if (source === 'hh.ru') return 'hh';\n  if (source === '\u0425\u0430\u0431\u0440 \u041a\u0430\u0440\u044c\u0435\u0440\u0430') return 'habr';\n  return source || 'unknown';\n}\n\nfunction getMatchReason(title, content, rating) {\n  const reasons = [];\n  const t = (title || '').toLowerCase();\n  const c = (content || '').toLowerCase();\n  const keywords = {\n    'AI/\u043d\u0435\u0439\u0440\u043e\u0441\u0435\u0442\u0438': ['\u0438\u0438', '\u043d\u0435\u0439\u0440\u043e\u0441\u0435\u0442', 'gpt', 'ai'],\n    'no-code/low-code': ['no-code', 'low-code'],\n    '\u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u044f': ['\u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446', '\u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446'],\n    '\u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u043c\u0438': ['project', 'pm', 'agile', 'scrum']\n  };\n  for (const [cat, words] of Object.entries(keywords)) {\n    for (const w of words) {\n      if (t.includes(w)) { reasons.push(`${cat} (+3 \u0431\u0430\u043b\u043b\u0430)`); break; }\n      else if (c.includes(w)) { reasons.push(`${cat} (+1 \u0431\u0430\u043b\u043b)`); break; }\n    }\n  }\n  return reasons.length === 0 ? `\u0420\u0435\u0439\u0442\u0438\u043d\u0433: ${rating}` : `\u0420\u0435\u0439\u0442\u0438\u043d\u0433: ${rating}\\n\\n\u2705 ${reasons.slice(0, 3).join('\\n\u2705 ')}`;\n}\n\n// 2. \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0446\u0438\u043a\u043b \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438\nfor (const item of items) {\n  const v = item.json;\n  const createdAt = formatDate(new Date());\n  \n  // \u041e\u0447\u0438\u0441\u0442\u043a\u0430 \u0438\u043c\u0435\u043d \u0434\u043b\u044f \u0444\u0430\u0439\u043b\u043e\u0432\n  const safeRole = (v.title || '\u0412\u0430\u043a\u0430\u043d\u0441\u0438\u044f').replace(/[<>:\"/\\\\|?*]/g, '').trim().substring(0, 50);\n  const safeCompany = (v.author || '\u041d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0430\u044f \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u044f').replace(/[<>:\"/\\\\|?*]/g, '').trim().substring(0, 30);\n  const dateStr = createdAt.split('-').reverse().join('-');\n  const fileName = `${safeRole} - ${safeCompany} - ${dateStr}.md`;\n\n  // \u0424\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u0442\u0435\u043a\u0441\u0442 \u0437\u0430\u043c\u0435\u0442\u043a\u0438\n  const noteContent = `---\ncompany: ${safeCompany}\nrole: ${safeRole}\nstatus: \u0432_\u0430\u043d\u0430\u043b\u0438\u0437\u0435\nsalary: ${v.salary || ''}\nlink: ${v.link || ''}\nexternal_id: ${v.id || ''}\ndeadline: \nsource: ${getSource(v.source)}\nlocation: ${v.city || ''}\nemployment_type: ${getEmploymentType(v.employment_type)}\nparsedByBot: false\nmatchScore: ${v.rating || 0}\ntags: vacancy\ncreatedAt: ${createdAt}\n---\n\n**\u041a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0439:**\n- [ ] \u0420\u0430\u0437\u0431\u043e\u0440 \u0432\u0430\u043a\u0430\u043d\u0441\u0438\u0438 \u043f\u0440\u043e\u0432\u0435\u0434\u0451\u043d?\n\n**\u041f\u043e\u0447\u0435\u043c\u0443 \u0431\u043e\u0442 \u0432\u044b\u0431\u0440\u0430\u043b \u044d\u0442\u0443 \u0432\u0430\u043a\u0430\u043d\u0441\u0438\u044e**\n${getMatchReason(v.title, v.content, v.rating || 0)}\n\n**\u0421\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0435 \u0437\u0430\u043c\u0435\u0442\u043a\u0438:**\n- [[\ud83d\ude80\u00ab\u041f\u0440\u043e\u0435\u043a\u0442\u00ab\u041a\u0430\u0440\u044c\u0435\u0440\u0430\u00bbv1.0\u00bb-\u041a\u043e\u043c\u0430\u043d\u0434\u043d\u044b\u0439 \u043f\u0443\u043d\u043a\u0442]]\n- [[\u0414\u0430\u0448\u0431\u043e\u0440\u0434-\u0412\u0430\u043a\u0430\u043d\u0441\u0438\u0438 \u043f\u043e \u0441\u0442\u0430\u0442\u0443\u0441\u0443]]`;\n\n  // 3. \u0412\u041e\u0417\u0412\u0420\u0410\u0429\u0410\u0415\u041c \u0420\u0415\u0417\u0423\u041b\u042c\u0422\u0410\u0422 (\u0412\u0430\u0436\u043d\u043e: \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u0432\u0441\u0435 \u043f\u043e\u043b\u044f \u0447\u0435\u0440\u0435\u0437 v)\n  result.push({\n    json: {\n      ...v,              // \u041f\u0440\u043e\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0435\u043c \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 ID \u0438 \u0432\u0441\u0435 \u043f\u043e\u043b\u044f \u0434\u0430\u043b\u044c\u0448\u0435\n      ...item.json, // \u0412\u043e\u0442 \u044d\u0442\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442 \u0438 id, \u0438 row_index, \u0438 \u0432\u0441\u0451 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0435\n      fileName: fileName,\n      content: noteContent\n    }\n  });\n}\n\nreturn result;\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1264,
        512
      ],
      "id": "5fc5e3df-b651-4f98-b870-e7777e8e1d29",
      "name": "Code in JavaScript Obsidian Formation"
    },
    {
      "parameters": {
        "jsCode": "const items = $input.all();\nconst result = [];\n\nfor (const item of items) {\n    result.push({\n        json: item.json,\n        binary: {\n            data: {\n                data: Buffer.from(item.json.content, 'utf8'),\n                mimeType: 'text/markdown',\n                fileName: item.json.fileName\n            }\n        }\n    });\n}\n\nreturn result;"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1440,
        512
      ],
      "id": "bff51d9f-64a1-4f99-8392-97cb8e58fbc7",
      "name": "Code in JavaScript binary format"
    },
    {
      "parameters": {
        "authentication": "serviceAccount",
        "documentId": {
          "__rl": true,
          "value": "1FMNVnZKyA7cPIBlsEQz4eRlRqYD-zwHtbHz9vBnVuh4",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "\u041b\u0438\u0441\u04421",
          "mode": "name"
        },
        "filtersUI": {
          "values": [
            {
              "lookupColumn": "vacancy_id",
              "lookupValue": "={{ Number($json.id) }}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.7,
      "position": [
        816,
        80
      ],
      "id": "d7f9f503-f322-4bc2-a9b5-1b63df2d6df5",
      "name": "Get row(s) in sheet Examination",
      "alwaysOutputData": true,
      "executeOnce": true,
      "credentials": {
        "googleApi": {
          "name": "<your credential>"
        }
      },
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "authentication": "serviceAccount",
        "operation": "append",
        "documentId": {
          "__rl": true,
          "value": "1FMNVnZKyA7cPIBlsEQz4eRlRqYD-zwHtbHz9vBnVuh4",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "\u041b\u0438\u0441\u04421",
          "mode": "name"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "vacancy_id": "={{ $('Code in JavaScript Deduplication').first().json.id }}"
          },
          "matchingColumns": [
            "vacancy_id"
          ],
          "schema": [
            {
              "id": "vacancy_id",
              "displayName": "vacancy_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.7,
      "position": [
        1792,
        512
      ],
      "id": "8b9bebec-f1f9-4457-9040-3ad40614e382",
      "name": "Append row in sheet",
      "credentials": {
        "googleApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "46692f0f-7a77-45dd-aa74-39a674cff8d3",
              "leftValue": "={{ $json.row_index }}",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "empty",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        704,
        1264
      ],
      "id": "5c4d0bff-fca9-4dc0-9699-e94e61759d7f",
      "name": "If"
    },
    {
      "parameters": {
        "jsCode": "// \u0423\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0439 \u043a\u043e\u0434 \u0440\u0430\u043d\u0436\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u043b\u044f \u043b\u044e\u0431\u044b\u0445 \u0432\u0430\u043a\u0430\u043d\u0441\u0438\u0439\nconst items = $(\"Code in JavaScript Deduplication\").all();\nconst newItems = [];\n\nconst keywords = [\n    '\u0438\u0438', '\u043d\u0435\u0439\u0440\u043e\u0441\u0435\u0442', '\u0438\u0441\u043a\u0443\u0441\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u043b\u043b\u0435\u043a\u0442', 'gpt',\n    'no-code', 'nocode', 'low-code',\n    '\u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446', '\u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446', '\u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442',\n    '\u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d', 'project', 'pm', 'agile', 'scrum', '\u043a\u0430\u043d\u0431\u0430\u043d',\n    '\u0441\u0442\u0430\u0436\u0435\u0440', '\u043f\u043e\u043c\u043e\u0449\u043d\u0438\u043a', '\u043c\u043b\u0430\u0434\u0448\u0438\u0439', 'junior', 'trainee', '\u0430\u0441\u0441\u0438\u0441\u0442\u0435\u043d\u0442'\n];\n\nfor (const item of items) {\n    let rating = 0;\n    \n    // \u0423\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0442\u0435\u043a\u0441\u0442\u0430 \u0434\u043b\u044f \u0430\u043d\u0430\u043b\u0438\u0437\u0430\n    let fullText = '';\n    \n    // \u0415\u0441\u043b\u0438 \u0435\u0441\u0442\u044c \u043f\u043e\u043b\u0435 content (\u043a\u0430\u043a \u0443 \u0425\u0430\u0431\u0440\u0430)\n    if (item.json.content) {\n        fullText = item.json.content.toLowerCase();\n    } \n    // \u0415\u0441\u043b\u0438 \u0435\u0441\u0442\u044c title \u0438 description (\u043a\u0430\u043a \u0443 hh.ru)\n    else {\n        const title = item.json.title ? item.json.title.toLowerCase() : '';\n        const description = item.j

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

V2.1 Career-Bot-Workflow. Uses telegram, httpRequest, readWriteFile, googleDrive. Scheduled trigger; 33 nodes.

Source: https://github.com/Gitman404/job-search-assistant/blob/18cd35fb5b2712c55c54bb1472c37eb48a6be5dc/v2-n8n/workflow/v2.1_career-bot-workflow.json — original creator credit. Request a take-down →

More Slack & Telegram workflows → · Browse all categories →

Related workflows

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

Slack & Telegram

v2.2_career-bot-workflow. Uses telegram, httpRequest, googleDrive, googleSheets. Scheduled trigger; 27 nodes.

Telegram, HTTP Request, Google Drive +2
Slack & Telegram

career-bot-workflow. Uses telegram, httpRequest, googleDrive, googleSheets. Scheduled trigger; 25 nodes.

Telegram, HTTP Request, Google Drive +1
Slack & Telegram

End-to-End Video Creation from user idea or transcript AI-Powered Scriptwriting using LLMs (e.g., DeepSeek via OpenRouter) Voiceover Generation with customizable TTS voices Image Scene Generation usin

HTTP Request, Form Trigger, Output Parser Structured +6
Slack & Telegram

Get notified when the International Space Station passes over your location - but only when you can actually see it! This workflow combines real-time ISS tracking with weather condition checks to send

HTTP Request, OpenAI Chat, Chain Llm +5
Slack & Telegram

This advanced n8n workflow is designed for SEO specialists, digital agency owners, webmasters, and marketing managers who need a comprehensive, automated solution to track and improve their website's

Google Sheets Tool, Telegram Trigger, Telegram +9