{
  "id": "R3ZzYANzMk10U0m8",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Product UAT Critical Bug Escalation (AI \u2192 Jira + Slack)",
  "tags": [
    {
      "id": "bX1tZbypCr5HBJMz",
      "name": "product management",
      "createdAt": "2025-11-20T18:06:00.432Z",
      "updatedAt": "2025-11-20T18:06:00.432Z"
    },
    {
      "id": "rYuINsb3Y1XjrgNv",
      "name": "Productivity",
      "createdAt": "2025-08-02T17:36:49.812Z",
      "updatedAt": "2025-08-02T17:36:49.812Z"
    }
  ],
  "nodes": [
    {
      "id": "a720620e-25aa-423c-9f02-f957995b8165",
      "name": "trigger",
      "type": "n8n-nodes-base.webhook",
      "position": [
        496,
        -192
      ],
      "parameters": {
        "path": "3a6c966e-0409-4a8d-9ad9-bbf834689964",
        "options": {},
        "httpMethod": "POST"
      },
      "typeVersion": 2.1
    },
    {
      "id": "799e4a87-8d32-47be-8e27-7f79b6e59735",
      "name": "normalize",
      "type": "n8n-nodes-base.code",
      "position": [
        880,
        0
      ],
      "parameters": {
        "jsCode": "const input = $json || {};\n\nconst source = input.source || input.uat?.source || \"webhook\";\nconst testerName = input.tester_name || input.tester?.name || input.uat?.tester_name || \"\";\nconst testerEmail = input.tester_email || input.tester?.email || input.uat?.tester_email || \"\";\nconst messageRaw = input.message || input.text || input.feedback || input.uat?.message_raw || \"\";\nconst buildVersion = input.build_version || input.uat?.build_version || \"unknown\";\nconst pageUrl = input.page_url || input.uat?.page_url || \"\";\nconst screenshotUrl = input.screenshot_url || input.uat?.screenshot_url || \"\";\n\nreturn {\n  uat: {\n    source,\n    tester_name: testerName,\n    tester_email: testerEmail,\n    message_raw: messageRaw,\n    build_version: buildVersion,\n    page_url: pageUrl,\n    screenshot_url: screenshotUrl,\n    received_at: new Date().toISOString(),\n  },\n};\n"
      },
      "typeVersion": 2
    },
    {
      "id": "eca4998b-7324-4430-8268-e02de600d82a",
      "name": "parsing and validation",
      "type": "n8n-nodes-base.code",
      "position": [
        1600,
        0
      ],
      "parameters": {
        "jsCode": "// Try multiple possible fields depending on node output\nconst raw =\n  $json.output ||\n  $json.text ||\n  $json.message ||\n  ($json.response?.text) ||\n  ($json.data?.[0]?.content) ||\n  ($json.response?.[0]?.message?.content) ||\n\n  \"\";\n\nlet triage;\nlet parseOk = true;\n\ntry {\n  triage = JSON.parse(raw);\n} catch (e) {\n  parseOk = false;\n  triage = {\n    sentiment: \"Negative\",\n    type: \"Noise\",\n    severity: \"Minor\",\n    summary: \"AI response could not be parsed as JSON.\",\n    components: [\"other\"],\n    repro_steps: [],\n    suggested_title: \"UAT feedback (manual triage)\",\n    confidence: 0,\n  };\n}\n\n// Normalize + validate\nconst allowedType = [\"CriticalBug\", \"UXImprovement\", \"FeatureRequest\", \"Noise\"];\nif (!allowedType.includes(triage.type)) triage.type = \"Noise\";\n\nconst allowedSeverity = [\"Blocker\", \"Critical\", \"Major\", \"Minor\"];\nif (!allowedSeverity.includes(triage.severity)) triage.severity = \"Minor\";\n\nconst allowedSentiment = [\"Positive\", \"Negative\"];\nif (!allowedSentiment.includes(triage.sentiment)) triage.sentiment = \"Negative\";\n\ntriage.confidence = Math.max(0, Math.min(1, Number(triage.confidence ?? 0)));\n\nreturn {\n  ...$json,\n  triage: {\n    ...triage,\n    parse_ok: parseOk,\n  },\n};\n"
      },
      "typeVersion": 2
    },
    {
      "id": "a89c57b4-7479-4a27-a71d-07f053ff04c2",
      "name": "critical bug",
      "type": "n8n-nodes-base.jira",
      "position": [
        1824,
        0
      ],
      "parameters": {
        "project": {
          "__rl": true,
          "mode": "list",
          "value": "10002",
          "cachedResultName": "test2"
        },
        "summary": "= {{ $json.triage.suggested_title || $json.triage.summary }}",
        "issueType": {
          "__rl": true,
          "mode": "list",
          "value": "10013",
          "cachedResultName": "Bug"
        },
        "additionalFields": {
          "priority": {
            "__rl": true,
            "mode": "list",
            "value": "2",
            "cachedResultName": "High"
          },
          "description": "=Build: {{ $json.uat.build_version }}\nPage: {{ $json.uat.page_url }}\nScreenshot: {{ $json.uat.screenshot_url }}\n\nRepro steps:\n{{ ($json.triage.repro_steps || []).join(\"\\n\") }}\n\nReporter:\n{{ $json.uat.tester_name }} - {{ $json.uat.tester_email }}\nSource: {{ $json.uat.source }}"
        }
      },
      "credentials": {
        "jiraSoftwareCloudApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "e38ee892-a1c0-4570-b463-877ce34291ed",
      "name": "engeneering alert",
      "type": "n8n-nodes-base.slack",
      "position": [
        2032,
        0
      ],
      "parameters": {
        "text": "=\ud83d\udea8 UAT Critical Bug ({{ $json.triage.severity }}) \u2022 {{ $json.triage.summary }} \u2022 Build: {{ $json.uat.build_version }} \u2022 Component: {{ ($json.triage.components || []).join(\", \") }} \u2022 Jira: {{ $json.key || $json.id }}",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "C09V1228324",
          "cachedResultName": "tous-n8n"
        },
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "credentials": {
        "slackOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "c90dd414-4659-4421-8da0-a5f01892972a",
      "name": "tester email",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2800,
        80
      ],
      "parameters": {
        "sendTo": "={{ $json.uat.tester_email }}",
        "message": "={{ $json.reply.body }}",
        "options": {},
        "subject": "={{ $json.reply.subject }}"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "42e9bcbf-a50b-4227-95c9-c063524a0b06",
      "name": "slack tester",
      "type": "n8n-nodes-base.slack",
      "position": [
        2800,
        -128
      ],
      "parameters": {
        "text": "={{ $json.reply.body }}",
        "user": {
          "__rl": true,
          "mode": "list",
          "value": "U09UKKK9R25",
          "cachedResultName": "analyticsn8n"
        },
        "select": "user",
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "credentials": {
        "slackOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "f889f02d-3cc4-43ef-814f-3c566df54b19",
      "name": "clean text",
      "type": "n8n-nodes-base.code",
      "position": [
        1040,
        0
      ],
      "parameters": {
        "jsCode": "const msg = $json.uat?.message_raw || \"\";\n\nconst cleaned = msg\n  .replace(/<[^>]*>/g, \" \")\n  .replace(/\\s+/g, \" \")\n  .trim()\n  .slice(0, 3000);\n\nreturn {\n  ...$json,\n  uat: {\n    ...$json.uat,\n    message_clean: cleaned,\n  },\n};\n"
      },
      "typeVersion": 2
    },
    {
      "id": "9960d6de-2665-47e0-a958-966e969cc1c7",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -48,
        -752
      ],
      "parameters": {
        "width": 400,
        "height": 1328,
        "content": "## How it works\n\nThis workflow automates Product UAT critical bug escalation using AI.\n\nWhen a tester submits feedback via a webhook, the workflow normalizes and cleans the input before sending it to an AI model. The AI classifies the feedback, evaluates severity, and generates a structured summary with a confidence score.\n\nValidated critical bugs automatically create a Jira issue, trigger an engineering Slack alert, and notify the tester via Slack or email.\nThe workflow then responds to the original webhook with a structured status payload, ensuring full traceability and fast feedback loops."
      },
      "typeVersion": 1
    },
    {
      "id": "a23dfd66-5b76-43de-8e15-96a1f6dda5df",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        384,
        -752
      ],
      "parameters": {
        "color": 7,
        "width": 768,
        "height": 1328,
        "content": "## Ingestion & Normalization\n\nCollects UAT feedback from a webhook and normalizes all inputs\n(tester, source, build, page, message) into a clean, AI-ready data structure."
      },
      "typeVersion": 1
    },
    {
      "id": "3be2ae4d-b1a0-4fa6-8969-e7397427ad76",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1184,
        -752
      ],
      "parameters": {
        "color": 7,
        "width": 576,
        "height": 1328,
        "content": "## AI Triage & Quality Control\n\nAn AI model analyzes the feedback and returns a structured triage\n(type, severity, summary, confidence), which is parsed and validated before execution."
      },
      "typeVersion": 1
    },
    {
      "id": "4d1479c8-74ed-4707-a6a1-d4d8d7f0277e",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1792,
        -752
      ],
      "parameters": {
        "color": 7,
        "width": 624,
        "height": 1328,
        "content": "## Critical Bug Escalation\n\nValidated critical bugs automatically create a Jira issue\nand trigger an engineering Slack alert with full context."
      },
      "typeVersion": 1
    },
    {
      "id": "c3c5b21f-0f6b-4159-a741-3ac30b36edda",
      "name": "Webhook response",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        2976,
        -32
      ],
      "parameters": {
        "options": {
          "responseKey": "={   \"status\": \"received\",   \"type\": \"{{ $json.triage.type }}\",   \"severity\": \"{{ $json.triage.severity }}\",   \"confidence\": \"{{ $json.triage.confidence }}\" }",
          "responseCode": 200
        },
        "respondWith": "allIncomingItems"
      },
      "typeVersion": 1.4
    },
    {
      "id": "0bdf87b2-2e98-4a19-a8ed-0af895be33ca",
      "name": "how to contact",
      "type": "n8n-nodes-base.if",
      "position": [
        2496,
        0
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "8433c8f3-bdaf-4c64-af3c-7c091e51b8cc",
              "operator": {
                "name": "filter.operator.equals",
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.uat.source }}",
              "rightValue": "slack"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "99285181-4c7d-4d20-bece-0f066f5b40e5",
      "name": "compose reply branch 1",
      "type": "n8n-nodes-base.set",
      "position": [
        2256,
        0
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "9945be1d-27e1-4029-98f6-f19b04ae96a0",
              "name": "reply.subject",
              "type": "string",
              "value": "=UAT feedback received \u2014 Ticket {{ $json.key || $json.id }}"
            },
            {
              "id": "11a2ea6f-a0ab-43c7-9192-b43521667209",
              "name": "reply.body",
              "type": "string",
              "value": "=Thanks for your feedback!\n\nWe logged it as a Critical Bug ({{ $json.triage.severity }}).\nTicket: {{ $json.key || $json.id }}\n\nSummary: {{ $json.triage.summary }}\nBuild: {{ $json.uat.build_version }}\n\nWe\u2019ll keep you posted.\n"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "f86ce651-83a4-4983-bd0d-10a5c15d9efd",
      "name": "AI agent",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        1296,
        0
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-5.2",
          "cachedResultName": "GPT-5.2"
        },
        "options": {},
        "responses": {
          "values": [
            {
              "content": "=Analyze this UAT feedback and return ONLY JSON.\n\nContext:\n- build_version: {{ $json.uat.build_version }}\n- page_url: {{ $json.uat.page_url }}\n- screenshot_url: {{ $json.uat.screenshot_url }}\n\nFeedback:\n{{ $json.uat.message_clean }}\n\nJSON schema (strict):\n{\n  \"sentiment\": \"Positive|Negative\",\n  \"type\": \"CriticalBug|UXImprovement|FeatureRequest|Noise\",\n  \"severity\": \"Blocker|Critical|Major|Minor\",\n  \"summary\": \"string (max 160 chars)\",\n  \"components\": [\"string\"],\n  \"repro_steps\": [\"string\"],\n  \"suggested_title\": \"string (max 80 chars)\",\n  \"confidence\": 0.0\n}\n\nRules:\n- If the user reports something broken, crash, data loss, payment failure, login failure => type=CriticalBug and severity at least Critical.\n- If unclear or not actionable => type=Noise, confidence <= 0.5\n- repro_steps should be empty array if not inferable.\n- components: choose from [login, onboarding, checkout, search, profile, settings, performance, ui, api, other].\n"
            }
          ]
        },
        "builtInTools": {}
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "659fd4a4-c0c4-4f7e-95d5-0cb305a94d20",
      "name": "data merge",
      "type": "n8n-nodes-base.merge",
      "position": [
        704,
        0
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "combineBy": "combineByPosition"
      },
      "typeVersion": 3.2
    },
    {
      "id": "91b87775-ed61-4ca9-a07b-df7f93ac017b",
      "name": "data mapping",
      "type": "n8n-nodes-base.set",
      "position": [
        496,
        192
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "0346a94c-9b3c-4317-8085-ea2505521edf",
              "name": "cfg.jiraProjectKey",
              "type": "string",
              "value": "UAT"
            },
            {
              "id": "caf9cd84-2d85-4faa-bd7b-c7e240bf6c7f",
              "name": "cfg.jiraIssueTypeBug",
              "type": "string",
              "value": "Bug"
            },
            {
              "id": "da76905d-3985-4eae-88da-b705580e38c6",
              "name": "cfg.slackChannelEng",
              "type": "string",
              "value": "#eng-uat"
            },
            {
              "id": "c96cb9ed-66db-463d-a7a8-145d1cc3c9d9",
              "name": "cfg.slackChannelPm",
              "type": "string",
              "value": "#product-uat"
            },
            {
              "id": "1c3b1959-e21a-487e-b121-3662b8914819",
              "name": "cfg.sheetIdDigest",
              "type": "string",
              "value": "YourID"
            },
            {
              "id": "059b436b-a29b-4991-a72e-c8bd4b844722",
              "name": "cfg.manualReviewEmail",
              "type": "string",
              "value": "user@example.com"
            },
            {
              "id": "25dbf28f-db8a-4a49-9cbf-587276851c61",
              "name": "cfg.confidenceThreshold",
              "type": "number",
              "value": 0.6
            },
            {
              "id": "745af86b-f13d-4ead-a322-ab4e2473e3d6",
              "name": "cfg.dedupeEnabled",
              "type": "boolean",
              "value": false
            },
            {
              "id": "dd5c4b90-2919-4d15-8768-913c9b5ae62e",
              "name": "cfg.llmProvider",
              "type": "string",
              "value": "openai"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "b67fc4f1-6247-4bf3-a30f-eb90da2ab953",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2448,
        -752
      ],
      "parameters": {
        "color": 7,
        "width": 784,
        "height": 1328,
        "content": "## Closed Loop\n\nNotifies the tester via Slack or email\nand responds to the original webhook\nwith a structured status payload."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "4912105a-25bf-4f2d-90ce-dcf659e0303a",
  "connections": {
    "trigger": {
      "main": [
        [
          {
            "node": "data merge",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI agent": {
      "main": [
        [
          {
            "node": "parsing and validation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "normalize": {
      "main": [
        [
          {
            "node": "clean text",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "clean text": {
      "main": [
        [
          {
            "node": "AI agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "data merge": {
      "main": [
        [
          {
            "node": "normalize",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "critical bug": {
      "main": [
        [
          {
            "node": "engeneering alert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "data mapping": {
      "main": [
        [
          {
            "node": "data merge",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "slack tester": {
      "main": [
        [
          {
            "node": "Webhook response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "tester email": {
      "main": [
        [
          {
            "node": "Webhook response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "how to contact": {
      "main": [
        [
          {
            "node": "slack tester",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "tester email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "engeneering alert": {
      "main": [
        [
          {
            "node": "compose reply branch 1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "compose reply branch 1": {
      "main": [
        [
          {
            "node": "how to contact",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "parsing and validation": {
      "main": [
        [
          {
            "node": "critical bug",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}