{
  "id": "vM9vVAYcheFEXgk0",
  "meta": {
    "instanceId": "8443f10082278c46aa5cf3acf8ff0f70061a2c58bce76efac814b16290845177"
  },
  "name": "Generate Release Notes Using ClickUp + GPT-4o + Notion + Slack",
  "tags": [],
  "nodes": [
    {
      "id": "d2d1f6df-b89b-435b-aa69-c6a7e84bd982",
      "name": "Validate Incoming ClickUp Task Event",
      "type": "n8n-nodes-base.if",
      "position": [
        -1344,
        -240
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "e2adb005-2b3c-4d1e-8445-442df1fe925a",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $json.task_id }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "8ae9f883-49df-464d-bf5a-fa6351c51a5f",
      "name": "Log Invalid ClickUp Events to Google Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -928,
        128
      ],
      "parameters": {
        "columns": {
          "value": {},
          "schema": [
            {
              "id": "error_id",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "error_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "error",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "error",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "error_id"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 1338537721,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1Uldk_4BxWbdZTDZxFUeohIfeBmGHHqVEl9Ogb0l6R8Y/edit#gid=1338537721",
          "cachedResultName": "error log sheet"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1Uldk_4BxWbdZTDZxFUeohIfeBmGHHqVEl9Ogb0l6R8Y",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1Uldk_4BxWbdZTDZxFUeohIfeBmGHHqVEl9Ogb0l6R8Y/edit?usp=drivesdk",
          "cachedResultName": "Interviewer Brief Pack "
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "credential-id",
          "name": "googleSheetsOAuth2Api Credential"
        }
      },
      "typeVersion": 4.6
    },
    {
      "id": "c884e43d-5823-481d-a0cb-f43c8b471326",
      "name": "Fetch Full Task Details from ClickUp",
      "type": "n8n-nodes-base.clickUp",
      "position": [
        -640,
        -256
      ],
      "parameters": {
        "id": "={{ $json.task_id }}",
        "operation": "get"
      },
      "credentials": {
        "clickUpApi": {
          "id": "credential-id",
          "name": "clickUpApi Credential"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "3f7c53f1-c1df-4762-84f5-75b534a1de5b",
      "name": "Extract Clean Task Fields from ClickUp Data",
      "type": "n8n-nodes-base.code",
      "position": [
        -384,
        -256
      ],
      "parameters": {
        "jsCode": "// Extract ClickUp task details safely\nconst task = $json;\n\n// Handle cases where arrays or fields might be empty\nconst assignee = (task.assignees && task.assignees.length > 0) ? task.assignees[0] : {};\nconst customFields = task.custom_fields || [];\n\n// Try to find the first field with a value (like a GitHub or docs link)\nconst linkField = customFields.find(f => f.value) || {};\n\nreturn [\n  {\n    json: {\n      title: task.name || \"Untitled Task\",\n      description: task.description || \"No description available.\",\n      status: task.status?.status || \"No status\",\n      priority: task.priority?.priority || \"Not set\",\n      due_date: task.due_date || \"No due date\",\n      assignee: assignee.username || \"Unassigned\",\n      email: assignee.email || \"No email\",\n      link: linkField.value || \"No link provided\",\n      url: task.url || \"No URL\",\n    },\n  },\n];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "f4559864-e4de-4d2b-9427-7bc7a15ea5fc",
      "name": "Provide GPT-4o Model for Release Notes Generation",
      "type": "@n8n/n8n-nodes-langchain.lmChatAzureOpenAi",
      "position": [
        1136,
        16
      ],
      "parameters": {
        "model": "gpt-4o",
        "options": {}
      },
      "credentials": {
        "azureOpenAiApi": {
          "id": "credential-id",
          "name": "azureOpenAiApi Credential"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "77d63c36-df56-4f12-9c10-d060b5fd6e3c",
      "name": "Generate Structured Release Notes via AI",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        1136,
        -240
      ],
      "parameters": {
        "text": "=Create Smart Release Notes from this task:\n\nTask Title: {{$json.title}}\nDescription: {{$json.description}}\nStatus: {{$json.status}}\nPriority: {{$json.priority}}\nDue Date: {{$json.due_date}}\nAssignee: {{$json.assignee}} ({{$json.email}})\nTask URL: {{$json.url}}\nReference Link: {{$json.link}}\n\nFormat the output EXACTLY like this (keep the headings):\n\n## 🚀 Release Notes – {{$json.title}}\n\n### 🔧 Summary\n- 1–2 bullets summarising what changed\n\n### ✨ Improvements & New Features\n- Bullet list of user-facing improvements and changes\n\n### 🐞 Bug Fixes\n- Bullet list of fixes\n- If you don't see any fixes, write: \"No bug fixes mentioned.\"\n\n### 📘 Impact Analysis\n- Who is affected?\n- Any dependencies or sensitive areas touched?\n- Overall risk level (low/medium/high) based on your judgement\n\n### ⚠ Known Issues\n- Potential or known issues to watch out for\n- If there are none, write: \"None known at this time.\"\n",
        "options": {
          "systemMessage": "=You are a professional release notes writer for a product team.\nYour job is to turn raw task data into clear, structured, non-marketing release notes.\n\nRules:\n- Always follow the given section headings and order.\n- Keep language simple and easy to skim.\n- Prefer bullet points over long paragraphs.\n- Do NOT write an FAQ. Only write release notes in the requested format.\n"
        },
        "promptType": "define"
      },
      "typeVersion": 2.1
    },
    {
      "id": "bf7b20b8-23af-4511-b487-574c9a0d07a5",
      "name": "Extract Release Notes Title & Final Output",
      "type": "n8n-nodes-base.code",
      "position": [
        1536,
        -240
      ],
      "parameters": {
        "jsCode": "const ai = items[0].json;\n\n// extract first markdown heading as title\nconst firstLine = ai.output.split(\"\\n\")[0].replace(\"## \", \"\").trim();\n\nreturn [\n  {\n    json: {\n      title: firstLine,\n      release_notes: ai.output\n    }\n  }\n];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "483b81ea-b25f-43ef-9930-6d09725d763f",
      "name": "Create Release Notes Page in Notion",
      "type": "n8n-nodes-base.notion",
      "position": [
        1824,
        -240
      ],
      "parameters": {
        "title": "={{ $json.title }}",
        "simple": false,
        "options": {},
        "resource": "databasePage",
        "databaseId": {
          "__rl": true,
          "mode": "list",
          "value": "29a802b9-1fa0-804a-b406-e078961e0659",
          "cachedResultUrl": "https://www.notion.so/29a802b91fa0804ab406e078961e0659",
          "cachedResultName": "Release Notes"
        },
        "propertiesUi": {
          "propertyValues": [
            {
              "key": "Description|rich_text",
              "text": {
                "text": [
                  {
                    "text": "={{ $json.release_notes }}",
                    "annotationUi": {}
                  }
                ]
              },
              "richText": true
            }
          ]
        }
      },
      "credentials": {
        "notionApi": {
          "id": "credential-id",
          "name": "notionApi Credential"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "f1e2aaed-c1ce-4a4a-ad50-55d7aed709eb",
      "name": "Post Release Announcement to Slack",
      "type": "n8n-nodes-base.slack",
      "position": [
        2112,
        -240
      ],
      "webhookId": "ddaa7632-9e35-4bd3-82d6-572d5cae84cc",
      "parameters": {
        "text": "=🚀 *Release Deployed*\n\n*Feature:* {{ $('Extract Release Notes Title & Final Output').item.json.title }}\n\n📘 *Summary:*\n{{ $('Extract Release Notes Title & Final Output').item.json.release_notes }}\n\n🔗 View full notes in Notion:\n{{ $json.url }}",
        "user": {
          "__rl": true,
          "mode": "list",
          "value": "U09HMPVD466",
          "cachedResultName": "newscctv22"
        },
        "select": "user",
        "otherOptions": {}
      },
      "credentials": {
        "slackApi": {
          "id": "credential-id",
          "name": "slackApi Credential"
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "b316cb94-8507-4f0c-b897-762535d1e24e",
      "name": "Append Release Log Entry to Google Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2432,
        -240
      ],
      "parameters": {
        "columns": {
          "value": {
            "Notes": "Auto-generated release log entry",
            "Title": "={{ $('Extract Clean Task Fields from ClickUp Data').first().json.title }}",
            "Module": "={{ $('Combine Task Info + Metadata into Final Payload').item.json.module }}",
            "Task ID": "={{ $('Code in JavaScript').first().json.task_id }}",
            "Priority": "={{ $('Extract Clean Task Fields from ClickUp Data').first().json.priority }}",
            "Notion URL": "={{ $('Create Release Notes Page in Notion').item.json.url }}",
            "Risk Level": "={{ $('Combine Task Info + Metadata into Final Payload').item.json.risk_level }}",
            "Released On": "={{new Date().toISOString().split('T')[0]}}",
            "Slack Message URL": "={{ $json.message.blocks[0].elements[0].elements[29].url }}"
          },
          "schema": [
            {
              "id": "Task ID",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Task ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Title",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Title",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Priority",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Priority",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Module",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Module",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Risk Level",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Risk Level",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Released On",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Released On",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Notion URL",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Notion URL",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Slack Message URL",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Slack Message URL",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Notes",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Notes",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 2120450248,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/17rcNd_ZpUQLm0uWEVbD-NY6GyFUkrD4BglvawlyBygM/edit#gid=2120450248",
          "cachedResultName": "Updated Release Notes Flow"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "17rcNd_ZpUQLm0uWEVbD-NY6GyFUkrD4BglvawlyBygM",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/17rcNd_ZpUQLm0uWEVbD-NY6GyFUkrD4BglvawlyBygM/edit?usp=drivesdk",
          "cachedResultName": "sample_leads_50"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "credential-id",
          "name": "googleSheetsOAuth2Api Credential"
        }
      },
      "typeVersion": 4.6
    },
    {
      "id": "2722eac8-dc0e-4566-8f44-c36cf4a3f299",
      "name": "Send Release Summary Email",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2336,
        -608
      ],
      "webhookId": "0c82c299-6938-42ed-bda6-5007d79af34f",
      "parameters": {
        "sendTo": "=gargsaurabh1804april@gmail.com",
        "message": "=<h2>🚀 New Release Published</h2>\n\n<p><b>Feature:</b> {{ $('Extract Release Notes Title & Final Output').item.json.title }}</p>\n\n<p><b>Summary:</b></p>\n<pre>{{ $('Extract Release Notes Title & Final Output').item.json.release_notes.split(\"\\n\\n\")[1] }}</pre>\n\n<p><b>Full Release Notes:</b></p>\n<pre>{{ $('Extract Release Notes Title & Final Output').item.json.release_notes }}</pre>\n\n<p><b>Notion Page:</b> \n<a href=\"{{ $('Create Release Notes Page in Notion').item.json.url }}\">\nClick here to view</a>\n</p>\n\n<p><b>Released On:</b> {{ new Date().toISOString().split(\"T\")[0] }}</p>\n",
        "options": {},
        "subject": "=New Release Published – {{ $('Extract Release Notes Title & Final Output').item.json.title }}"
      },
      "credentials": {
        "gmailOAuth2": {
          "id": "credential-id",
          "name": "gmailOAuth2 Credential"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "90d26ead-66a7-462c-8652-c86ea79edf6f",
      "name": "Provide GPT-4o Model for Metadata Extraction",
      "type": "@n8n/n8n-nodes-langchain.lmChatAzureOpenAi",
      "position": [
        -128,
        256
      ],
      "parameters": {
        "model": "gpt-4o",
        "options": {}
      },
      "credentials": {
        "azureOpenAiApi": {
          "id": "credential-id",
          "name": "azureOpenAiApi Credential"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "7d029983-92a9-440c-a2e5-e1f40469aa05",
      "name": "Generate Release Metadata via AI",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        -96,
        32
      ],
      "parameters": {
        "text": "=Analyze the task details below and extract structured metadata useful for release management.\n\nTask Data:\n{{ JSON.stringify($json, null, 2) }}\n\nReturn ONLY a valid JSON object with the following fields:\n\n{\n  \"risk_level\": \"low | medium | high\",\n  \"change_type\": \"feature | fix | enhancement | refactor\",\n  \"module\": \"backend | frontend | ui | automation | analytics | other\",\n  \"impact_score\": 1-10,\n  \"requires_testing\": true or false\n}\n\nRules:\n- Be accurate and concise.\n- Infer values from description, priority, and status.\n- If uncertain, make the best logical guess.\n",
        "options": {
          "systemMessage": "=You are a senior engineering analyst. \nYour job is to classify changes based on risk, complexity, and module.\nAlways return clean JSON. No explanations.\n"
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 2.1
    },
    {
      "id": "d90c385e-8db7-4e1e-9740-467bf26066a6",
      "name": "Parse AI Metadata JSON Output",
      "type": "n8n-nodes-base.code",
      "position": [
        256,
        32
      ],
      "parameters": {
        "jsCode": "// The AI node returns metadata as a STRING inside output.\n// Example: \"{ \\\"risk_level\\\": \\\"medium\\\", ... }\"\n\n// Grab the raw string from the previous node\nconst rawString = $json.output;\n\n// Safely parse it into a real JSON object\nlet parsed = {};\ntry {\n  parsed = JSON.parse(rawString);\n} catch (error) {\n  // If parsing fails, return an error structure\n  parsed = {\n    error: \"Failed to parse AI metadata JSON\",\n    raw_output: rawString\n  };\n}\n\n// Return as proper JSON to the next node\nreturn [\n  {\n    json: parsed\n  }\n];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "e2068588-bd5c-4dcf-b027-3a4c38ab6fef",
      "name": "Merge Task Details with Metadata",
      "type": "n8n-nodes-base.merge",
      "position": [
        592,
        -240
      ],
      "parameters": {},
      "typeVersion": 3.2
    },
    {
      "id": "ebccabcd-da53-4381-a375-29ace5e46589",
      "name": "Combine Task Info + Metadata into Final Payload",
      "type": "n8n-nodes-base.code",
      "position": [
        832,
        -240
      ],
      "parameters": {
        "jsCode": "// Input 0 = Task Details from \"Parse Task Details\"\n// Input 1 = Metadata from \"Code (Parsed Metadata)\"\nconst task = items[0].json;\nconst meta = items[1].json;\n\n// Merge both objects into a single final object\nconst combined = {\n  ...task,   // expands all task fields\n  ...meta    // expands all metadata fields\n};\n\n// Return the combined object as one item\nreturn [{ json: combined }];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "6d8cfcfd-1ec0-4017-a488-6f49a1713bba",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2528,
        -1136
      ],
      "parameters": {
        "width": 816,
        "height": 464,
        "content": "## 🚀 Generate Release Notes Using ClickUp + GPT-4o + Notion + Slack\nThis workflow transforms raw ClickUp task updates into complete release documentation.\nIt validates incoming events, fetches task details, extracts clean metadata, generates\nprofessional release notes using GPT-4o, creates a Notion page, posts announcements\nto Slack, sends formatted release emails, and logs everything into Google Sheets.\n\nThe system ensures:\n• Clean task extraction (title, assignee, priority, description, links)  \n• AI-generated release notes with structured sections  \n• AI metadata classification (risk level, module, impact, change type)  \n• Centralized Notion documentation creation  \n• Automated Slack announcements for the team  \n• Email notifications for leads/managers  \n• Error handling + invalid event logging  \n\nThis replaces hours of manual writing and communication with a consistent, \nhigh-quality automated release workflow.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "56e3d7d6-04ed-469b-b405-06192bed9917",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1904,
        -592
      ],
      "parameters": {
        "color": 7,
        "width": 1152,
        "height": 912,
        "content": "## 📝 ClickUp Event Intake & Validation\nCaptures incoming task update events and validates them before processing.\n\n• Webhook  \n  Receives raw ClickUp event payload via POST.\n\n• Code in JavaScript  \n  Parses the raw body and extracts `task_id` safely.\n\n• Validate Incoming ClickUp Task Event  \n  Ensures `task_id` exists before moving forward.\n\n• Log Invalid ClickUp Events to Google Sheet  \n  Records malformed or incomplete events for debugging and audit tracking.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "f9a9912f-ac13-4e47-bc1f-6e2491b3ae33",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -704,
        -608
      ],
      "parameters": {
        "color": 7,
        "width": 1168,
        "height": 1040,
        "content": "## 🔍 Task Data Extraction & Metadata Enrichment\nFetches full task information and enhances it with AI-generated metadata.\n\n• Fetch Full Task Details from ClickUp  \n  Retrieves detailed task data (status, description, custom fields, assignee).\n\n• Extract Clean Task Fields from ClickUp Data  \n  Normalizes task values (title, assignee email, priority, link, URL).\n\n• Generate Release Metadata via AI  \n  GPT-4o infers risk_level, module, change_type, impact_score, testing needs.\n\n• Parse AI Metadata JSON Output  \n  Converts AI output (stringified JSON) into usable structured JSON.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "3dee45a4-ce0a-4015-abf2-420e24a441a8",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        512,
        -496
      ],
      "parameters": {
        "color": 7,
        "width": 528,
        "height": 464,
        "content": "## 🧩 Merge Task Details with Metadata\nCombines clean task fields with AI-generated metadata into one payload.\n\n• Merge Task Details with Metadata  \n  Joins task information and metadata into a single combined dataset.\n\n• Combine Task Info + Metadata into Final Payload  \n  Produces the finalized release-ready object used in downstream automation.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "08460f7a-9547-4745-99ca-7c816e78e007",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1088,
        -528
      ],
      "parameters": {
        "color": 7,
        "width": 672,
        "height": 688,
        "content": "## ✍️ AI-Generated Structured Release Notes\nCreates high-quality release notes using GPT-4o with strict formatting rules.\n\n• Provide GPT-4o Model for Release Notes Generation  \n  Supplies AI engine to the release-notes agent.\n\n• Generate Structured Release Notes via AI  \n  Builds release notes with sections: Summary, Improvements, Bug Fixes, Impact, Known Issues.\n\n• Extract Release Notes Title & Final Output  \n  Extracts title + prepares clean release notes for Notion, Slack, and Email.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "cfade227-75ad-42f0-88e2-24fad80c9319",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1808,
        -976
      ],
      "parameters": {
        "color": 7,
        "width": 768,
        "height": 1072,
        "content": "## 📣 Automated Release Communication & Documentation\nCreates documents, notifies teams, and logs release details.\n\n• Create Release Notes Page in Notion  \n  Stores full release notes in the Release Notes database.\n\n• Post Release Announcement to Slack  \n  Sends formatted release summary to the selected Slack user/channel.\n\n• Send Release Summary Email  \n  Sends a beautifully formatted HTML release summary to email recipients.\n\n• Append Release Log Entry to Google Sheet  \n  Logs task ID, priority, module, risk level, Notion URL, Slack message URL, and release date.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "a9f2b8f1-406b-49c7-9992-9cc9f5c061dd",
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -1808,
        -240
      ],
      "webhookId": "4703a2b4-7af0-4949-a18c-32b5a2f05269",
      "parameters": {
        "path": "4703a2b4-7af0-4949-a18c-32b5a2f05269",
        "options": {},
        "httpMethod": "POST"
      },
      "typeVersion": 2.1
    },
    {
      "id": "bb569018-5aab-426b-9b26-86d85ffdbe55",
      "name": "Code in JavaScript",
      "type": "n8n-nodes-base.code",
      "position": [
        -1600,
        -240
      ],
      "parameters": {
        "jsCode": "// The webhook sends the body as a string like:\n// \"{\\\"task_id\\\":\\\"86b78ggjw\\\"}\"\n\n// Step 1: Read the raw body\nconst rawBody = $json.body;\n\n// Step 2: Parse it into actual JSON\nlet parsed;\ntry {\n  parsed = JSON.parse(rawBody);\n} catch (err) {\n  parsed = { error: \"Invalid JSON\", raw: rawBody };\n}\n\n// Step 3: Return only the task_id in clean form\nreturn [\n  {\n    json: {\n      task_id: parsed.task_id || null\n    }\n  }\n];\n"
      },
      "typeVersion": 2
    }
  ],
  "active": false,
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "297851c7-eafa-410c-a9f7-d4af35694422",
  "connections": {
    "Webhook": {
      "main": [
        [
          {
            "node": "Code in JavaScript",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code in JavaScript": {
      "main": [
        [
          {
            "node": "Validate Incoming ClickUp Task Event",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse AI Metadata JSON Output": {
      "main": [
        [
          {
            "node": "Merge Task Details with Metadata",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Generate Release Metadata via AI": {
      "main": [
        [
          {
            "node": "Parse AI Metadata JSON Output",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge Task Details with Metadata": {
      "main": [
        [
          {
            "node": "Combine Task Info + Metadata into Final Payload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Post Release Announcement to Slack": {
      "main": [
        [
          {
            "node": "Append Release Log Entry to Google Sheet",
            "type": "main",
            "index": 0
          },
          {
            "node": "Send Release Summary Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Release Notes Page in Notion": {
      "main": [
        [
          {
            "node": "Post Release Announcement to Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Full Task Details from ClickUp": {
      "main": [
        [
          {
            "node": "Extract Clean Task Fields from ClickUp Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate Incoming ClickUp Task Event": {
      "main": [
        [
          {
            "node": "Fetch Full Task Details from ClickUp",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Log Invalid ClickUp Events to Google Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Structured Release Notes via AI": {
      "main": [
        [
          {
            "node": "Extract Release Notes Title & Final Output",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Release Notes Title & Final Output": {
      "main": [
        [
          {
            "node": "Create Release Notes Page in Notion",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Clean Task Fields from ClickUp Data": {
      "main": [
        [
          {
            "node": "Generate Release Metadata via AI",
            "type": "main",
            "index": 0
          },
          {
            "node": "Merge Task Details with Metadata",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Provide GPT-4o Model for Metadata Extraction": {
      "ai_languageModel": [
        [
          {
            "node": "Generate Release Metadata via AI",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Combine Task Info + Metadata into Final Payload": {
      "main": [
        [
          {
            "node": "Generate Structured Release Notes via AI",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Provide GPT-4o Model for Release Notes Generation": {
      "ai_languageModel": [
        [
          {
            "node": "Generate Structured Release Notes via AI",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    }
  }
}