{
  "name": "AI Support Deflection & Triage (RAG)",
  "nodes": [
    {
      "parameters": {
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        },
        "simple": true,
        "filters": {},
        "options": {}
      },
      "id": "email-trigger-support-inbox",
      "name": "Email Trigger: Support Inbox",
      "type": "n8n-nodes-base.gmailTrigger",
      "typeVersion": 1,
      "position": [
        -720,
        320
      ],
      "credentials": {
        "gmailOAuth2": {
          "id": "REPLACE_GMAIL",
          "name": "Gmail (Support)"
        }
      }
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "s1",
              "name": "from",
              "value": "={{ $json.from }}",
              "type": "string"
            },
            {
              "id": "s2",
              "name": "subject",
              "value": "={{ $json.subject }}",
              "type": "string"
            },
            {
              "id": "s3",
              "name": "body",
              "value": "={{ ($json.text || $json.snippet || '').slice(0, 4000) }}",
              "type": "string"
            },
            {
              "id": "s4",
              "name": "threadId",
              "value": "={{ $json.threadId }}",
              "type": "string"
            },
            {
              "id": "s5",
              "name": "messageId",
              "value": "={{ $json.id }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "normalize-ticket",
      "name": "Normalize Ticket",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -500,
        320
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.anthropic.com/v1/messages",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "anthropic-version",
              "value": "2023-06-01"
            },
            {
              "name": "content-type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ model:\"claude-sonnet-4-6\", max_tokens:600, system:\"Du bist Support-Triage. Antworte NUR mit JSON: {\\\"category\\\": string, \\\"urgency\\\": \\\"low\\\"|\\\"med\\\"|\\\"high\\\", \\\"sentiment\\\": \\\"neg\\\"|\\\"neu\\\"|\\\"pos\\\", \\\"language\\\": string, \\\"is_spam\\\": boolean, \\\"summary\\\": string}.\", messages:[{role:\"user\", content: \"Betreff: \" + $json.subject + \"\\n\\n\" + $json.body }] }) }}",
        "options": {
          "timeout": 30000
        }
      },
      "id": "claude-classify",
      "name": "Claude: Classify",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        -280,
        320
      ],
      "credentials": {
        "httpHeaderAuth": {
          "id": "REPLACE_ANTHRO",
          "name": "Anthropic API key (x-api-key)"
        }
      }
    },
    {
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "let d; try { d = JSON.parse($json.content[0].text); } catch(e){ const m=($json.content?.[0]?.text||'').match(/\\{[\\s\\S]*\\}/); d=m?JSON.parse(m[0]):{category:'unknown',urgency:'med',sentiment:'neu',language:'de',is_spam:false,summary:''}; }\nreturn { ...$('Normalize Ticket').item.json, ...d };"
      },
      "id": "parse-classify",
      "name": "Parse Classify",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -60,
        320
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "c1",
              "leftValue": "={{ $json.is_spam }}",
              "rightValue": "",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ]
        },
        "options": {}
      },
      "id": "if-spam?",
      "name": "IF: Spam?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        160,
        320
      ]
    },
    {
      "parameters": {},
      "id": "no-op-archive-spam",
      "name": "No-Op: Archive Spam",
      "type": "n8n-nodes-base.noOp",
      "typeVersion": 1,
      "position": [
        380,
        520
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.openai.com/v1/embeddings",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "content-type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ model:\"text-embedding-3-small\", input: $json.subject + \" \" + $json.body }) }}",
        "options": {}
      },
      "id": "embed-query-openai",
      "name": "Embed Query (OpenAI)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        380,
        220
      ],
      "credentials": {
        "httpHeaderAuth": {
          "id": "REPLACE_OPENAI",
          "name": "OpenAI API key (Bearer)"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://YOUR-PROJECT.supabase.co/rest/v1/rpc/match_documents",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "content-type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ query_embedding: $json.data[0].embedding, match_count: 5 }) }}",
        "options": {}
      },
      "id": "vector-search-kb",
      "name": "Vector Search (KB)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        600,
        220
      ],
      "onError": "continueRegularOutput",
      "credentials": {
        "httpHeaderAuth": {
          "id": "REPLACE_SUPABA",
          "name": "Supabase service key"
        }
      }
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "b1",
              "name": "context",
              "value": "={{ (Array.isArray($json) ? $json : ($json.matches || [])).map(m => '- ' + (m.content || '')).join('\\n') }}",
              "type": "string"
            },
            {
              "id": "b2",
              "name": "question",
              "value": "={{ $('Parse Classify').item.json.subject + '\\n' + $('Parse Classify').item.json.body }}",
              "type": "string"
            },
            {
              "id": "b3",
              "name": "from",
              "value": "={{ $('Parse Classify').item.json.from }}",
              "type": "string"
            },
            {
              "id": "b4",
              "name": "threadId",
              "value": "={{ $('Parse Classify').item.json.threadId }}",
              "type": "string"
            },
            {
              "id": "b5",
              "name": "language",
              "value": "={{ $('Parse Classify').item.json.language }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "build-answer-prompt",
      "name": "Build Answer Prompt",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        820,
        220
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.anthropic.com/v1/messages",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "anthropic-version",
              "value": "2023-06-01"
            },
            {
              "name": "content-type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ model:\"claude-sonnet-4-6\", max_tokens:900, system:\"Du bist Kundensupport. Beantworte die Frage NUR mit dem bereitgestellten Kontext. Antworte NUR mit JSON: {\\\"answer\\\": string, \\\"confidence\\\": number (0-1), \\\"citations\\\": string[], \\\"can_auto_send\\\": boolean}. Wenn der Kontext nicht reicht: confidence niedrig und can_auto_send=false. Antworte in der Sprache des Kunden.\", messages:[{role:\"user\", content: \"Sprache: \" + $json.language + \"\\n\\nKontext:\\n\" + $json.context + \"\\n\\nKundenfrage:\\n\" + $json.question }] }) }}",
        "options": {
          "timeout": 40000
        }
      },
      "id": "claude-draft-answer",
      "name": "Claude: Draft Answer",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1040,
        220
      ],
      "credentials": {
        "httpHeaderAuth": {
          "id": "REPLACE_ANTHRO",
          "name": "Anthropic API key (x-api-key)"
        }
      }
    },
    {
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "let d; try { d = JSON.parse($json.content[0].text); } catch(e){ const m=($json.content?.[0]?.text||'').match(/\\{[\\s\\S]*\\}/); d=m?JSON.parse(m[0]):{answer:'',confidence:0,citations:[],can_auto_send:false}; }\nreturn { ...$('Build Answer Prompt').item.json, answer:d.answer||'', confidence:Number(d.confidence)||0, citations:d.citations||[], can_auto_send: !!d.can_auto_send };"
      },
      "id": "parse-answer",
      "name": "Parse Answer",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1260,
        220
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "a1",
              "leftValue": "={{ $json.can_auto_send }}",
              "rightValue": "",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            },
            {
              "id": "a2",
              "leftValue": "={{ $json.confidence }}",
              "rightValue": 0.8,
              "operator": {
                "type": "number",
                "operation": "gte"
              }
            }
          ]
        },
        "options": {}
      },
      "id": "if-auto-send?",
      "name": "IF: Auto-send?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        1480,
        220
      ]
    },
    {
      "parameters": {
        "resource": "message",
        "operation": "reply",
        "messageId": "={{ $('Normalize Ticket').item.json.messageId }}",
        "message": "={{ $json.answer }}",
        "options": {}
      },
      "id": "gmail-auto-reply",
      "name": "Gmail: Auto-Reply",
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2.1,
      "position": [
        1700,
        100
      ],
      "credentials": {
        "gmailOAuth2": {
          "id": "REPLACE_GMAIL",
          "name": "Gmail (Support)"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://your-helpdesk.example.com/api/tickets/update",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ thread: $json.threadId, status:\"solved\", resolved_by:\"ai\", confidence:$json.confidence }) }}",
        "options": {}
      },
      "id": "helpdesk-mark-solved",
      "name": "Helpdesk: Mark Solved",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1920,
        100
      ],
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "resource": "message",
        "operation": "post",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "value": "support-review",
          "mode": "name"
        },
        "text": "=:eyes: *Review noetig* ({{ Math.round($json.confidence*100) }}% sicher)\\nVon: {{ $json.from }}\\nFrage: {{ $json.question }}\\n\\n*Entwurf:*\\n{{ $json.answer }}",
        "otherOptions": {}
      },
      "id": "slack-human-review",
      "name": "Slack: Human Review",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.2,
      "position": [
        1700,
        360
      ],
      "credentials": {
        "slackOAuth2Api": {
          "id": "REPLACE_SLACK",
          "name": "Slack account"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://your-helpdesk.example.com/api/tickets/update",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ thread: $json.threadId, status:\"open\", assigned_team:\"support\", ai_draft:$json.answer }) }}",
        "options": {}
      },
      "id": "helpdesk-assign-human",
      "name": "Helpdesk: Assign Human",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1920,
        360
      ],
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "operation": "append",
        "documentId": {
          "__rl": true,
          "value": "REPLACE_SHEET_ID",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "Tickets",
          "mode": "name"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "ts": "={{ $now.toISO() }}",
            "from": "={{ $json.from }}",
            "category": "={{ $('Parse Classify').item.json.category }}",
            "urgency": "={{ $('Parse Classify').item.json.urgency }}",
            "confidence": "={{ $json.confidence }}",
            "outcome": "={{ $json.can_auto_send && $json.confidence>=0.8 ? 'auto-resolved' : 'human' }}"
          },
          "matchingColumns": [],
          "schema": []
        },
        "options": {}
      },
      "id": "sheets-deflection-log",
      "name": "Sheets: Deflection Log",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.4,
      "position": [
        2160,
        220
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "REPLACE_SHEETS",
          "name": "Google Sheets account"
        }
      }
    },
    {
      "parameters": {},
      "id": "no-op-done-support",
      "name": "No-Op: Done (Support)",
      "type": "n8n-nodes-base.noOp",
      "typeVersion": 1,
      "position": [
        2380,
        220
      ]
    },
    {
      "parameters": {},
      "id": "error-trigger-support",
      "name": "Error Trigger (Support)",
      "type": "n8n-nodes-base.errorTrigger",
      "typeVersion": 1,
      "position": [
        -720,
        640
      ]
    },
    {
      "parameters": {
        "resource": "message",
        "operation": "post",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "value": "automation-alerts",
          "mode": "name"
        },
        "text": "=:rotating_light: Support-Workflow Fehler: {{ $json.execution.error.message }}",
        "otherOptions": {}
      },
      "id": "slack-error-support",
      "name": "Slack: Error (Support)",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.2,
      "position": [
        -500,
        640
      ],
      "credentials": {
        "slackOAuth2Api": {
          "id": "REPLACE_SLACK",
          "name": "Slack account"
        }
      }
    },
    {
      "parameters": {
        "content": "## 1) Intake + Triage\\nGmail-Trigger holt Support-Mails. Claude klassifiziert (Kategorie, Dringlichkeit, Sentiment, Sprache, Spam). Spam wird archiviert.",
        "height": 150,
        "width": 520,
        "color": 5
      },
      "id": "note2-1",
      "name": "note2-1",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -740,
        120
      ]
    },
    {
      "parameters": {
        "content": "## 2) RAG-Antwort\\nFrage -> Embedding (OpenAI) -> Vektor-Suche in eurer Wissensbasis (Supabase/pgvector) -> Top-5 Treffer als Kontext -> Claude entwirft die Antwort NUR aus dem Kontext, inkl. **confidence** + Quellen.",
        "height": 170,
        "width": 900,
        "color": 6
      },
      "id": "note2-2",
      "name": "note2-2",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        360,
        20
      ]
    },
    {
      "parameters": {
        "content": "## 3) Confidence-Gate (Human-in-the-loop)\\nSicher genug (>=0.8 & can_auto_send): **automatisch antworten** + Ticket schliessen.\\nSonst: Entwurf an Slack zur Freigabe + Ticket einem Menschen zuweisen.\\nAlles wird geloggt (Deflection-Quote).",
        "height": 160,
        "width": 900,
        "color": 3
      },
      "id": "note2-3",
      "name": "note2-3",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        1480,
        20
      ]
    }
  ],
  "connections": {
    "Email Trigger: Support Inbox": {
      "main": [
        [
          {
            "node": "Normalize Ticket",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Ticket": {
      "main": [
        [
          {
            "node": "Claude: Classify",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Claude: Classify": {
      "main": [
        [
          {
            "node": "Parse Classify",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Classify": {
      "main": [
        [
          {
            "node": "IF: Spam?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF: Spam?": {
      "main": [
        [
          {
            "node": "No-Op: Archive Spam",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Embed Query (OpenAI)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Embed Query (OpenAI)": {
      "main": [
        [
          {
            "node": "Vector Search (KB)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Vector Search (KB)": {
      "main": [
        [
          {
            "node": "Build Answer Prompt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Answer Prompt": {
      "main": [
        [
          {
            "node": "Claude: Draft Answer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Claude: Draft Answer": {
      "main": [
        [
          {
            "node": "Parse Answer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Answer": {
      "main": [
        [
          {
            "node": "IF: Auto-send?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF: Auto-send?": {
      "main": [
        [
          {
            "node": "Gmail: Auto-Reply",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Slack: Human Review",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Gmail: Auto-Reply": {
      "main": [
        [
          {
            "node": "Helpdesk: Mark Solved",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Helpdesk: Mark Solved": {
      "main": [
        [
          {
            "node": "Sheets: Deflection Log",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Slack: Human Review": {
      "main": [
        [
          {
            "node": "Helpdesk: Assign Human",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Helpdesk: Assign Human": {
      "main": [
        [
          {
            "node": "Sheets: Deflection Log",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Sheets: Deflection Log": {
      "main": [
        [
          {
            "node": "No-Op: Done (Support)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Error Trigger (Support)": {
      "main": [
        [
          {
            "node": "Slack: Error (Support)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "pinData": {},
  "meta": {},
  "tags": [
    {
      "name": "Support"
    },
    {
      "name": "AI"
    },
    {
      "name": "RAG"
    }
  ]
}