{
  "id": "72MkDQmQhXVdN197",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "QA News Feed",
  "tags": [],
  "nodes": [
    {
      "id": "f3668b13-71b2-4699-a696-380332edbf93",
      "name": "Remove Duplicates",
      "type": "n8n-nodes-base.removeDuplicates",
      "position": [
        1424,
        288
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 2
    },
    {
      "id": "7a5f539c-6395-4233-ac90-181f0c83193d",
      "name": "No Operation, do nothing",
      "type": "n8n-nodes-base.noOp",
      "position": [
        80,
        96
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "a0e7b809-02d4-4041-b3f0-a10a5d99ef25",
      "name": "No Operation, do nothing1",
      "type": "n8n-nodes-base.noOp",
      "position": [
        2096,
        240
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "5514a4b9-65a2-4072-b204-b550bcdc0dda",
      "name": "Input Feeds List",
      "type": "n8n-nodes-base.set",
      "position": [
        -592,
        240
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "444ac845-ac2b-4d33-87f5-37c40f234052",
              "name": "urls",
              "type": "array",
              "value": "['https://www.thetesttribe.com/feed/','https://medium.com/feed/tag/qa-testing','https://www.cypress.io/feed.xml','https://dev.to/feed']"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "d3e27ee6-0184-42f7-952b-eff2674792ca",
      "name": "Read Feed",
      "type": "n8n-nodes-base.rssFeedRead",
      "position": [
        80,
        288
      ],
      "parameters": {
        "url": "={{ $json.urls }}",
        "options": {}
      },
      "typeVersion": 1.2
    },
    {
      "id": "2f2fc835-4cd1-4722-a18a-fd83710bd864",
      "name": "Extract Data",
      "type": "n8n-nodes-base.set",
      "position": [
        304,
        288
      ],
      "parameters": {
        "options": {
          "dotNotation": true,
          "ignoreConversionErrors": true
        },
        "assignments": {
          "assignments": [
            {
              "id": "7b13be15-3034-46e3-8236-ab9f6ea081ab",
              "name": "title",
              "type": "string",
              "value": "={{ $json.title }}"
            },
            {
              "id": "97433edd-cabd-4291-ba77-4d50e41c1577",
              "name": "link",
              "type": "string",
              "value": "={{ $json.link }}"
            },
            {
              "id": "fb85da11-7b2f-4594-9352-c63ee971b021",
              "name": "contentSnippet",
              "type": "string",
              "value": "={{ $json.contentSnippet }}"
            },
            {
              "id": "f2cfe536-f53f-4bf3-a2d3-35c07dc2a89f",
              "name": "pubDate",
              "type": "string",
              "value": "={{ $json.isoDate }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "38f9e7ad-9b63-4fd9-af31-727d714704ae",
      "name": "Get Current Date",
      "type": "n8n-nodes-base.dateTime",
      "position": [
        528,
        288
      ],
      "parameters": {
        "options": {
          "includeInputFields": true
        }
      },
      "typeVersion": 2
    },
    {
      "id": "8326a5eb-ea7b-4b25-96f2-dcce51662eda",
      "name": "Get Feed Published Date",
      "type": "n8n-nodes-base.dateTime",
      "position": [
        752,
        288
      ],
      "parameters": {
        "date": "={{ $json.pubDate }}",
        "options": {
          "includeInputFields": true
        },
        "operation": "formatDate",
        "outputFieldName": "publishedDate"
      },
      "typeVersion": 2
    },
    {
      "id": "989ce6e6-5869-417c-8bd6-ffeecb41c826",
      "name": "Formatted Current Date",
      "type": "n8n-nodes-base.dateTime",
      "position": [
        976,
        288
      ],
      "parameters": {
        "date": "={{ $json.currentDate }}",
        "options": {
          "includeInputFields": true
        },
        "operation": "formatDate",
        "outputFieldName": "currentDate"
      },
      "typeVersion": 2
    },
    {
      "id": "dfc71ba7-7c91-49de-9322-eda7df2c5ae6",
      "name": "Wait for 10 seconds",
      "type": "n8n-nodes-base.wait",
      "position": [
        2096,
        432
      ],
      "parameters": {
        "amount": 10
      },
      "typeVersion": 1.1
    },
    {
      "id": "470ddeac-033f-476e-b5ba-5f82ad4a0a5e",
      "name": "Loop Over Feed URL's",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        -144,
        240
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "f2adc0a7-3749-4c9f-ae49-dca63bf8bc77",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2384,
        -848
      ],
      "parameters": {
        "width": 672,
        "height": 704,
        "content": "## QA News Intelligence Engine\nThis workflow automatically transforms raw QA RSS feeds into curated, AI-summarized updates sent to Telegram every 3 hours.\n\n### How it works:\n\nCollects news from multiple RSS sources (The Test Tribe, Medium, Cypress, and Dev.to).\n\nNormalizes data and filters for specific keywords like \"Playwright,\" \"Quality,\" and \"Testing.\"\n\nUses a two-step process to remove duplicates within the current execution and compares items against previous executions.\n\nProcesses news in batches of 5. It first attempts to use Gemini to create a 3-bullet technical summary.\n\nIf Gemini fails or returns an empty result, the workflow automatically switches to OpenAI (GPT-4o-mini) to generate the summary.\n\nSends the title, link, and AI summary to a Telegram group with a 10-second delay to manage rate limits.\n\n### How to set up:\n\nCredentials: Connect your Telegram Bot, Google Gemini (PaLM), and OpenAI API accounts.\n\nTelegram: Enter your specific Chat ID in the Telegram nodes.\n\nScheduling: The trigger is set to 3 hours but can be adjusted in the \"Schedule Trigger\" node."
      },
      "typeVersion": 1
    },
    {
      "id": "1f3d8d4d-0be0-4591-a3a7-054293b683f9",
      "name": "Remove Duplicates Comparing with Prev Exec",
      "type": "n8n-nodes-base.removeDuplicates",
      "position": [
        1648,
        288
      ],
      "parameters": {
        "options": {},
        "operation": "removeItemsSeenInPreviousExecutions",
        "dedupeValue": "={{ $json.title }}{{ $json.link }}"
      },
      "typeVersion": 2
    },
    {
      "id": "770ddc2f-fdc6-43a1-8baf-1f3a82ec0704",
      "name": "OpenAI",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        3120,
        240
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o-mini",
          "cachedResultName": "GPT-4O-MINI"
        },
        "options": {
          "maxTokens": 500
        },
        "responses": {
          "values": [
            {
              "content": "=Summarize the following QA news article in 3 concise bullet points.\\n\\nTitle:{{ $('Wait for 10 seconds').item.json.title }} \\n\\nContent:{{ $('Wait for 10 seconds').item.json.link }} \\n\\nKeep it technical and relevant for QA engineers.The result only the raw text, no JSON formatting, no curly braces, and no markdown code blocks. Make sure sentences are complete"
            },
            {
              "role": "system",
              "content": "You are a senior QA automation engineer"
            }
          ]
        },
        "builtInTools": {}
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "ee3bf2b2-2335-4a17-befb-53f6237b6b41",
      "name": "Gemini",
      "type": "@n8n/n8n-nodes-langchain.googleGemini",
      "onError": "continueRegularOutput",
      "position": [
        2320,
        432
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "models/gemini-2.5-flash",
          "cachedResultName": "models/gemini-2.5-flash"
        },
        "options": {
          "temperature": 0.4,
          "maxOutputTokens": 900
        },
        "messages": {
          "values": [
            {
              "content": "=Summarize the following QA news article in 3 concise bullet points.\\n\\nTitle: {{$json.title}}\\n\\nContent: {{$json.contentSnippet}}\\n\\nKeep it technical, well formatted and relevant for QA engineers.The result only the raw text, no JSON formatting, no curly braces, and no markdown code blocks. Make sure sentences are completed\""
            }
          ]
        },
        "builtInTools": {}
      },
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "df7ae9f3-2d01-45ad-9669-0a8a52ad7833",
      "name": "Set Gemini AI Summary",
      "type": "n8n-nodes-base.set",
      "position": [
        2672,
        432
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "7e22b3ed-1581-4354-a301-167a3afe7f80",
              "name": "aiSummary",
              "type": "string",
              "value": "={{ $json.content.parts[0].text }}"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "c7a7bba3-7832-45a2-b6dd-ce11e98bc81c",
      "name": "Set OpenAI summary",
      "type": "n8n-nodes-base.set",
      "position": [
        3472,
        240
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "51251581-ccff-4594-85ab-418082578d08",
              "name": "aiSummary",
              "type": "string",
              "value": "={{$json.output[0].content[0].text}}"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "5c411184-4193-4d5c-8dff-83ef156296b0",
      "name": "Loop Over Items",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        3696,
        176
      ],
      "parameters": {
        "options": {},
        "batchSize": 3
      },
      "typeVersion": 3
    },
    {
      "id": "e98ccf9c-9bb3-4348-81af-91c14056212c",
      "name": "No Operation, do nothing2",
      "type": "n8n-nodes-base.noOp",
      "position": [
        3920,
        0
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "a4a66863-d42a-4e97-ac92-498f32b153bf",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -528,
        -112
      ],
      "parameters": {
        "color": 7,
        "width": 1184,
        "height": 640,
        "content": "## Section 1: Sources & ingestion\n\n\nCollect RSS feeds, split URLs, and extract article data (title, link, snippet) for processing."
      },
      "typeVersion": 1
    },
    {
      "id": "8644d889-4f0f-4fe7-bc65-026b3964c688",
      "name": "Date Formatting and Relevance",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        480,
        -128
      ],
      "parameters": {
        "color": 7,
        "width": 864,
        "height": 704,
        "content": "## Section 2: Date filtering\n\nNormalize publication dates and compare with current date to keep only recent articles."
      },
      "typeVersion": 1
    },
    {
      "id": "ba6387c6-1d2a-4192-b609-51b328ffc832",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1392,
        -112
      ],
      "parameters": {
        "color": 7,
        "width": 432,
        "height": 560,
        "content": "## Section 3: Content Refining\nRemove duplicate articles within the run and across previous executions using title + link."
      },
      "typeVersion": 1
    },
    {
      "id": "4e907d84-5792-4003-8033-823222ead2ce",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2320,
        288
      ],
      "parameters": {
        "color": 7,
        "width": 672,
        "height": 336,
        "content": "## Section 4: AI summarization\nManages the dual-AI logic. If the primary Gemini summary is empty or errors out, the \"If\" node routes the task to OpenAI."
      },
      "typeVersion": 1
    },
    {
      "id": "6c19780a-25e2-47b7-a789-b75f3ff48d6e",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3120,
        -96
      ],
      "parameters": {
        "color": 7,
        "width": 1056,
        "height": 784,
        "content": "## Section 5: Delivery\nBatch process final articles and send summaries to Telegram with delay to avoid rate limits."
      },
      "typeVersion": 1
    },
    {
      "id": "84df91cf-eb40-4390-8001-32103130c5e2",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2016,
        -176
      ],
      "parameters": {
        "color": 3,
        "width": 256,
        "height": 656,
        "content": "## CRITICAL: Rate Limiting & Credentials\n\n### Wait Node: Do not remove the 10-second wait node; it is essential to prevent Telegram from blocking the bot during high-volume news cycles.\n\n### AI Error Handling: The Gemini node is set to \"Continue Regular Output\" on error to allow the OpenAI fallback to function correctly."
      },
      "typeVersion": 1
    },
    {
      "id": "828d66ac-f710-456a-80f2-9351c8c2fa9a",
      "name": "Loop over filtered news",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        1872,
        288
      ],
      "parameters": {
        "options": {},
        "batchSize": 5
      },
      "typeVersion": 3
    },
    {
      "id": "34e39c05-8d3f-4a54-989d-688bd67d2178",
      "name": "Schedular",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -816,
        240
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours",
              "hoursInterval": 3
            }
          ]
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "9e767616-3200-49fd-873c-84a0a0508471",
      "name": "Fetch one url at a time",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        -368,
        240
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "urls"
      },
      "typeVersion": 1
    },
    {
      "id": "4878fe97-27aa-407b-9526-332b18aa7180",
      "name": "Filter by today's news",
      "type": "n8n-nodes-base.filter",
      "position": [
        1200,
        288
      ],
      "parameters": {
        "options": {
          "ignoreCase": true
        },
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": false,
            "typeValidation": "strict"
          },
          "combinator": "or",
          "conditions": [
            {
              "id": "8a197153-47d0-4dde-86bb-8320b060031f",
              "operator": {
                "type": "dateTime",
                "operation": "equals"
              },
              "leftValue": "={{$json.publishedDate}}",
              "rightValue": "={{ $json.currentDate }}"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "e559815e-a2c7-44e6-988b-c0bb66ac6260",
      "name": "Send News To Telegram Channel",
      "type": "n8n-nodes-base.telegram",
      "position": [
        3184,
        432
      ],
      "parameters": {
        "text": "=Title : {{ $('Wait for 10 seconds').item.json.title }}\nLink: {{ $('Wait for 10 seconds').item.json.link }}\nGist of the news:{{ $json.aiSummary }}",
        "chatId": "123456789",
        "additionalFields": {
          "parse_mode": "HTML",
          "appendAttribution": false,
          "disable_web_page_preview": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "7d2054b5-51cc-4d24-b4c4-97cde5a2d8bd",
      "name": "Send News To Telegram Channel1",
      "type": "n8n-nodes-base.telegram",
      "position": [
        3920,
        240
      ],
      "parameters": {
        "text": "=Title : {{ $('Wait for 10 seconds').item.json.title }}\nLink:{{ $('Wait for 10 seconds').item.json.link }}\nGist of the news:{{ $json.aiSummary }}",
        "chatId": "123456789",
        "additionalFields": {
          "parse_mode": "HTML",
          "appendAttribution": false,
          "disable_web_page_preview": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "0e69d4e7-e454-40f2-8e77-8a1f3cf0b839",
      "name": "Check AI Summary or error",
      "type": "n8n-nodes-base.if",
      "position": [
        2896,
        432
      ],
      "parameters": {
        "options": {
          "ignoreCase": true
        },
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": false,
            "typeValidation": "loose"
          },
          "combinator": "or",
          "conditions": [
            {
              "id": "e57c58fc-2b9b-4dc8-802b-905bcd7f229e",
              "operator": {
                "type": "string",
                "operation": "empty",
                "singleValue": true
              },
              "leftValue": "={{ $json.aiSummary }}",
              "rightValue": ""
            },
            {
              "id": "833c39d8-1abd-426c-8875-5ef489e6270c",
              "operator": {
                "type": "string",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.error }}",
              "rightValue": ""
            }
          ]
        },
        "looseTypeValidation": true
      },
      "typeVersion": 2.3
    }
  ],
  "active": true,
  "settings": {
    "binaryMode": "separate",
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "82028cdb-5bcc-494f-a383-6c6041a3dad7",
  "connections": {
    "Gemini": {
      "main": [
        [
          {
            "node": "Set Gemini AI Summary",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI": {
      "main": [
        [
          {
            "node": "Set OpenAI summary",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Feed": {
      "main": [
        [
          {
            "node": "Loop Over Feed URL's",
            "type": "main",
            "index": 0
          },
          {
            "node": "Extract Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedular": {
      "main": [
        [
          {
            "node": "Input Feeds List",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Data": {
      "main": [
        [
          {
            "node": "Get Current Date",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over Items": {
      "main": [
        [
          {
            "node": "No Operation, do nothing2",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Send News To Telegram Channel1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Current Date": {
      "main": [
        [
          {
            "node": "Get Feed Published Date",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Input Feeds List": {
      "main": [
        [
          {
            "node": "Fetch one url at a time",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Remove Duplicates": {
      "main": [
        [
          {
            "node": "Remove Duplicates Comparing with Prev Exec",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set OpenAI summary": {
      "main": [
        [
          {
            "node": "Send News To Telegram Channel1",
            "type": "main",
            "index": 0
          },
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait for 10 seconds": {
      "main": [
        [
          {
            "node": "Loop over filtered news",
            "type": "main",
            "index": 0
          },
          {
            "node": "Gemini",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over Feed URL's": {
      "main": [
        [
          {
            "node": "No Operation, do nothing",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Read Feed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Gemini AI Summary": {
      "main": [
        [
          {
            "node": "Check AI Summary or error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter by today's news": {
      "main": [
        [
          {
            "node": "Remove Duplicates",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Formatted Current Date": {
      "main": [
        [
          {
            "node": "Filter by today's news",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch one url at a time": {
      "main": [
        [
          {
            "node": "Loop Over Feed URL's",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Feed Published Date": {
      "main": [
        [
          {
            "node": "Formatted Current Date",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop over filtered news": {
      "main": [
        [
          {
            "node": "No Operation, do nothing1",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Wait for 10 seconds",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check AI Summary or error": {
      "main": [
        [
          {
            "node": "OpenAI",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Send News To Telegram Channel",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send News To Telegram Channel1": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Remove Duplicates Comparing with Prev Exec": {
      "main": [
        [
          {
            "node": "Loop over filtered news",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}