{
  "id": "rdlr1EaEcjC8i1YY",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "N-0046 Exception Queue Smart Prioritization Engine",
  "tags": [],
  "nodes": [
    {
      "id": "7a608f87-b09c-4224-8464-c17ca80492c7",
      "name": "Receive Exception Request",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -6224,
        5600
      ],
      "parameters": {
        "path": "exception-trigger",
        "options": {},
        "responseMode": "responseNode"
      },
      "typeVersion": 2
    },
    {
      "id": "22c1b9cb-ad0e-4f67-bdc0-0d9bd95e9768",
      "name": "Read Exceptions from Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -5840,
        5600
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1prWm2iUrj63OWRHCJSSkCUqMH9l7A0KY6RLjFAGudmc/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1prWm2iUrj63OWRHCJSSkCUqMH9l7A0KY6RLjFAGudmc",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1prWm2iUrj63OWRHCJSSkCUqMH9l7A0KY6RLjFAGudmc/edit?usp=drivesdk",
          "cachedResultName": "Priority_Ranking"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4
    },
    {
      "id": "4114eb2b-5733-4031-ba55-98d83249fde0",
      "name": "Format Data for AI",
      "type": "n8n-nodes-base.code",
      "position": [
        -5360,
        5600
      ],
      "parameters": {
        "jsCode": "// CODE 1 \u2014 Format rows into a clean text list for Gemini\nconst exceptions = $input.all().map(item => item.json);\n\nconst exceptionList = exceptions.map((ex, i) =>\n  `[${i + 1}] ID: ${ex.ExceptionID || 'N/A'} | Title: ${ex.Title || 'Untitled'} | Severity: ${ex.Severity || 'Unknown'} | System: ${ex.System || 'N/A'} | Reported: ${ex.ReportedAt || 'N/A'}`\n).join('\\n');\n\nreturn [{\n  json: {\n    exceptionList,\n    totalCount: exceptions.length\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "68fda6a3-1456-45e2-a9b0-1d533dbb0075",
      "name": "AI \u2014 Rank & Prioritize",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -5184,
        5600
      ],
      "parameters": {
        "url": "https://generativelanguage.googleapis.com/v1/models/gemini-2.5-flash:generateContent?",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"contents\": [{\n    \"parts\": [{\n      \"text\": {{ JSON.stringify(\"Analyze and rank these exceptions. Respond ONLY with a valid JSON object \u2014 no markdown, no backticks, no extra text.\\nRequired structure:\\n{\\n  \\\"prioritized_exceptions\\\": [\\n    {\\n      \\\"exception_id\\\": \\\"EXC-001\\\",\\n      \\\"title\\\": \\\"...\\\",\\n      \\\"severity\\\": \\\"...\\\",\\n      \\\"rank\\\": 1,\\n      \\\"priority_score\\\": 95,\\n      \\\"priority_label\\\": \\\"P0\\\",\\n      \\\"estimated_impact\\\": \\\"...\\\",\\n      \\\"reasoning\\\": \\\"...\\\",\\n      \\\"recommended_action\\\": \\\"...\\\"\\n    }\\n  ],\\n  \\\"summary\\\": \\\"...\\\",\\n  \\\"critical_count\\\": 1,\\n  \\\"high_count\\\": 1,\\n  \\\"medium_count\\\": 1,\\n  \\\"low_count\\\": 0\\n}\\n\\nExceptions:\\n\" + $json.exceptionList) }}\n    }]\n  }]\n}",
        "sendBody": true,
        "sendQuery": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "queryParameters": {
          "parameters": [
            {
              "name": "key",
              "value": "=<redacted-credential>"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "15f3b7cb-524e-4cf1-bf13-0c86b16128b4",
      "name": "Save Summary to Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -4784,
        5600
      ],
      "parameters": {
        "columns": {
          "value": {
            "summary": "={{ $json.summary }}",
            "low_count": "={{ $json.low_count }}",
            "high_count": "={{ $json.high_count }}",
            "totalCount": "={{ $json.totalCount }}",
            "analyzed_at": "={{ $json.analyzed_at }}",
            "medium_count": "={{ $json.medium_count }}",
            "critical_count": "={{ $json.critical_count }}"
          },
          "schema": [
            {
              "id": "summary",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "summary",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "critical_count",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "critical_count",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "high_count",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "high_count",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "medium_count",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "medium_count",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "low_count",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "low_count",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "totalCount",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "totalCount",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "analyzed_at",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "analyzed_at",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "summary"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 1284297464,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1prWm2iUrj63OWRHCJSSkCUqMH9l7A0KY6RLjFAGudmc/edit#gid=1284297464",
          "cachedResultName": "Sheet2"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1prWm2iUrj63OWRHCJSSkCUqMH9l7A0KY6RLjFAGudmc",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1prWm2iUrj63OWRHCJSSkCUqMH9l7A0KY6RLjFAGudmc/edit?usp=drivesdk",
          "cachedResultName": "Priority_Ranking"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4
    },
    {
      "id": "9ecf7b82-2699-4f8c-9f09-19974f0252dd",
      "name": "Check Critical Alerts",
      "type": "n8n-nodes-base.if",
      "position": [
        -4384,
        5600
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "cond-is-critical",
              "operator": {
                "type": "number",
                "operation": "gt"
              },
              "leftValue": "={{ $('AI Results').first().json.critical_count }}",
              "rightValue": 0
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "281fe072-d909-4adf-bccd-bc0c47ecd60d",
      "name": "Send Critical Email",
      "type": "n8n-nodes-base.gmail",
      "position": [
        -4144,
        5440
      ],
      "parameters": {
        "message": "={{ $('AI Results').first().json.emailBody }}",
        "options": {},
        "subject": "={{ $('AI Results').first().json.emailSubject }}"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "963c2b82-5f6d-4b44-8e96-5dbc6b551c88",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -6240,
        5040
      ],
      "parameters": {
        "width": 512,
        "height": 368,
        "content": "## Exception Queue Smart Prioritization Engine\n## How it works:\nThis workflow reads exception data from Google Sheets, sends it to AI (Gemini) for intelligent ranking, then generates Slack alerts, email notifications for critical issues, and saves summarized insights back to Sheets.\n\n## Setup steps:\n1. Connect Google Sheets, Slack, and Gmail credentials\n2. Update Sheet ID and Slack channel in Set node\n3. Add your Gemini API key\n4. Trigger via webhook to run workflow"
      },
      "typeVersion": 1
    },
    {
      "id": "9055cb9d-bfa8-4093-a598-83be17d61ce1",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -6256,
        5456
      ],
      "parameters": {
        "color": 7,
        "width": 724,
        "height": 416,
        "content": "## Data Collection & Validation\nReads exceptions from Sheet1 and checks if data exists before processing."
      },
      "typeVersion": 1
    },
    {
      "id": "5c555493-409a-427c-b366-d885f4857f3d",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -5392,
        5472
      ],
      "parameters": {
        "color": 7,
        "width": 528,
        "height": 336,
        "content": "## AI Processing\nFormats exception data and sends it to Gemini AI for ranking and prioritization."
      },
      "typeVersion": 1
    },
    {
      "id": "ba1f66a9-978d-419a-9907-a370d82741fa",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -4832,
        5344
      ],
      "parameters": {
        "color": 7,
        "width": 864,
        "height": 512,
        "content": "## Notifications & Storage\nSends Slack alerts, emails for critical issues, and saves results to Sheet2."
      },
      "typeVersion": 1
    },
    {
      "id": "0a53df81-24b7-418a-a582-e8def02050ac",
      "name": "Config Variables",
      "type": "n8n-nodes-base.set",
      "position": [
        -6016,
        5600
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "1e221fc0-5259-42f6-a671-182ad0e555aa",
              "name": "sheet1Name",
              "type": "string",
              "value": "Sheet1"
            },
            {
              "id": "4d8509b5-4632-48d9-9f3a-aad73e166134",
              "name": "sheet2Name",
              "type": "string",
              "value": "Sheet2"
            },
            {
              "id": "a2b4a57f-ebf1-44ae-ae7c-c80bb569525e",
              "name": "slackChannel",
              "type": "string",
              "value": "new-channel"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "b269f347-7823-405c-9332-2dff72ba3992",
      "name": "Exceptions Available?",
      "type": "n8n-nodes-base.if",
      "position": [
        -5648,
        5600
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "cond-has-rows",
              "operator": {
                "type": "number",
                "operation": "gt"
              },
              "leftValue": "={{ $input.all().length }}",
              "rightValue": 0
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "d8b66285-c478-4d50-a3ad-cc39d3d07628",
      "name": "No Exceptions Found",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        -5344,
        5856
      ],
      "parameters": {
        "options": {},
        "respondWith": "json",
        "responseBody": "={ \"success\": true, \"message\": \"No open exceptions found\" }"
      },
      "typeVersion": 1.1
    },
    {
      "id": "70adccea-53cb-4f04-917f-10ae3ed59c3b",
      "name": "AI Results",
      "type": "n8n-nodes-base.code",
      "position": [
        -4992,
        5600
      ],
      "parameters": {
        "jsCode": "// CODE 2 \u2014 Parse AI response + build Slack + email + sheet rows\n// OUTPUT: Always exactly ONE item.\n// Sheet2 node reads from sheetRows array embedded in that single item.\n\nconst response = $input.first().json;\nconst textContent = response.candidates?.[0]?.content?.parts?.[0]?.text || '';\nconst now = new Date();\nconst nowISO = now.toISOString();\nconst nowIN  = now.toLocaleString('en-IN', { timeZone: 'Asia/Kolkata' });\n\nconst totalCount = $('Format Data for AI').first().json.totalCount || 0;\n\n// Parse Gemini JSON\nlet parsed;\ntry {\n  const cleaned = textContent\n    .replace(/```json|```/g, '')\n    .replace(/^[^{]*/, '')\n    .replace(/[^}]*$/, '')\n    .trim();\n  parsed = JSON.parse(cleaned);\n} catch (e) {\n  parsed = {};\n}\n\nconst exceptions     = parsed.prioritized_exceptions || [];\nconst summary        = parsed.summary        || 'No summary provided';\nconst critical_count = parsed.critical_count || 0;\nconst high_count     = parsed.high_count     || 0;\nconst medium_count   = parsed.medium_count   || 0;\nconst low_count      = parsed.low_count      || 0;\n\nconst sorted = exceptions.sort((a, b) => (a.rank || 999) - (b.rank || 999));\n\n// Slack ranked list \u2014 full details per exception\nconst rankedList = sorted.slice(0, 10).map(ex =>\n  `*${ex.rank}. [${ex.priority_label}] ${ex.exception_id}* \u2014 ${ex.title}\\n` +\n  `   Severity: *${ex.severity}* | Score: ${ex.priority_score}\\n` +\n  `   Impact: ${ex.estimated_impact}\\n` +\n  `   Action: ${ex.recommended_action}`\n).join('\\n\\n') || 'No exceptions ranked.';\n\nconst slackBlocks = [\n  { type: 'header', text: { type: 'plain_text', text: 'Exception Queue \u2014 AI Priority Report', emoji: true } },\n  { type: 'section', text: { type: 'mrkdwn', text: `*Time:* ${nowIN}\\n*Total:* ${totalCount} | :red_circle: Critical: ${critical_count} | :large_orange_circle: High: ${high_count} | :large_yellow_circle: Medium: ${medium_count} | :white_circle: Low: ${low_count}` } },\n  { type: 'divider' },\n  { type: 'section', text: { type: 'mrkdwn', text: `*Ranked Exceptions (Top ${Math.min(sorted.length, 10)}):*\\n\\n${rankedList}` } },\n  { type: 'divider' },\n  { type: 'section', text: { type: 'mrkdwn', text: `*AI Summary:* ${summary}` } },\n  { type: 'actions', elements: [{ type: 'button', text: { type: 'plain_text', text: 'View Full Sheet', emoji: true }, url: 'https://docs.google.com/spreadsheets/d/1prWm2iUrj63OWRHCJSSkCUqMH9l7A0KY6RLjFAGudmc', style: 'primary' }] }\n];\n\n// Critical email\nconst criticalList = sorted.filter(ex =>\n  ex.priority_label?.toUpperCase() === 'P0' || ex.severity?.toLowerCase() === 'critical'\n);\nconst emailSubject = `[CRITICAL] ${criticalList.length} Exception(s) Need Immediate Action \u2014 ${nowIN}`;\nconst emailBody = `\n<h2>Critical Exceptions Report</h2>\n<p><strong>Time:</strong> ${nowIN}</p>\n<p><strong>Total analyzed:</strong> ${totalCount} &nbsp;|&nbsp; Critical: ${critical_count} &nbsp;|&nbsp; High: ${high_count} &nbsp;|&nbsp; Medium: ${medium_count} &nbsp;|&nbsp; Low: ${low_count}</p>\n<h3>Critical Items:</h3>\n<table border=\"1\" cellpadding=\"6\" cellspacing=\"0\" style=\"border-collapse:collapse;font-family:Arial,sans-serif;font-size:14px\">\n  <tr style=\"background:#c0392b;color:#fff\"><th>ID</th><th>Title</th><th>Severity</th><th>Priority</th><th>Score</th><th>Recommended Action</th></tr>\n  ${criticalList.map(ex => `<tr><td><strong>${ex.exception_id||'N/A'}</strong></td><td>${ex.title||'N/A'}</td><td>${ex.severity||'N/A'}</td><td>${ex.priority_label||'N/A'}</td><td>${ex.priority_score||'N/A'}</td><td>${ex.recommended_action||'N/A'}</td></tr>`).join('')}\n</table>\n<br/><p><strong>AI Summary:</strong> ${summary}</p>\n<p><a href=\"https://docs.google.com/spreadsheets/d/1prWm2iUrj63OWRHCJSSkCUqMH9l7A0KY6RLjFAGudmc\">View Full Report</a></p>`;\n\n// Sheet rows \u2014 stored as array inside the single output item\nconst sheetRows = (sorted.length > 0 ? sorted : [{\n  exception_id: 'N/A', title: 'No exceptions returned', severity: 'Unknown',\n  rank: 0, priority_score: 0, priority_label: 'N/A',\n  estimated_impact: 'N/A', reasoning: summary, recommended_action: 'Check AI response'\n}]).map(ex => ({\n  ExceptionID:       ex.exception_id       || 'N/A',\n  Title:             ex.title              || 'No title',\n  Severity:          ex.severity           || 'Unknown',\n  Rank:              ex.rank               || 0,\n  PriorityScore:     ex.priority_score     || 0,\n  PriorityLabel:     ex.priority_label     || 'N/A',\n  EstimatedImpact:   ex.estimated_impact   || 'N/A',\n  Reasoning:         ex.reasoning          || 'No reasoning',\n  RecommendedAction: ex.recommended_action || 'No action',\n  AnalyzedAt:        nowISO\n}));\n\n// Always return exactly ONE item \u2014 no more duplicate Slack/Gmail/Webhook runs\nreturn [{\n  json: {\n    summary,\n    critical_count,\n    high_count,\n    medium_count,\n    low_count,\n    totalCount,\n    analyzed_at:  nowISO,\n    slackText:    `Exception Report \u2014 ${nowIN}`,\n    slackBlocks:  JSON.stringify(slackBlocks),\n    emailSubject,\n    emailBody,\n    sheetRows:    JSON.stringify(sheetRows)\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "2b5ebad0-60eb-4a35-bdb3-0de16c8246b8",
      "name": "Slack Report",
      "type": "n8n-nodes-base.slack",
      "position": [
        -4592,
        5600
      ],
      "parameters": {
        "text": "={{ $('AI Results').item.json.slackText }}",
        "select": "channel",
        "blocksUi": "={{ $('AI Results').item.json.slackBlocks }}",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "C0AP86XGA78",
          "cachedResultName": "new-channel"
        },
        "messageType": "block",
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "credentials": {
        "slackOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "8e14fe90-1047-4ed4-bd88-18be32a52ce2",
      "name": "Success",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        -3952,
        5616
      ],
      "parameters": {
        "options": {},
        "respondWith": "json",
        "responseBody": "={\n  \"success\": true,\n  \"message\": \"Done\",\n  \"total_processed\": {{ $('Format Data for AI').first().json.totalCount }},\n  \"critical_count\": {{ $('AI Results').first().json.critical_count }},\n  \"analyzed_at\": \"{{ $('AI Results').first().json.analyzed_at }}\"\n}"
      },
      "typeVersion": 1.1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "7b1aef92-bf1e-4904-8ef3-e049eeefb0d5",
  "connections": {
    "AI Results": {
      "main": [
        [
          {
            "node": "Save Summary to Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Slack Report": {
      "main": [
        [
          {
            "node": "Check Critical Alerts",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Config Variables": {
      "main": [
        [
          {
            "node": "Read Exceptions from Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Data for AI": {
      "main": [
        [
          {
            "node": "AI \u2014 Rank & Prioritize",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Critical Email": {
      "main": [
        [
          {
            "node": "Success",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Critical Alerts": {
      "main": [
        [
          {
            "node": "Send Critical Email",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Success",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Exceptions Available?": {
      "main": [
        [
          {
            "node": "Format Data for AI",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "No Exceptions Found",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save Summary to Sheet": {
      "main": [
        [
          {
            "node": "Slack Report",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Slack \u2014 Notify Team3": {
      "main": [
        [
          {
            "node": "IF \u2014 Any Critical Exceptions?3",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI \u2014 Rank & Prioritize": {
      "main": [
        [
          {
            "node": "AI Results",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Receive Exception Request": {
      "main": [
        [
          {
            "node": "Config Variables",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Exceptions from Sheet": {
      "main": [
        [
          {
            "node": "Exceptions Available?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}