AutomationFlowsAI & RAG › Automated Weekly Korean News Crawler

Automated Weekly Korean News Crawler

Original n8n title: Woorifisa

WooriFisa. Uses agent, httpRequest, documentDefaultDataLoader, vectorStorePinecone. Scheduled trigger; 86 nodes.

Cron / scheduled trigger★★★★★ complexityAI-powered86 nodesAgentHTTP RequestDocument Default Data LoaderPinecone Vector StoreOpenAI ChatOpenAI EmbeddingsOpenAI@Mendable/N8N Nodes Firecrawl
AI & RAG Trigger: Cron / scheduled Nodes: 86 Complexity: ★★★★★ AI nodes: yes Added:

This workflow follows the Agent → Chat 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
{
  "name": "WooriFisa",
  "nodes": [
    {
      "parameters": {
        "hasOutputParser": true,
        "options": {
          "systemMessage": "You are an intelligent assistant acting as a teaching assistant (TA)\nfor the \"\uc6b0\ub9acFISA \ud074\ub77c\uc6b0\ub4dc \uc5d4\uc9c0\ub2c8\uc5b4\ub9c1\" course.\n\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nRole & Response Style (MANDATORY)\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nYour role:\n- Support learners by answering questions clearly and practically.\n- Explain concepts in a calm, professional, but approachable teaching-assistant tone.\n- Guide learners using course-aligned explanations rather than overly academic or vague answers.\n\nResponse style rules:\n- Always respond in Korean.\n- Always use \ud574\uc694\uccb4.\n- Tone must resemble a university TA in their early-to-mid 20s:\n  - Calm, friendly, and supportive\n  - Clear and direct explanations\n  - Not casual slang, not overly formal\n- Be straightforward; do not speak vaguely.\n- Respect conventional and widely accepted practices.\n- Think with future learning continuity in mind.\n\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nSystem Time Tool (HIGHEST PRIORITY)\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nA tool is available that returns the current date and time in Korea (KST).\n\nRules:\n- If the user question contains any time- or date-related expression, you MUST use this tool FIRST.\n- Examples of triggers include: \uc624\ub298, \uc9c0\uae08, \ud604\uc7ac, \uc774\ubc88 \uc8fc, \ub2e4\uc74c \uc8fc, \uc5b4\uc81c, \ub0b4\uc77c, \ub0a0\uc9dc, \uc694\uc77c, \uba87 \uc8fc\ucc28, \uae30\uc900\uc77c, \uc2dc\uc791\uc77c, \ub9c8\uac10\uc77c\n- Relative expressions MUST be resolved using the returned Korean current date/time.\n\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nData Sources (Priority Order)\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nAlways follow this strict retrieval order for any question:\n\n1) System Time Tool (today\u2019s date in KST)\n2) Blog vector store (Velog, Tistory)\n3) MySQL fisa_schedule table\n4) Lecture vector store (Notion URLs only)\n5) OpenAI Search Tool (supplementary, optional, for verification only)\n\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nData Source Details\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n1) MySQL: fisa_schedule table\n- Columns:\n  - schedule_date (DATE)\n  - main_schedule (TEXT)\n  - detail_schedule (TEXT)\n  - special_lecture (TEXT)\n  - exam (BOOLEAN)\n  - extra_schedule (TEXT)\n- Highest authority for schedule-related questions: \uc77c\uc815, \uc624\ub298, \ub2e4\uc74c\uc8fc, \uacfc\uc81c, \uc9c4\ub3c4, \uacc4\ud68d, \ub9c8\uac10, \uc2a4\ucf00\uc904, \uc8fc\ucc28, n\uc8fc\ucc28\n- Weekly ranges are derived from schedule_date, based on the official start date and System Time Tool.\n\n2) Blog vector store\n- Study journal posts written by learners\n- metadata.type = \"blog\"\n- URLs from Velog or Tistory\n- Primary source for learning content\n\n3) Lecture vector store\n- Official course lecture materials\n- metadata.type = \"lecture\"\n- URLs must be from Notion\n- Used to reinforce or formalize blog explanations\n\n4) OpenAI Search Tool (SUPPLEMENTARY)\n- Used only for refinement or verification of technical explanations\n- Must not override blog or lecture content\n- Must align with course scope\n\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nQuestion Classification (MANDATORY)\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nClassify every user question into one or more of:\n\n- \"\uc77c\uc815 \uc9c8\ubb38\"\n- \"\uc218\uc5c5 \ub0b4\uc6a9 \uc9c8\ubb38\"\n- \"\uc77c\ubc18 \uc9c8\ubb38\"\n\nRules:\n- \ub0a0\uc9dc\u00b7\uc2dc\uac04 \ud45c\ud604 \ud3ec\ud568 \u2192 \uc77c\uc815 \uc9c8\ubb38\n- \uae30\uc220, \uac1c\ub150, \ub3c4\uad6c \u2192 \uc218\uc5c5 \ub0b4\uc6a9 \uc9c8\ubb38\n- \uacfc\uc815 \uc18c\uac1c, \uc81c\ub3c4, \uae30\ud0c0 \u2192 \uc77c\ubc18 \uc9c8\ubb38\n\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nEnhanced Retrieval Strategy for \"\uc218\uc5c5 \ub0b4\uc6a9 \uc9c8\ubb38\"\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nStep 1. Blog-first Retrieval\n- Always search Blog vector store first\n- Priority:\n  1) Week reference (n\uc8fc\ucc28) if present\n  2) Core technical keywords from the user question\n- Retrieve only metadata.type = \"blog\"\n\nStep 2. Keyword Extraction\n- Extract key technical terms from blog content:\n  - Technologies\n  - Core concepts\n  - Tools, commands, services\n- Use ONLY these keywords to search Lecture vector store\n\nStep 3. Lecture Retrieval\n- Search Lecture vector store using blog-derived keywords only\n- Only metadata.type = \"lecture\"\n- URLs must be from Notion\n\nStep 4. OpenAI Search Tool (OPTIONAL)\n- Only if blog + lecture content is:\n  - Insufficient\n  - Slightly outdated\n  - Lacking clarity\n- Purpose: confirm correctness, improve explanation\n- Must be clearly framed as \u201c\ubcf4\ucda9 \uc124\uba85\u201d or \u201c\uc77c\ubc18\uc801\uc778 \uae30\uc900\u201d\n\nStep 5. Answer Composition\n- Core explanation: Blog content\n- Reinforce/validate: Lecture content\n- Optional refinement: OpenAI search\n- If conflict: Lecture > Blog > Search\n\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nLearning Category (ONLY for \uc218\uc5c5 \ub0b4\uc6a9 \uc9c8\ubb38)\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nAssign exactly one:\n- \uc790\ubc14\n- \uc2a4\ud504\ub9c1\n- n8n\n- ELK(elasticsearch, logstash, kibana)\n- \ub3c4\ucee4\n- \ucfe0\ubc84\ub124\ud2f0\uc2a4\n- \ub9ac\ub205\uc2a4\n- \ud074\ub77c\uc6b0\ub4dc\n- AWS\n\nIf NOT a learning question:\n- Category = \"ETC\"\n\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nOutput Format (TEXT ONLY)\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nAlways respond using plain text in the following order:\n\n1. \uc9c8\ubb38 \uc720\ud615\n2. \ub2f5\ubcc0\n3. \ud559\uc2b5 \uce74\ud14c\uace0\ub9ac\n4. \uc77c\uc815 (MySQL \uae30\ubc18, \ud574\ub2f9\ub420 \ub54c\ub9cc)\n5. \uc218\uc5c5 \uc790\ub8cc (Lectures)\n6. \ube14\ub85c\uadf8 \uc790\ub8cc (Blogs)\n\nRules:\n- Never invent URLs\n- Lecture URLs: Notion only\n- Blog URLs: Velog or Tistory only\n- Explicitly state when data is missing\n\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nGlobal Rules\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n- Always use System Time Tool first if question contains any date/time expression\n- Blog search is the primary source for learning content\n- MySQL schedule data has the highest authority for \uc77c\uc815\n- Blog \u2192 Lecture \u2192 OpenAI Search is the strict order for learning explanations\n- Do NOT mention internal retrieval steps or decision logic in the final answer\n- Always follow the fixed order: \uc624\ub298 \ub0a0\uc9dc \ud655\uc778 \u2192 \ube14\ub85c\uadf8 \uac80\uc0c9 \u2192 \uc77c\uc815 \ud655\uc778 \u2192 \uad50\uc548 \ud655\uc778\n\n### VARIATION & ANTI-REPETITION RULES (REQUIRED)\n\n- You MUST avoid generating questions that are identical or highly similar to previous quizzes stored in memory.\n- Even if the topic is the same, you MUST change:\n  - the question angle,\n  - the scenario,\n  - or the level of abstraction.\n- Do NOT reuse the same example, wording, or answer pattern.\n- Prefer:\n  - different concepts within the same topic, or\n  - different real-world scenarios for the same concept.\n\n"
        }
      },
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 3.1,
      "position": [
        1368,
        2868
      ],
      "id": "4cb22064-ee98-47a7-964a-764a9137977d",
      "name": "Chatbot"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "edcd64db-8ece-412f-84ee-fdce959b7f39",
              "leftValue": "={{ $json.pages.length }}",
              "rightValue": "",
              "operator": {
                "type": "number",
                "operation": "notEmpty",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        1632,
        2436
      ],
      "id": "428ce89a-558c-4e9b-affd-1c79c03367ac",
      "name": "\ud06c\ub864\ub9c1 \uacb0\uacfc \ud310\ub2e8(Notion \uad50\uc548)"
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "triggerAtDay": [
                1
              ],
              "triggerAtHour": 1
            }
          ]
        }
      },
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.3,
      "position": [
        736,
        1408
      ],
      "id": "b42f083e-8901-4dcc-b429-5350217f4b32",
      "name": "\uc8fc\uac04 \ud06c\ub864\ub7ec"
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {}
          ]
        }
      },
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.3,
      "position": [
        736,
        2436
      ],
      "id": "6f11246a-5312-4a1d-8106-67a4a4f09e8c",
      "name": "\uc77c\uac04 \ud06c\ub864\ub7ec"
    },
    {
      "parameters": {
        "fieldToSplitOut": "data.searchPosts.posts",
        "options": {}
      },
      "type": "n8n-nodes-base.splitOut",
      "typeVersion": 1,
      "position": [
        1184,
        1408
      ],
      "id": "a66cdb00-db3d-49db-9e54-ecb016e887e0",
      "name": "Split Out"
    },
    {
      "parameters": {
        "url": "=https://velog.io/@{{ $('1\uac1c\uc529').item.json.user.username }}/{{ $('1\uac1c\uc529').item.json.url_slug }}",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        2528,
        1088
      ],
      "id": "5c03f5ba-bab1-4f50-930d-d9a344b2742f",
      "name": "\uc0c1\uc138\uc815\ubcf4 \uac00\uc838\uc624\uae30",
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "options": {}
      },
      "type": "n8n-nodes-base.splitInBatches",
      "typeVersion": 3,
      "position": [
        1856,
        1408
      ],
      "id": "de1b359d-180b-4255-8b2c-266d5211b68c",
      "name": "1\uac1c\uc529"
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "triggerAtDay": [
                1
              ],
              "triggerAtHour": 1
            }
          ]
        }
      },
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.3,
      "position": [
        736,
        1984
      ],
      "id": "e1b6f7c3-4a68-433f-a954-8bfae7210e58",
      "name": "\uc8fc\uac04 \ud06c\ub864\ub7ec1"
    },
    {
      "parameters": {
        "jsCode": "// Loop over input items and add a new field called 'myNewField' to the JSON of each one\nfor (const item of $input.all()) {\n  const text = item.json.data\n  .replace(/<script[\\s\\S]*?>[\\s\\S]*?<\\/script>/gi, '')\n  .replace(/<style[\\s\\S]*?>[\\s\\S]*?<\\/style>/gi, '')\n  .replace(/<[^>]*>/g, '')\n  .trim();\n  item.json.data = text;\n}\n\nreturn $input.all();"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2752,
        1088
      ],
      "id": "d3c29d5e-33ca-4bc1-a2f1-49e7a7a9c251",
      "name": "HTML \ud0dc\uadf8 \uc81c\uac70"
    },
    {
      "parameters": {
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.documentDefaultDataLoader",
      "typeVersion": 1.1,
      "position": [
        3912,
        1384
      ],
      "id": "83d067e4-0c6c-4b0f-b6eb-1c8a462603c3",
      "name": "Default Data Loader"
    },
    {
      "parameters": {
        "mode": "insert",
        "pineconeIndex": {
          "__rl": true,
          "value": "woorifisa-lectures",
          "mode": "list",
          "cachedResultName": "woorifisa-lectures"
        },
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.vectorStorePinecone",
      "typeVersion": 1.3,
      "position": [
        2528,
        2312
      ],
      "id": "a8dd6032-d272-4d4e-90b9-daeae9421bcd",
      "name": "\uad50\uc548 \uc2a4\ud1a0\uc5b4",
      "credentials": {
        "pineconeApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.documentDefaultDataLoader",
      "typeVersion": 1.1,
      "position": [
        2664,
        2536
      ],
      "id": "bb098329-95ca-4114-8164-7e65678f5204",
      "name": "Default Data Loader1"
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
          "value": "gpt-4.1",
          "mode": "list",
          "cachedResultName": "gpt-4.1"
        },
        "builtInTools": {
          "webSearch": {
            "searchContextSize": "low"
          }
        },
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.3,
      "position": [
        960,
        3092
      ],
      "id": "8b3cb234-58a4-4941-a4ed-592231208b48",
      "name": "OpenAI Chat Model",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "options": {
          "dimensions": 1024
        }
      },
      "type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi",
      "typeVersion": 1.2,
      "position": [
        3784,
        1384
      ],
      "id": "7e1df215-f1ab-473a-90cd-d2e801d6e99c",
      "name": "Embeddings OpenAI",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "options": {
          "dimensions": 1024
        }
      },
      "type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi",
      "typeVersion": 1.2,
      "position": [
        2536,
        2536
      ],
      "id": "bb2f8054-4e62-471e-8ff1-e1790c1c8fde",
      "name": "Embeddings OpenAI1",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "options": {}
      },
      "type": "n8n-nodes-base.splitInBatches",
      "typeVersion": 3,
      "position": [
        2080,
        2436
      ],
      "id": "6ba06fd8-9858-4765-bf35-735b6486397b",
      "name": "Loop Over Items2"
    },
    {
      "parameters": {
        "jsCode": "function generateEmbedding(){\n  const title = \"title: \" + $input.first().json.title;\n  const content = \"content: \" + $input.first().json.content;\n  const url = \"url: \" + $input.first().json.url;\n\n  return title + \"\\n\" + content + \"\\n\" + url + \"\\n\";\n}\n\nreturn [{\n  embedding: generateEmbedding()\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2304,
        2312
      ],
      "id": "b652b079-69d8-4e71-8a7d-2fe586b13e1c",
      "name": "Code in JavaScript1"
    },
    {
      "parameters": {
        "options": {
          "dimensions": 1024
        }
      },
      "type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi",
      "typeVersion": 1.2,
      "position": [
        1296,
        3300
      ],
      "id": "af77eac3-f3b1-4126-a74d-a54bfc442229",
      "name": "Embeddings OpenAI2",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "options": {
          "dimensions": 1024
        }
      },
      "type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi",
      "typeVersion": 1.2,
      "position": [
        1584,
        3300
      ],
      "id": "3ca67cce-6f03-4f9f-9242-0519b5314ba9",
      "name": "Embeddings OpenAI3",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "mode": "retrieve-as-tool",
        "toolDescription": "You are a retrieval-based assistant.\n\nThe knowledge base is a unified vector store containing embedded documents.\nEach document includes a metadata field called \"type\" that identifies its source:\n\n- type: \"material\" \u2192 official lecture materials and course handouts\n- type: \"blog\" \u2192 study journal blog posts written during learning\n\nThe lecture materials are related to:\n- Java Spring\n- Docker\n- Cloud and infrastructure concepts\n\nEach document includes:\n- Content\n- A title\n- A brief summary\n- A reference (file name, document link, or URL)\n\nWhen a user asks a question, follow these rules strictly:\n\n1. Retrieve the most relevant documents from the vector store using semantic similarity.\n2. Use ONLY the retrieved documents to construct the answer.\n3. Do NOT use prior knowledge, general knowledge, or assumptions.\n4. Separate retrieved documents based on their \"type\" metadata:\n   - Documents with type \"material\" must be placed in the \"materials\" array.\n   - Documents with type \"blog\" must be placed in the \"blogs\" array.\n\nResponse rules:\n- The response MUST be returned strictly in JSON format.\n- Do NOT include any text outside the JSON response.\n- Do NOT invent or infer any information.\n- Use only the exact metadata provided in the retrieved documents.\n- If no relevant documents exist for a section, return an empty array for that section.\n\nThe JSON response must follow this exact structure:\n\n{\n  \"answer\": string,\n  \"materials\": [\n    {\n      \"title\": string,\n      \"summary\": string,\n      \"reference\": string\n    }\n  ],\n  \"blogs\": [\n    {\n      \"title\": string,\n      \"summary\": string,\n      \"link\": string\n    }\n  ]\n}\n\nAdditional constraints:\n- \"materials\" and \"blogs\" must always be arrays.\n- Include only documents that are directly relevant to the user's question.\n- If no documents are relevant at all, return an empty array for both \"materials\" and \"blogs\", and keep \"answer\" concise and based only on retrieved content (or empty if nothing is retrieved).\n",
        "pineconeIndex": {
          "__rl": true,
          "value": "woorifisa-lectures",
          "mode": "list",
          "cachedResultName": "woorifisa-lectures"
        },
        "topK": 5,
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.vectorStorePinecone",
      "typeVersion": 1.3,
      "position": [
        1216,
        3092
      ],
      "id": "79ffcd78-5eb3-492f-aabb-08b1ac8a3889",
      "name": "lecture store(read)",
      "credentials": {
        "pineconeApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "mode": "retrieve-as-tool",
        "toolDescription": "\uc218\uc5c5 \uad50\uc548\uc790\ub8cc\n",
        "pineconeIndex": {
          "__rl": true,
          "value": "woorifisa-blogs",
          "mode": "list",
          "cachedResultName": "woorifisa-blogs"
        },
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.vectorStorePinecone",
      "typeVersion": 1.3,
      "position": [
        1504,
        3092
      ],
      "id": "822b57e0-82ec-4d23-8a43-4f4e152084ca",
      "name": "blog store(read)",
      "credentials": {
        "pineconeApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "edcd64db-8ece-412f-84ee-fdce959b7f39",
              "leftValue": "={{ $input.all().isNotEmpty() }}",
              "rightValue": "",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        1632,
        1984
      ],
      "id": "f56cd6cb-8d38-42de-b10f-0136bc5726c1",
      "name": "0\uac1c \uc774\uc0c11"
    },
    {
      "parameters": {
        "options": {}
      },
      "type": "n8n-nodes-base.splitInBatches",
      "typeVersion": 3,
      "position": [
        1856,
        1984
      ],
      "id": "fff7e5de-c885-4d86-8f2b-a0c1d77f74c3",
      "name": "1\uac1c\uc5291"
    },
    {
      "parameters": {
        "modelId": {
          "__rl": true,
          "value": "gpt-4.1-mini",
          "mode": "list",
          "cachedResultName": "GPT-4.1-MINI"
        },
        "responses": {
          "values": [
            {
              "role": "system",
              "content": "You are an assistant that transforms educational materials into a format **optimized for semantic embedding**.\n\nInput:\n- Lecture notes, blog learning logs, study materials, etc.\n- Technology scope: Java Spring, Docker, Cloud/Infrastructure\n- Input data may include title, content, url, source, and other metadata\n\nOutput Goals:\n- Do **not summarize**; preserve full learning structure and conceptual flow\n- Explicitly clarify learning topics and scope\n- Highlight step-by-step learning progression or sequence\n- Clearly explain relationships between key technologies, concepts, and tools\n- Convert lists or bullet points into coherent explanatory sentences\n- Emphasize curriculum order, learning progression, and conceptual grouping\n- Include original URLs for reference\n- Output format: JSON with a single field `\"embedding_text\"` containing **one continuous string**\n\nExample Output:\n\n{\n  \"embedding_text\": \"Java Spring learning materials are structured around the MVC pattern, explaining the roles and relationships of Model, View, and Controller. The Model handles data and business logic, the View provides the user interface, and the Controller manages requests and connects the Model and View. Additionally, DAO and DTO patterns optimize data access and transfer. The step-by-step learning sequence progresses from basic syntax \u2192 object-oriented programming \u2192 database integration \u2192 Spring MVC structure \u2192 hands-on exercises. URL: https://example.com\"\n}\n\nRules:\n1. Never summarize; maintain the full conceptual and learning flow\n2. Do not add information that is not present in the input\n3. Output must be JSON with only one field `\"embedding_text\"` as a single string\n4. Keep technical terms in English without translating\n"
            },
            {
              "content": "=data: {{ $json.data }}\nurl: \"https://velog.io/@{{ $json.user.username }}/{{ $json.url_slug }}\""
            }
          ]
        },
        "builtInTools": {},
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "typeVersion": 2.1,
      "position": [
        3200,
        1160
      ],
      "id": "b2f85381-30a4-4f64-946d-2b515652f804",
      "name": "\uc784\ubca0\ub529 \ubb38\uc11c \ucd5c\uc801\ud654",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "modelId": {
          "__rl": true,
          "value": "gpt-4.1-mini",
          "mode": "list",
          "cachedResultName": "GPT-4.1-MINI"
        },
        "responses": {
          "values": [
            {
              "role": "system",
              "content": "You are an assistant that transforms educational materials into a format **optimized for semantic embedding**.\n\nInput:\n- Lecture notes, blog learning logs, study materials, etc.\n- Technology scope: Java Spring, Docker, Cloud/Infrastructure\n- Input data may include title, content, url, source, and other metadata\n\nOutput Goals:\n- Do **not summarize**; preserve full learning structure and conceptual flow\n- Explicitly clarify learning topics and scope\n- Highlight step-by-step learning progression or sequence\n- Clearly explain relationships between key technologies, concepts, and tools\n- Convert lists or bullet points into coherent explanatory sentences\n- Emphasize curriculum order, learning progression, and conceptual grouping\n- Include original URLs for reference\n- Output format: JSON with a single field `\"embedding_text\"` containing **one continuous string**\n\nExample Output:\n\n{\n  \"embedding_text\": \"Java Spring learning materials are structured around the MVC pattern, explaining the roles and relationships of Model, View, and Controller. The Model handles data and business logic, the View provides the user interface, and the Controller manages requests and connects the Model and View. Additionally, DAO and DTO patterns optimize data access and transfer. The step-by-step learning sequence progresses from basic syntax \u2192 object-oriented programming \u2192 database integration \u2192 Spring MVC structure \u2192 hands-on exercises. URL: https://example.com\"\n}\n\nRules:\n1. Never summarize; maintain the full conceptual and learning flow\n2. Do not add information that is not present in the input\n3. Output must be JSON with only one field `\"embedding_text\"` as a single string\n4. Keep technical terms in English without translating\n"
            }
          ]
        },
        "builtInTools": {},
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "typeVersion": 2.1,
      "position": [
        2528,
        1736
      ],
      "id": "960dcb85-c6ba-4ab5-a1dc-ab7a31eb5643",
      "name": "\uc784\ubca0\ub529 \ubb38\uc11c \ucd5c\uc801\ud654 2",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "options": {
          "dimensions": 1024
        }
      },
      "type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi",
      "typeVersion": 1.2,
      "position": [
        3112,
        1960
      ],
      "id": "09702656-146d-461f-a24c-44d7a648244f",
      "name": "Embeddings OpenAI4",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.documentDefaultDataLoader",
      "typeVersion": 1.1,
      "position": [
        3240,
        1960
      ],
      "id": "5d44bff6-fc72-480e-8881-3d6925b86fca",
      "name": "Default Data Loader2"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "2445c0b2-9c27-4c74-89de-165fb7091d95",
              "leftValue": "={{ $json.released_at }}",
              "rightValue": "={{  $now }}",
              "operator": {
                "type": "dateTime",
                "operation": "beforeOrEquals"
              }
            },
            {
              "id": "1ddaec4a-7fa8-401e-bf13-08dec78e2d03",
              "leftValue": "={{ $json.released_at }}",
              "rightValue": "={{ $now.minus(1, 'year' ) }}",
              "operator": {
                "type": "dateTime",
                "operation": "afterOrEquals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.filter",
      "typeVersion": 2.3,
      "position": [
        1408,
        1408
      ],
      "id": "8af0419d-80f3-4f05-852f-a654b48c03d6",
      "name": "\uc800\ubc88\uc8fc \ub370\uc774\ud130\ub9cc \ud544\ud130(\uc784\uc2dc 1\ub144)"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "edd1ffb1-520a-4c2d-85aa-06bf229a92fe",
              "leftValue": "={{ $json.published_date }}",
              "rightValue": "={{ $now }}",
              "operator": {
                "type": "dateTime",
                "operation": "beforeOrEquals"
              }
            },
            {
              "id": "2e9cb341-a99e-434c-a2b0-6a72fd7bfa9f",
              "leftValue": "={{ $json.published_date }}",
              "rightValue": "={{ $now.minus(1, 'year') }}",
              "operator": {
                "type": "dateTime",
                "operation": "afterOrEquals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.filter",
      "typeVersion": 2.3,
      "position": [
        1408,
        1984
      ],
      "id": "5b67de36-51d8-4b68-a83c-4d1af03035df",
      "name": "\uc800\ubc88\uc8fc \ub370\uc774\ud130\ub9cc \ud544\ud130(\uc784\uc2dc 1\ub144)2"
    },
    {
      "parameters": {
        "fieldToSplitOut": "data.tistory_posts",
        "options": {}
      },
      "type": "n8n-nodes-base.splitOut",
      "typeVersion": 1,
      "position": [
        1184,
        1984
      ],
      "id": "f7565357-edd0-4a04-9873-6d04678fbd45",
      "name": "Split Out1"
    },
    {
      "parameters": {
        "jsCode": "return [{\n  embedding: JSON.parse($input.first().json.output[0].content[0].text).embedding_text\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2880,
        1736
      ],
      "id": "4ddbed4b-b194-4cf4-9aa0-5666dce8efb6",
      "name": "\uc784\ubca0\ub529 \ucd94\ucd9c"
    },
    {
      "parameters": {
        "jsCode": "return [{\n  embedding: JSON.parse($input.first().json.output[0].content[0].text).embedding_text\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        3552,
        1160
      ],
      "id": "18a29bc1-9cb1-4264-8a60-6c56430adf96",
      "name": "\uc784\ubca0\ub529 \ucd94\ucd9c2"
    },
    {
      "parameters": {
        "mode": "insert",
        "pineconeIndex": {
          "__rl": true,
          "value": "woorifisa-blogs",
          "mode": "list",
          "cachedResultName": "woorifisa-blogs"
        },
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.vectorStorePinecone",
      "typeVersion": 1.3,
      "position": [
        3104,
        1736
      ],
      "id": "d2621a0c-5f71-4583-a22e-949627bd8649",
      "name": "\ube14\ub85c\uadf8 store(\uc800\uc7a5)",
      "credentials": {
        "pineconeApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "mode": "insert",
        "pineconeIndex": {
          "__rl": true,
          "value": "woorifisa-blogs",
          "mode": "list",
          "cachedResultName": "woorifisa-blogs"
        },
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.vectorStorePinecone",
      "typeVersion": 1.3,
      "position": [
        3776,
        1160
      ],
      "id": "c563180e-c197-4251-82f7-ab630cb73650",
      "name": "\ube14\ub85c\uadf8 \uc2a4\ud1a0\uc5b4 \uc800\uc7a52",
      "credentials": {
        "pineconeApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "scrape",
        "requestOptions": {}
      },
      "type": "@mendable/n8n-nodes-firecrawl.firecrawl",
      "typeVersion": 1,
      "position": [
        960,
        1984
      ],
      "id": "3d2738b1-eaf5-4df9-85d6-76bcb860df0d",
      "name": "tistory \ud06c\ub864\ub7ec",
      "credentials": {
        "firecrawlApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://v2.velog.io/graphql",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "content-type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "query",
              "value": "query SearchPosts($keyword: String!, $offset: Int, $username: String) {       searchPosts(keyword: $keyword, offset: $offset, username: $username) {         count         posts {           id           title           short_description           thumbnail           user {             id             username             profile {               id               thumbnail               display_name               __typename             }             __typename           }           url_slug           released_at           tags           is_private           comments_count           __typename         }         __typename       }     }"
            },
            {
              "name": "variables",
              "value": "{\"keyword\": \"\uc6b0\ub9acfisa \ud074\ub77c\uc6b0\ub4dc \uc5d4\uc9c0\ub2c8\uc5b4\ub9c1\"}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        960,
        1408
      ],
      "id": "13b269c0-6195-4b73-845c-64a4b3c89386",
      "name": "velog \ud06c\ub864\ub7ec",
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "jsCode": "// \uc139\uc158\ubcc4 \ubd84\ub9ac\nfunction extract(label, text) {\n  const regex = new RegExp(`${label}[\\\\s\\\\S]*?(?=\\\\n\\\\d+\\\\. |$)`, \"g\");\n  const match = text.match(regex);\n  if (!match) return \"\";\n  return match[0].replace(label, \"\").trim();\n}\n\nfor (const item of $input.all()) {\n   // \uc139\uc158 \ucd94\ucd9c\n  const raw = item.json.output;\n  const questionType = extract(\"1. \uc9c8\ubb38 \uc720\ud615\",raw);\n  const generalAnswer = extract(\"2. \ub2f5\ubcc0\",raw);\n  const category = extract(\"3. \ud559\uc2b5 \uce74\ud14c\uace0\ub9ac\",raw);\n  const schedule = extract(\"4. \uc77c\uc815\",raw);\n  const lectures = extract(\"5. \uc218\uc5c5 \uc790\ub8cc\",raw);\n  const blogs = extract(\"6. \ube14\ub85c\uadf8 \uc790\ub8cc\",raw);\n  \n  // \ud604\uc7ac \uc2dc\uac04\n  const now = new Date().toISOString();\n\n  return {\n      \uc9c8\ubb38\uc720\ud615: questionType,\n      \ud559\uc2b5\uce74\ud14c\uace0\ub9ac: category,\n      \ub2f5\ubcc0: generalAnswer,\n      \uc77c\uc815: schedule,\n      \uc218\uc5c5\uc790\ub8cc: lectures,\n      \ube14\ub85c\uadf8\uc790\ub8cc: blogs,\n      \uc0dd\uc131\uc77c\uc2dc: now\n    }\n}\n\nreturn $input.all();"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2128,
        2868
      ],
      "id": "89001e4e-848d-4cd8-b0a0-e0b74ef5f199",
      "name": "Code in JavaScript"
    },
    {
      "parameters": {},
      "type": "@n8n/n8n-nodes-langchain.memoryRedisChat",
      "typeVersion": 1.5,
      "position": [
        1088,
        3092
      ],
      "id": "3c429f9c-a084-41a9-bcce-dc4764933598",
      "name": "Redis Chat Memory",
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "table": {
          "__rl": true,
          "value": "fisa_chat_histories",
          "mode": "list",
          "cachedResultName": "fisa_chat_histories"
        },
        "dataMode": "defineBelow",
        "valuesToSend": {
          "values": [
            {
              "column": "question_type",
              "value": "={{ $json['\uc9c8\ubb38\uc720\ud615'] }}"
            },
            {
              "column": "learning_category",
              "value": "={{ $json['\ud559\uc2b5\uce74\ud14c\uace0\ub9ac'] }}"
            },
            {
              "column": "general_answer",
              "value": "={{ $json['\ub2f5\ubcc0'] }}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.mySql",
      "typeVersion": 2.5,
      "position": [
        2352,
        2868
      ],
      "id": "262cd7d9-c9a3-4d6f-a828-76dd8c4cb2a0",
      "name": "Insert rows in a table",
      "credentials": {
        "mySql": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "select",
        "table": {
          "__rl": true,
          "value": "fisa_schedule",
          "mode": "list",
          "cachedResultName": "fisa_schedule"
        },
        "limit": 200,
        "options": {}
      },
      "type": "n8n-nodes-base.mySqlTool",
      "typeVersion": 2.5,
      "position": [
        1792,
        3092
      ],
      "id": "e33e4b45-3ad2-4a03-b857-1184e9c92515",
      "name": "Select rows from a table in MySQL",
      "credentials": {
        "mySql": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "edcd64db-8ece-412f-84ee-fdce959b7f39",
              "leftValue": "={{ $input.all().isNotEmpty() }}",
              "rightValue": {},
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        1632,
        1408
      ],
      "id": "c8bef18c-f438-4d64-a214-9145931384c1",
      "name": "0\uac1c \uc774\uc0c1"
    },
    {
      "parameters": {
        "operation": "select",
        "table": {
          "__rl": true,
          "value": "fisa_crawl_histories",
          "mode": "list",
          "cachedResultName": "fisa_crawl_histories"
        },
        "where": {
          "values": [
            {
              "column": "url",
              "value": "=https://velog.io/@{{ $json.user.username }}/{{ $json.url_slug }}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.mySql",
      "typeVersion": 2.5,
      "position": [
        2080,
        1088
      ],
      "id": "c12794d8-29ee-484f-ab5b-bed786e2db31",
      "name": "\uc911\ubcf5 \ub370\uc774\ud130 \ud655\uc778",
      "alwaysOutputData": true,
      "credentials": {
        "mySql": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "table": {
          "__rl": true,
          "value": "fisa_crawl_histories",
          "mode": "list",
          "cachedResultName": "fisa_crawl_histories"
        },
        "dataMode": "defineBelow",
        "valuesToSend": {
          "values": [
            {
              "column": "source_type",
              "value": "blog"
            },
            {
              "column": "url",
              "value": "=https://velog.io/@{{ $('Merge').item.json.user.username }}/{{ $('Merge').item.json.url_slug }}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.mySql",
      "typeVersion": 2.5,
      "position": [
        4128,
        1284
      ],
      "id": "d9e60e69-0dbb-40c6-9913-1ed364705fba",
      "name": "\ube14\ub85c\uadf8 \ud06c\ub864\ub9c1 \uc815\ubcf4 \uc800\uc7a5",
      "credentials": {
        "mySql": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "2eb0f95a-4558-4687-b230-ab68e41c49ac",
              "leftValue": "={{$json.values() }}",
              "rightValue": "",
              "operator": {
                "type": "array",
                "operation": "empty",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        2304,
        1088
      ],
      "id": "de7c0915-b100-4949-a369-7bfa142c374f",
      "name": "\uc911\ubcf5\uc774 \uc544\ub2cc \uacbd\uc6b0"
    },
    {
      "parameters": {
        "operation": "select",
        "table": {
          "__rl": true,
          "value": "fisa_crawl_histories",
          "mode": "list",
          "cachedResultName": "fisa_crawl_histories"
        },
        "where": {
          "values": [
            {
              "column": "url",
              "value": "=https://velog.io/@{{ $json.user.username }}/{{ $json.url_slug }}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.mySql",
      "typeVersion": 2.5,
      "position": [
        2080,
        1736
      ],
      "id": "e1938412-2452-4fd6-baac-b26ea64f598f",
      "name": "\uc911\ubcf5 \ub370\uc774\ud130 \ud655\uc7781",
      "alwaysOutputData": true,
      "credentials": {
        "mySql": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 3
          },
          "conditions": [
            {
              "id": "cd9783cd-f5de-437f-93b7-2dc6a459eacc",
              "leftValue": "",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "equals",
                "name": "filter.operator.equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        2304,
        1736
      ],
      "id": "35bb1af4-533d-427b-b302-0921368eaf27",
      "name": "If"
    },
    {
      "parameters": {
        "table": {
          "__rl": true,
          "value": "fisa_crawl_histories",
          "mode": "list",
          "cachedResultName": "fisa_crawl_histories"
        },
        "dataMode": "defineBelow",
        "valuesToSend": {
          "values": [
            {
              "column": "source_type",
              "value": "blog"
            },
            {
              "column": "url",
              "value": "={{ $('0\uac1c \uc774\uc0c11').first().json.source_url }}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.mySql",
      "typeVersion": 2.5,
      "position": [
        3456,
        1860
      ],
      "id": "59c0d015-3d3f-4ba2-a8b9-700c469ae439",
      "name": "\ube14\ub85c\uadf8 \ud06c\ub864\ub9c1 \uc815\ubcf4 \uc800\uc7a51",
      "credentials": {
        "mySql": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "table": {
          "__rl": true,
          "value": "fisa_crawl_history",
          "mode": "list",
          "cachedResultName": "fisa_crawl_history"
        },
        "dataMode": "defineBelow",
        "valuesToSend": {
          "values": [
            {
              "column": "source_type",
              "value": "notion"
            },
            {
              "column": "url",
              "value": "={{ $('Loop Over Items2').item.json.url }}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.mySql",
      "typeVersion": 2.5,
      "position": [
        2880,
        2436
      ],
      "id": "2c49a45f-06e1-4258-80f4-c3054e2e5a3d",
      "name": "Insert rows in a table1",
      "credentials": {
        "mySql": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "http://notion-crawler:3000/crawl",
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "excludeUrls",
              "value": "={{ $json.urls }}"
            }
          ]
        },
        "options": {
          "timeout": 100000000
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        1408,
        2436
      ],
      "id": "f0e5bbfd-937c-45a0-b999-d017e54fd57d",
      "name": "\uad50\uc548 \ub178\uc158 \ud06c\ub864\ub7ec"
    },
    {
      "parameters": {
        "fieldToSplitOut": "pages",
        "options": {}
      },
      "type": "n8n-nodes-base.splitOut",
      "typeVersion": 1,
      "position": [
        1856,
        2436
      ],
      "id": "f93f1a37-3483-40d0-847e-4d38e852f864",
      "name": "Split Out2"
    },
    {
      "parameters": {
        "jsCode": "// Loop over input items and add a new field called 'myNewField' to the JSON of each one\nconst urls = [];\nfor (const item of $input.all()) {\n  urls.push(item.json.url)\n}\n\nreturn {\n  urls\n}"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1184,
        2436
      ],
      "id": "86a47e31-8c34-4d82-9908-526880827f48",
      "name": "Code in JavaScript2"
    },
    {
      "parameters": {
        "mode": "combine",
        "combineBy": "combineAll",
        "options": {}
      },
      "type": "n8n-nodes-base.merge",
      "typeVersion": 3.2,
      "position": [
        2976,
        1160
      ],
      "id": "bb40f510-8704-4e23-938f-f6b5d37fa992",
      "name": "Merge"
    },
    {
      "parameters": {
        "description": "You can call the MCP to retrieve the current date and time\nbased on the user's locale and timezone.\n\nYou MUST call the MCP in the following cases:\n- When the user mentions relative dates such as:\n  \"today\", \"tomorrow\", \"yesterday\", \"this week\", \"next week\", or similar expressions\n- When calculating schedules, deadlines, or plans that depend on the current date\n- When resolving expressions like \"n days later\", \"this month\", or \"next month\"\n\nThe MCP returns the current date and time adjusted to the user's locale.\nAlways use the MCP result as the source of truth for \"now\".\n\nDo NOT assume or hardcode the current date or time.\nDo NOT calculate relative dates without calling the MCP first.\n",
        "jsCode": "return new Date().toLocaleString('ko-KR', {\n  timeZone: 'Asia/Seoul'\n})\n"
      },
      "type": "@n8n/n8n-nodes-langchain.toolCode",
      "typeVersion": 1.3,
      "position": [
        1920,
        3092
      ],
      "id": "29c4a82e-4ebf-4142-8d44-7ba831ddb68f",
      "name": "\ud604\uc7ac\ub0a0\uc9dc \ubc18\ud658"
    },
    {
      "parameters": {
        "operation": "select",
        "table": {
          "__rl": true,
          "value": "fisa_crawl_histories",
          "mode": "list",
          "cachedResultName": "fisa_crawl_histories"
        },
        "where": {
          "values": [
            {
              "column": "source_type",
              "value": "notion"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.mySql",
      "typeVersion": 2.5,
      "position": [
        960,
        2436
      ],
      "id": "43c4c455-c5e8-4845-b175-6ff2b6f305dc",
      "name": "\ud06c\ub864\ub9c1url \uc870\ud68c",
      "credentials": {
        "mySql": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "public": true,
        "availableInChat": true,
        "agentName": "woorifisa",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.chatTrigger",
      "typeVersion": 1.4,
      "position": [
        736,
        2868
      ],
      "id": "95b5ab28-7c7a-4dd5-8142-6b2cd51e78b0",
      "name": "When chat message received"
    },
    {
      "parameters": {
        "operation": "select",
        "table": {
          "__rl": true,
          "value": "fisa_chat_histories",
          "mode": "list",
          "cachedResultName": "fisa_chat_histories"
        },
        "limit": 20,
        "sort": {
          "values": [
            {
              "column": "created_at",
              "direction": "DESC"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.mySql",
      "typeVersion": 2.5,
      "position": [
        960,
        3508
      ],
      "id": "b8b95a24-f65a-451f-a112-cd1c177c6125",
      "name": "Select rows from a table1",
      "alwaysOutputData": true,
      "credentials": {
        "mySql": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "function parseQuizJson(rawText) {\n  if (!rawText) {\n    throw new Error(\"\uc785\ub825 \uac12\uc774 \ube44\uc5b4 \uc788\uc2b5\ub2c8\ub2e4.\");\n  }\n\n  // \uc55e\ub4a4 \uacf5\ubc31 \ubc0f \uc904\ubc14\uafc8 \uc815\ub9ac\n  const cleaned = rawText.trim();\n\n  let parsed;\n  try {\n    parsed = JSON.parse(cleaned);\n  } catch (e) {\n    throw new Error(\"JSON \ud30c\uc2f1 \uc2e4\ud328: \" + e.message);\n  }\n\n  return parsed;\n}\n\n/* n8n Function \ub178\ub4dc */\nconst raw = $input.first().json.output;\n\n// output\uc774 \ubb38\uc790\uc5f4\uc77c \uacbd\uc6b0\nconst quiz =\n  typeof raw === \"string\"\n    ? parseQuizJson(raw)\n    : raw;\n\nreturn [quiz];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        3120,
        3508
      ],
      "id": "7b95f4e3-02a7-4173-9216-cd7df5d7b148",
      "name": "Code in JavaScript3"
    },
    {
      "parameters": {
        "table": {
          "__rl": true,
          "value": "fisa_quiz_questions",
          "mode": "list",
          "cachedResultName": "fisa_quiz_questions"
        },
        "dataMode": "defineBelow",
        "valuesToSend": {
          "values": [
            {
              "column": "question_id",
              "value": "={{ $json.id }}"
            },
            {
              "column": "type",
              "value": "={{ $json.type }}"
            },
            {
              "column": "question",
              "value": "={{ $json.question }}"
            },
            {
              "column": "explanation",
              "value": "={{ $json.explanation }}"
            },
            {
              "column": "answer",
              "value": "={{ $json.answer }}"
            },
            {
              "column": "options",
              "value": "={{ JSON.stringify($json.options) }}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.mySql",
      "typeVersion": 2.5,
      "position": [
        3792,
        3412
      ],
      "id": "2e173f2e-6907-4555-8ae7-c5f9bae0dd48",
      "name": "Insert rows in a table2",
      "credentials": {
        "mySql": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Loop over input items and add a new field called 'myNewField' to the JSON of each one\n\nreturn $input.all() ? $input.all() : [];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1184,
        3508
      ],
      "id": "332157c7-e184-4792-8aa6-bb18f33aa689",
      "name": "Code in JavaScript4"
    },
    {
      "parameters": {
        "modelId": {
          "__rl": true,
          "value": "gpt-4.1",
          "mode": "list",
          "cachedResultName": "GPT-4.1"
        },
        "responses": {
          "values": [
            {
              "content": "=### INPUT DATA:\n{{ $json.data.map(JSON.stringify) }}\n\n### TASK:\nAnalyze the input and output a structured technical summary.\n\n### GUIDELINES:\n1. TOPICS: Identify the 3 most discussed technical categories.\n2. KEYWORDS: Extract 5-7 specific technical terms or commands.\n3. CONTEXT: Summarize the main technical challenge students faced this week in 2 sentences.\n\n### OUTPUT FORMAT:\nCore_Topics: <topic1, topic2, topic3>\nKey_Keywords: <key1, key2, key3, key4, key5>\nTechnical_Summary: <Your 2-sentence summary here>\n\n### FILTER:\nImmediately discard any data related to \"schedules\", \"lunch\", \"links\", or \"personal talk\"."
            }
          ]
        },
        "builtInTools": {},
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "typeVersion": 2.1,
      "position": [
        1632,
        3508
      ],
      "id": "de74a02e-293d-4458-baca-0ab7e7fab0ce",
      "name": "\uc9c8\ubb38 \uc694\uc57d",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "mode": "retrieve-as-tool",
        "toolDescription": "\uc218\uc5c5 \uad50\uc548\uc790\ub8cc\n",
        "pineconeIndex": {
          "__rl": true,
          "value": "woorifisa-blogs",
          "mode": "list",
          "cachedResultName": "woorifisa-blogs"
        },
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.vectorStorePinecone",
      "typeVersion": 1.3,
      "position": [
        2464,
        3524
      ],
      "id": "963b4ef3-80bc-4368-99f7-c2c6a4f1b770",
      "name": "blog store(read)1",
      "credentials": {
        "pineconeApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "options": {
          "dimensions": 1024
        }
      },
      "type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi",
      "typeVersion": 1.2,
      "position": [
        2544,
        3732
      ],
      "id": "64128df7-515a-4387-920e-83b5e8d42b05",
      "name": "Embeddings OpenAI6",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "options": {
          "dimensions": 1024
        }
      },
      "type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi",
      "typeVersion": 1.2,
      "position": [
        2832,
        3732
      ],
      "id": "8ffa7518-3ced-4562-b0b6-b1b800e16d54",
      "name": "Embeddings OpenAI5",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "mode": "retrieve-as-tool",
        "toolDescription": "You are a retrieval-based assistant.\n\nThe knowledge base is a unified vector store containing embedded documents.\nEach document includes a metadata field called \"type\" that identifies its source:\n\n- type: \"material\" \u2192 official lecture materials and course handouts\n- type: \"blog\" \u2192 study journal blog posts written during learning\n\nThe lecture materials are related to:\n- Java Spring\n- Docker\n- Cloud and infrastructure concepts\n\nEach document includes:\n- Content\n- A title\n- A brief summary\n- A reference (file name, document link, or URL)\n\nWhen a user asks a question, follow these rules strictly:\n\n1. Retrieve the most relevant documents from the vector store using semantic similarity.\n2. Use ONLY the retrieved documents to construct the answer.\n3. Do NOT use prior knowledge, general knowledge, or assumptions.\n4. Separate retrieved documents based on their \"type\" metadata:\n   - Documents with type \"material\" must be placed in the \"materials\" array.\n   - Documents with type \"blog\" must be placed in the \"blogs\" array.\n\nResponse rules:\n- The response MUST be returned strictly in JSON format.\n- Do NOT include any text outside the JSON response.\n- Do NOT invent or infer any information.\n- Use only the exact metadata provided in the retrieved documents.\n- If no relevant documents exist for a section, return an empty array for that section.\n\nThe JSON response must follow this exact structure:\n\n{\n  \"answer\": string,\n  \"materials\": [\n    {\n      \"title\": string,\n      \"summary\": string,\n      \"reference\": string\n    }\n  ],\n  \"blogs\": [\n    {\n      \"title\": string,\n      \"summary\": string,\n      \"link\": string\n    }\n  ]\n}\n\nAdditional constraints:\n- \"materials\" and \"blogs\" must always be arrays.\n- Include only documents that are directly relevant to the user's question.\n- If no documents are relevant at all, return an empty array for both \"materials\" and \"blogs\", and keep \"answer\" concise and based only on retrieved content (or empty if nothing is retrieved).\n",
        "pineconeIndex": {
          "__rl": true,
          "value": "woorifisa-lectures",
          "mode": "list",
          "cachedResultName": "woorifisa-lectures"
        },
        "topK": 5,
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.vectorStorePinecone",
      "typeVersion": 1.3,
      "position": [
        2752,
        3524
      ],
      "id": "eeb5061b-f94e-490a-8080-bc7e1cb0d223",
      "name": "lecture store(read)1",
      "credentials": {
        "pineconeApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
  

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

How this works

This workflow automates the extraction and organisation of financial data from Korean sources, delivering timely insights directly into your Notion workspace to streamline research and reporting. It's ideal for financial analysts, compliance officers, or educators tracking market trends who need reliable, scheduled updates without manual effort. The core step involves an AI agent processing crawled data via HTTP requests, loading documents for analysis, and storing vectors in Pinecone for efficient retrieval and querying with OpenAI embeddings.

Use this workflow for daily or weekly monitoring of regulatory updates and financial news in the Korean market, especially when integrating with Notion for collaborative lesson plans or reports. Avoid it for real-time alerts, as the cron triggers focus on batch processing rather than instant responses; opt for simpler scrapers if you lack Pinecone setup. Common variations include adjusting schedules for monthly runs or adding filters for specific sectors like banking regulations.

About this workflow

WooriFisa. Uses agent, httpRequest, documentDefaultDataLoader, vectorStorePinecone. Scheduled trigger; 86 nodes.

Source: https://github.com/woorifisa-6th-n8n-chatbot-team/woorifisa-n8n-project/blob/117743d5ec86aa20d47ee91f806659d04904358a/flows/WooriFisa.json — 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

Supercharge your trading decisions with this end-to-end AI automation that connects market intelligence, technical analysis, and automated trade execution — all without manual intervention.

Tool Think, Supabase Vector Store, OpenAI Embeddings +14
AI & RAG

This workflow automates patient communication for medical clinics using the WhatsApp Business API. It supports appointment booking, rescheduling, service inquiries, follow-ups, and document submission

Google Sheets, Data Table, Data Table Tool +12
AI & RAG

WooriFisa 최종. Uses memoryMongoDbChat, agent, httpRequest, documentDefaultDataLoader. Scheduled trigger; 68 nodes.

Memory Mongo Db Chat, Agent, HTTP Request +14
AI & RAG

Tech Radar. Uses googleDrive, documentDefaultDataLoader, stickyNote, mySql. Scheduled trigger; 53 nodes.

Google Drive, Document Default Data Loader, MySQL +15
AI & RAG

This project is built on top of the famous open source ThoughtWorks Tech Radar.

Google Drive, Document Default Data Loader, MySQL +15