{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "97c3d1fa-9857-44e2-ae12-170c3fce8b62",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4688,
        1216
      ],
      "parameters": {
        "width": 440,
        "height": 808,
        "content": "## Automate intelligent customer support responses with AI and Slack\n\n### How it works\n1. **Receive request** via webhook with customer question\n2. **Analyze sentiment** and detect urgency using JavaScript\n3. **Send urgent alerts** to Slack for critical cases\n4. **Search knowledge base** and fetch conversation history from PostgreSQL\n5. **Generate AI response** with context-aware prompts\n6. **Route intelligently**: Auto-respond via email OR escalate to Slack\n7. **Log everything** to Google Sheets and PostgreSQL for analytics\n\n### Setup steps\n1. **Slack webhooks**: Replace `YOUR_URGENT_WEBHOOK` and `YOUR_ESCALATION_WEBHOOK` with your webhook URLs\n2. **Google Sheets**: Replace `YOUR_SPREADSHEET_ID` with your spreadsheet ID and authenticate\n3. **Email**: Configure SMTP/Gmail credentials in the email node\n4. **PostgreSQL** (optional): Create `support_conversations` table or disable DB nodes\n5. **Production**: Replace mock AI nodes with OpenAI/Anthropic API nodes\n\n### Key features\n- Multi-language support (Japanese & English)\n- Sentiment analysis with urgency detection\n- Smart escalation routing\n- Real-time Slack notifications\n- Comprehensive analytics logging"
      },
      "typeVersion": 1
    },
    {
      "id": "d0bd5bbb-8b47-4c11-a3ad-d80d181d7781",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        5318,
        1368
      ],
      "parameters": {
        "color": 7,
        "width": 820,
        "height": 280,
        "content": "## Intake & Analysis\n\nReceives customer requests, extracts data, and analyzes sentiment/urgency to determine handling priority."
      },
      "typeVersion": 1
    },
    {
      "id": "00089b7e-e250-49e6-b687-e8caa381c7ce",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        6160,
        1296
      ],
      "parameters": {
        "color": 7,
        "width": 500,
        "height": 344,
        "content": "## Urgency Routing\n\nSends immediate Slack alerts for urgent cases (negative sentiment or urgent keywords), then merges paths to continue workflow."
      },
      "typeVersion": 1
    },
    {
      "id": "649f76b7-3f55-4d4c-bd92-71ad0a2cbe3a",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        6786,
        1368
      ],
      "parameters": {
        "color": 7,
        "width": 1020,
        "height": 280,
        "content": "## Context Building & AI Response\n\nFetches conversation history, searches knowledge base, builds AI context, and generates intelligent responses with confidence scoring."
      },
      "typeVersion": 1
    },
    {
      "id": "4fff7600-8288-423c-b3ff-c31bb7f75182",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        7904,
        1280
      ],
      "parameters": {
        "color": 7,
        "width": 740,
        "height": 424,
        "content": "## Smart Routing & Delivery\n\nAnalyzes response quality and decides: auto-respond via email OR escalate to support team via Slack based on confidence score and priority."
      },
      "typeVersion": 1
    },
    {
      "id": "81fd500f-b6a3-4181-a423-27b2ffab280d",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        8656,
        1360
      ],
      "parameters": {
        "color": 7,
        "width": 760,
        "height": 280,
        "content": "## Logging & Response\n\nLogs all interactions to Google Sheets and PostgreSQL for analytics, then sends structured API response with metadata."
      },
      "typeVersion": 1
    },
    {
      "id": "8ade0c3c-2940-4057-8e66-b4c68bb357c0",
      "name": "Webhook Trigger",
      "type": "n8n-nodes-base.webhook",
      "notes": "POST /customer-support\n{\n  \"email\": \"user@example.com\",\n  \"name\": \"John Doe\",\n  \"question\": \"How do I reset my password?\",\n  \"conversationId\": \"optional\",\n  \"language\": \"en\",\n  \"priority\": \"normal\"\n}",
      "position": [
        5344,
        1488
      ],
      "parameters": {
        "path": "customer-support",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 2
    },
    {
      "id": "519c4d0c-3d9b-49b1-aeff-80533846c928",
      "name": "Extract & Enrich Data",
      "type": "n8n-nodes-base.set",
      "notes": "Extracts user data and generates unique IDs",
      "position": [
        5568,
        1488
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "question_id",
              "name": "questionId",
              "type": "string",
              "value": "={{ $now.toISO() }}-{{ $json.body.email.split('@')[0] }}-{{ Math.random().toString(36).substr(2, 9) }}"
            },
            {
              "id": "user_question",
              "name": "userQuestion",
              "type": "string",
              "value": "={{ $json.body.question }}"
            },
            {
              "id": "user_email",
              "name": "userEmail",
              "type": "string",
              "value": "={{ $json.body.email }}"
            },
            {
              "id": "user_name",
              "name": "userName",
              "type": "string",
              "value": "={{ $json.body.name || 'Customer' }}"
            },
            {
              "id": "timestamp",
              "name": "timestamp",
              "type": "string",
              "value": "={{ $now.toISO() }}"
            },
            {
              "id": "conversation_id",
              "name": "conversationId",
              "type": "string",
              "value": "={{ $json.body.conversationId || 'new-' + $now.toMillis() }}"
            },
            {
              "id": "user_language",
              "name": "userLanguage",
              "type": "string",
              "value": "={{ $json.body.language || 'en' }}"
            },
            {
              "id": "priority",
              "name": "priority",
              "type": "string",
              "value": "={{ $json.body.priority || 'normal' }}"
            }
          ]
        }
      },
      "typeVersion": 3.3
    },
    {
      "id": "ff46a5c0-4f3a-4a82-8166-9c0d07bcd879",
      "name": "Sentiment & Context Analysis",
      "type": "n8n-nodes-base.code",
      "notes": "Analyzes sentiment, urgency, and language\nRecommend using OpenAI/Claude API in production",
      "position": [
        5792,
        1488
      ],
      "parameters": {
        "jsCode": "// Sentiment analysis and keyword extraction\nconst question = $input.item.json.userQuestion;\n\n// Simple sentiment analysis (recommend using OpenAI/Claude API in production)\nconst negativeKeywords = ['angry', 'terrible', 'worst', 'refund', 'complaint', 'issue', 'problem', 'frustrated', 'disappointed'];\nconst urgentKeywords = ['urgent', 'immediately', 'asap', 'emergency', 'critical', 'now'];\nconst positiveKeywords = ['thank', 'great', 'excellent', 'satisfied', 'happy', 'appreciate'];\n\nlet sentiment = 'neutral';\nlet urgency = 'normal';\nlet emotionScore = 0;\n\n// Sentiment scoring\nnegativeKeywords.forEach(keyword => {\n  if (question.toLowerCase().includes(keyword)) {\n    emotionScore -= 1;\n    sentiment = 'negative';\n  }\n});\n\npositiveKeywords.forEach(keyword => {\n  if (question.toLowerCase().includes(keyword)) {\n    emotionScore += 1;\n    sentiment = 'positive';\n  }\n});\n\nurgentKeywords.forEach(keyword => {\n  if (question.toLowerCase().includes(keyword)) {\n    urgency = 'high';\n  }\n});\n\n// Very negative cases\nif (emotionScore <= -2) {\n  sentiment = 'very_negative';\n  urgency = 'high';\n}\n\n// Keyword extraction (simplified)\nconst keywords = question\n  .replace(/[!?.,]/g, ' ')\n  .split(' ')\n  .filter(word => word.length > 2)\n  .slice(0, 5);\n\n// Language detection (simplified - supports Japanese/English)\nconst hasKanji = /[\\u4e00-\\u9faf]/.test(question);\nconst hasHiragana = /[\\u3040-\\u309f]/.test(question);\nconst detectedLanguage = (hasKanji || hasHiragana) ? 'ja' : 'en';\n\nreturn {\n  json: {\n    questionId: $input.item.json.questionId,\n    userQuestion: question,\n    userEmail: $input.item.json.userEmail,\n    userName: $input.item.json.userName,\n    conversationId: $input.item.json.conversationId,\n    timestamp: $input.item.json.timestamp,\n    sentiment: sentiment,\n    emotionScore: emotionScore,\n    urgency: urgency,\n    keywords: keywords.join(', '),\n    detectedLanguage: detectedLanguage,\n    requiresImmediateAttention: sentiment === 'very_negative' || urgency === 'high'\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "d4f0a17e-a39a-4aa0-ba3a-b966e4daf621",
      "name": "Urgency Check",
      "type": "n8n-nodes-base.if",
      "notes": "Routes urgent cases to Slack alert",
      "position": [
        6016,
        1488
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "urgent_condition",
              "operator": {
                "type": "boolean",
                "operation": "true"
              },
              "leftValue": "={{ $json.requiresImmediateAttention }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "be626954-1b67-4949-853b-7895a97435d4",
      "name": "Send Urgent Alert",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "Sends urgent alert to Slack\nReplace YOUR_URGENT_WEBHOOK with actual webhook URL",
      "position": [
        6240,
        1416
      ],
      "parameters": {
        "url": "https://hooks.slack.com/services/YOUR_URGENT_WEBHOOK",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"text\": \"\ud83d\udea8 *Urgent Support Request*\",\n  \"blocks\": [\n    {\n      \"type\": \"header\",\n      \"text\": {\n        \"type\": \"plain_text\",\n        \"text\": \"\u26a0\ufe0f Urgent Support Request Received\"\n      }\n    },\n    {\n      \"type\": \"section\",\n      \"fields\": [\n        {\n          \"type\": \"mrkdwn\",\n          \"text\": \"*Sentiment:*\\n{{ $json.sentiment === 'very_negative' ? '\ud83d\ude21 Very Negative' : '\u26a1 Urgent' }}\"\n        },\n        {\n          \"type\": \"mrkdwn\",\n          \"text\": \"*Priority:*\\n\ud83d\udd34 High\"\n        },\n        {\n          \"type\": \"mrkdwn\",\n          \"text\": \"*User:*\\n{{ $json.userName }} ({{ $json.userEmail }})\"\n        },\n        {\n          \"type\": \"mrkdwn\",\n          \"text\": \"*Time:*\\n{{ $json.timestamp }}\"\n        }\n      ]\n    },\n    {\n      \"type\": \"section\",\n      \"text\": {\n        \"type\": \"mrkdwn\",\n        \"text\": \"*Question:*\\n```{{ $json.userQuestion }}```\"\n      }\n    },\n    {\n      \"type\": \"section\",\n      \"text\": {\n        \"type\": \"mrkdwn\",\n        \"text\": \"*Keywords:* {{ $json.keywords }}\"\n      }\n    },\n    {\n      \"type\": \"actions\",\n      \"elements\": [\n        {\n          \"type\": \"button\",\n          \"text\": {\n            \"type\": \"plain_text\",\n            \"text\": \"Respond Now\"\n          },\n          \"style\": \"danger\",\n          \"url\": \"https://your-dashboard.com/urgent/{{ $json.questionId }}\"\n        }\n      ]\n    }\n  ]\n}",
        "sendBody": true,
        "specifyBody": "json"
      },
      "typeVersion": 4.2
    },
    {
      "id": "748e4c16-6c42-4a24-8159-e9d0ca4c08c5",
      "name": "Merge After Urgency",
      "type": "n8n-nodes-base.merge",
      "notes": "Merges urgent and normal paths",
      "position": [
        6464,
        1488
      ],
      "parameters": {},
      "typeVersion": 3
    },
    {
      "id": "b70fd79f-6445-4978-9482-4712533f0c1e",
      "name": "Fetch Conversation History",
      "type": "n8n-nodes-base.postgres",
      "notes": "Fetches past conversation history from PostgreSQL\nDisable this node if table doesn't exist",
      "position": [
        6688,
        1488
      ],
      "parameters": {
        "query": "=SELECT conversation_history, created_at \nFROM support_conversations \nWHERE conversation_id = '{{ $json.conversationId }}' \nOR user_email = '{{ $json.userEmail }}'\nORDER BY created_at DESC \nLIMIT 5",
        "options": {},
        "operation": "executeQuery"
      },
      "typeVersion": 2.4
    },
    {
      "id": "b556035b-feeb-4cd4-8ff6-30d816abb61f",
      "name": "Search Knowledge Base",
      "type": "n8n-nodes-base.code",
      "notes": "Searches knowledge base (currently mock)\nReplace with Pinecone/Supabase node in production",
      "position": [
        6912,
        1488
      ],
      "parameters": {
        "jsCode": "// Knowledge base search simulation\n// In production: use Pinecone/Supabase/Qdrant for vector search\nconst question = $input.item.json.userQuestion;\nconst language = $input.item.json.detectedLanguage;\n\n// Mock search results (replace with actual vector search)\nconst mockSearchResults = language === 'ja' ? [\n  {\n    text: \"\u30d1\u30b9\u30ef\u30fc\u30c9\u30ea\u30bb\u30c3\u30c8\u306f\u3001\u30ed\u30b0\u30a4\u30f3\u753b\u9762\u306e\u300c\u30d1\u30b9\u30ef\u30fc\u30c9\u3092\u5fd8\u308c\u305f\u65b9\u300d\u30ea\u30f3\u30af\u304b\u3089\u884c\u3048\u307e\u3059\u3002\u767b\u9332\u6e08\u307f\u306e\u30e1\u30fc\u30eb\u30a2\u30c9\u30ec\u30b9\u306b\u30ea\u30bb\u30c3\u30c8\u7528\u306e\u30ea\u30f3\u30af\u304c\u9001\u4fe1\u3055\u308c\u307e\u3059\u3002\",\n    score: 0.85,\n    metadata: { category: \"Account Management\", source: \"FAQ-001\" }\n  },\n  {\n    text: \"\u30e1\u30fc\u30eb\u30a2\u30c9\u30ec\u30b9\u306e\u5909\u66f4\u306f\u3001\u30a2\u30ab\u30a6\u30f3\u30c8\u8a2d\u5b9a\u30da\u30fc\u30b8\u304b\u3089\u53ef\u80fd\u3067\u3059\u3002\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u306e\u305f\u3081\u3001\u73fe\u5728\u306e\u30d1\u30b9\u30ef\u30fc\u30c9\u306e\u5165\u529b\u304c\u5fc5\u8981\u306b\u306a\u308a\u307e\u3059\u3002\",\n    score: 0.72,\n    metadata: { category: \"Account Management\", source: \"FAQ-003\" }\n  }\n] : [\n  {\n    text: \"To reset your password, click the 'Forgot Password' link on the login page. A reset link will be sent to your registered email address.\",\n    score: 0.85,\n    metadata: { category: \"Account Management\", source: \"FAQ-001\" }\n  },\n  {\n    text: \"You can change your email address from the Account Settings page. For security reasons, you'll need to enter your current password.\",\n    score: 0.72,\n    metadata: { category: \"Account Management\", source: \"FAQ-003\" }\n  }\n];\n\nreturn {\n  json: {\n    ...($input.item.json),\n    searchResults: mockSearchResults\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "b5132f09-072b-46e8-98a9-e28ff3eeebaa",
      "name": "Build AI Context",
      "type": "n8n-nodes-base.code",
      "notes": "Builds comprehensive AI context with prompt engineering",
      "position": [
        7136,
        1488
      ],
      "parameters": {
        "jsCode": "// Builds AI context from search results and conversation history\nconst searchResults = $input.item.json.searchResults || [];\nconst conversationHistory = $('Fetch Conversation History').all();\nconst currentData = $input.item.json;\n\n// Format conversation history\nlet historyContext = '';\nif (conversationHistory.length > 0) {\n  historyContext = '\\n\u3010Past Conversation History\u3011\\n';\n  conversationHistory.forEach((conv, idx) => {\n    if (conv.json.conversation_history) {\n      historyContext += `${idx + 1}. ${conv.json.conversation_history}\\n`;\n    }\n  });\n}\n\n// Format search results\nlet knowledgeContext = '';\nif (Array.isArray(searchResults) && searchResults.length > 0) {\n  knowledgeContext = '\\n\u3010Knowledge Base Results\u3011\\n';\n  searchResults.forEach((result, idx) => {\n    knowledgeContext += `${idx + 1}. ${result.text}\\n`;\n    knowledgeContext += `   Relevance: ${(result.score * 100).toFixed(1)}%\\n`;\n    knowledgeContext += `   Source: ${result.metadata?.source || 'Unknown'}\\n\\n`;\n  });\n} else {\n  knowledgeContext = '\\n\u3010Knowledge Base Results\u3011\\nNo relevant information found.\\n';\n}\n\n// Tone guidance based on sentiment\nlet toneGuidance = '';\nswitch(currentData.sentiment) {\n  case 'very_negative':\n    toneGuidance = 'Use a very polite and apologetic tone. Acknowledge the customer\\'s frustration and provide quick solutions.';\n    break;\n  case 'negative':\n    toneGuidance = 'Be empathetic and understanding. Show genuine concern and work towards resolution.';\n    break;\n  case 'positive':\n    toneGuidance = 'Express appreciation and maintain a friendly tone. Keep the positive momentum.';\n    break;\n  default:\n    toneGuidance = 'Use a professional and helpful tone. Provide clear and concise information.';\n}\n\n// Build AI prompt\nconst aiPrompt = `\nYou are a professional customer support representative. Answer the customer's question based on the following information.\n\n\u3010Customer Information\u3011\nName: ${currentData.userName}\nEmail: ${currentData.userEmail}\nLanguage: ${currentData.detectedLanguage === 'ja' ? 'Japanese' : 'English'}\nSentiment: ${currentData.sentiment}\nUrgency: ${currentData.urgency}\n\n\u3010Question\u3011\n${currentData.userQuestion}\n\n${knowledgeContext}\n${historyContext}\n\n\u3010Response Guidelines\u3011\n${toneGuidance}\n\n\u3010Instructions\u3011\n1. Use knowledge base information to provide accurate answers\n2. Consider past conversation history if available\n3. Include the following metadata at the end:\n   CONFIDENCE_SCORE: [0-100]\n   REQUIRES_FOLLOWUP: [true/false]\n   SUGGESTED_CATEGORY: [category name]\n`;\n\nreturn {\n  json: {\n    ...currentData,\n    knowledgeContext: knowledgeContext,\n    historyContext: historyContext,\n    toneGuidance: toneGuidance,\n    aiPrompt: aiPrompt,\n    hasHistory: conversationHistory.length > 0,\n    searchResultCount: searchResults.length\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "c8f42c73-bd2a-4f19-99bf-bb9d19961549",
      "name": "AI Response Generator",
      "type": "n8n-nodes-base.code",
      "notes": "Generates AI response (currently mock)\nReplace with OpenAI/Anthropic node in production",
      "position": [
        7360,
        1488
      ],
      "parameters": {
        "jsCode": "// AI response generation simulation\n// In production: replace with OpenAI/Claude API\nconst context = $input.item.json;\nconst language = context.detectedLanguage;\n\n// Generate mock response\nconst greeting = language === 'ja' ? \n  `${context.userName}\u69d8\\n\\n\u304a\u554f\u3044\u5408\u308f\u305b\u3044\u305f\u3060\u304d\u3042\u308a\u304c\u3068\u3046\u3054\u3056\u3044\u307e\u3059\u3002` :\n  `Dear ${context.userName},\\n\\nThank you for your inquiry.`;\n\nconst mainContent = language === 'ja' ?\n  `\\n\\n\u3054\u8cea\u554f\u306e\u4ef6\u306b\u3064\u3044\u3066\u3001\u4ee5\u4e0b\u306e\u901a\u308a\u3054\u6848\u5185\u3055\u305b\u3066\u3044\u305f\u3060\u304d\u307e\u3059\u3002\\n\\n${context.knowledgeContext}\\n\\n\u4e0a\u8a18\u306e\u60c5\u5831\u304c\u304a\u5f79\u306b\u7acb\u3066\u3070\u5e78\u3044\u3067\u3059\u3002` :\n  `\\n\\nRegarding your question, here is the information you need:\\n\\n${context.knowledgeContext}\\n\\nI hope this information is helpful.`;\n\nconst closing = language === 'ja' ?\n  `\\n\\n\u3054\u4e0d\u660e\u306a\u70b9\u304c\u3054\u3056\u3044\u307e\u3057\u305f\u3089\u3001\u304a\u6c17\u8efd\u306b\u304a\u554f\u3044\u5408\u308f\u305b\u304f\u3060\u3055\u3044\u3002\\n\\n\u4eca\u5f8c\u3068\u3082\u3088\u308d\u3057\u304f\u304a\u9858\u3044\u3044\u305f\u3057\u307e\u3059\u3002` :\n  `\\n\\nIf you have any further questions, please don't hesitate to ask.\\n\\nBest regards,\\nSupport Team`;\n\n// Calculate confidence score based on search quality\nconst avgScore = context.searchResults && context.searchResults.length > 0 ?\n  context.searchResults.reduce((sum, r) => sum + r.score, 0) / context.searchResults.length :\n  0.3;\n\nconst confidenceScore = Math.round(avgScore * 100);\n\n// Determine if followup is needed\nconst requiresFollowup = \n  confidenceScore < 70 || \n  context.sentiment === 'very_negative' ||\n  context.searchResultCount === 0;\n\n// Categorize question\nconst question = context.userQuestion.toLowerCase();\nlet category = 'General';\nif (question.includes('password') || question.includes('\u30d1\u30b9\u30ef\u30fc\u30c9')) category = 'Account Management';\nelse if (question.includes('payment') || question.includes('\u652f\u6255') || question.includes('billing')) category = 'Billing';\nelse if (question.includes('bug') || question.includes('error') || question.includes('\u30d0\u30b0') || question.includes('\u30a8\u30e9\u30fc')) category = 'Technical Support';\nelse if (question.includes('refund') || question.includes('\u8fd4\u91d1') || question.includes('cancel')) category = 'Refunds';\n\nconst mockAIResponse = `${greeting}${mainContent}${closing}\n\nCONFIDENCE_SCORE: ${confidenceScore}\nREQUIRES_FOLLOWUP: ${requiresFollowup}\nSUGGESTED_CATEGORY: ${category}`;\n\nreturn {\n  json: {\n    ...context,\n    response: mockAIResponse\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "9a826727-8466-4099-b8dd-dd7e4130bd84",
      "name": "Process & Analyze Response",
      "type": "n8n-nodes-base.code",
      "notes": "Analyzes AI response and determines escalation need",
      "position": [
        7584,
        1488
      ],
      "parameters": {
        "jsCode": "// Analyzes AI response and determines routing\nconst aiResponse = $input.item.json.response;\nconst contextData = $input.item.json;\n\n// Extract metadata\nconst confidenceMatch = aiResponse.match(/CONFIDENCE_SCORE:\\s*(\\d+)/);\nconst followupMatch = aiResponse.match(/REQUIRES_FOLLOWUP:\\s*(true|false)/);\nconst categoryMatch = aiResponse.match(/SUGGESTED_CATEGORY:\\s*(.+)/);\n\nconst confidenceScore = confidenceMatch ? parseInt(confidenceMatch[1]) : 0;\nconst requiresFollowup = followupMatch ? followupMatch[1] === 'true' : false;\nconst suggestedCategory = categoryMatch ? categoryMatch[1].trim() : 'Uncategorized';\n\n// Clean response (remove metadata)\nconst cleanResponse = aiResponse\n  .replace(/CONFIDENCE_SCORE:\\s*\\d+/g, '')\n  .replace(/REQUIRES_FOLLOWUP:\\s*(true|false)/g, '')\n  .replace(/SUGGESTED_CATEGORY:\\s*.+/g, '')\n  .trim();\n\n// Escalation logic\nconst needsEscalation = \n  confidenceScore < 70 ||  // Low confidence\n  requiresFollowup ||       // Needs followup\n  contextData.sentiment === 'very_negative' ||  // Very negative\n  contextData.urgency === 'high' ||  // High urgency\n  cleanResponse.includes('escalate') || // Explicit escalation\n  contextData.searchResultCount === 0;  // No knowledge base results\n\n// Priority scoring\nlet priorityScore = 0;\nif (contextData.sentiment === 'very_negative') priorityScore += 30;\nif (contextData.urgency === 'high') priorityScore += 25;\nif (confidenceScore < 50) priorityScore += 20;\nif (requiresFollowup) priorityScore += 15;\nif (contextData.emotionScore < -1) priorityScore += 10;\nif (contextData.searchResultCount === 0) priorityScore += 10;\n\nconst priority = priorityScore >= 50 ? 'critical' : \n                 priorityScore >= 30 ? 'high' : \n                 priorityScore >= 15 ? 'medium' : 'low';\n\n// Estimated response time\nconst estimatedResponseTime = \n  priority === 'critical' ? 'Within 1 hour' :\n  priority === 'high' ? 'Within 4 hours' :\n  priority === 'medium' ? 'Within 24 hours' : 'Within 48 hours';\n\nreturn {\n  json: {\n    questionId: contextData.questionId,\n    conversationId: contextData.conversationId,\n    userQuestion: contextData.userQuestion,\n    userEmail: contextData.userEmail,\n    userName: contextData.userName,\n    aiResponse: cleanResponse,\n    confidenceScore: confidenceScore,\n    requiresFollowup: requiresFollowup,\n    suggestedCategory: suggestedCategory,\n    needsEscalation: needsEscalation,\n    priority: priority,\n    priorityScore: priorityScore,\n    sentiment: contextData.sentiment,\n    emotionScore: contextData.emotionScore,\n    urgency: contextData.urgency,\n    detectedLanguage: contextData.detectedLanguage,\n    keywords: contextData.keywords,\n    status: needsEscalation ? 'escalated' : 'auto_resolved',\n    timestamp: contextData.timestamp,\n    hasHistory: contextData.hasHistory,\n    searchResultCount: contextData.searchResultCount,\n    estimatedResponseTime: estimatedResponseTime\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "0afc78ac-509f-4a9b-a183-bf97fdebab25",
      "name": "Routing Decision",
      "type": "n8n-nodes-base.if",
      "notes": "Routes to escalation or auto-response",
      "position": [
        7808,
        1488
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "escalation_condition",
              "operator": {
                "type": "boolean",
                "operation": "true"
              },
              "leftValue": "={{ $json.needsEscalation }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "6c741000-e1d9-46bb-8148-9e688517f69a",
      "name": "Slack Escalation",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "Sends detailed escalation to Slack\nReplace YOUR_ESCALATION_WEBHOOK with actual URL",
      "position": [
        8032,
        1392
      ],
      "parameters": {
        "url": "https://hooks.slack.com/services/YOUR_ESCALATION_WEBHOOK",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"text\": \"\ud83d\udccb *Support Question Escalation*\",\n  \"blocks\": [\n    {\n      \"type\": \"header\",\n      \"text\": {\n        \"type\": \"plain_text\",\n        \"text\": \"{{ $json.priority === 'critical' ? '\ud83d\udd34' : $json.priority === 'high' ? '\ud83d\udfe0' : '\ud83d\udfe1' }} Support Question Escalated\"\n      }\n    },\n    {\n      \"type\": \"section\",\n      \"fields\": [\n        {\n          \"type\": \"mrkdwn\",\n          \"text\": \"*Question ID:*\\n`{{ $json.questionId }}`\"\n        },\n        {\n          \"type\": \"mrkdwn\",\n          \"text\": \"*Priority:*\\n{{ $json.priority === 'critical' ? '\ud83d\udd34 Critical' : $json.priority === 'high' ? '\ud83d\udfe0 High' : $json.priority === 'medium' ? '\ud83d\udfe1 Medium' : '\ud83d\udfe2 Low' }} ({{ $json.priorityScore }}pts)\"\n        },\n        {\n          \"type\": \"mrkdwn\",\n          \"text\": \"*User:*\\n{{ $json.userName }}\\n{{ $json.userEmail }}\"\n        },\n        {\n          \"type\": \"mrkdwn\",\n          \"text\": \"*Category:*\\n{{ $json.suggestedCategory }}\"\n        },\n        {\n          \"type\": \"mrkdwn\",\n          \"text\": \"*Sentiment:*\\n{{ $json.sentiment === 'very_negative' ? '\ud83d\ude21 Very Negative' : $json.sentiment === 'negative' ? '\ud83d\ude1e Negative' : $json.sentiment === 'positive' ? '\ud83d\ude0a Positive' : '\ud83d\ude10 Neutral' }}\"\n        },\n        {\n          \"type\": \"mrkdwn\",\n          \"text\": \"*Confidence:*\\n{{ $json.confidenceScore }}%\"\n        }\n      ]\n    },\n    {\n      \"type\": \"section\",\n      \"text\": {\n        \"type\": \"mrkdwn\",\n        \"text\": \"*Question:*\\n```{{ $json.userQuestion }}```\"\n      }\n    },\n    {\n      \"type\": \"section\",\n      \"text\": {\n        \"type\": \"mrkdwn\",\n        \"text\": \"*AI Suggested Response:*\\n{{ $json.aiResponse.substring(0, 500) }}{{ $json.aiResponse.length > 500 ? '...' : '' }}\"\n      }\n    },\n    {\n      \"type\": \"context\",\n      \"elements\": [\n        {\n          \"type\": \"mrkdwn\",\n          \"text\": \"{{ $json.hasHistory ? '\ud83d\udcda Has history' : '\ud83c\udd95 New user' }} | \u23f0 {{ $json.timestamp }} | \ud83d\udd50 ETA: {{ $json.estimatedResponseTime }}\"\n        }\n      ]\n    },\n    {\n      \"type\": \"actions\",\n      \"elements\": [\n        {\n          \"type\": \"button\",\n          \"text\": {\n            \"type\": \"plain_text\",\n            \"text\": \"Respond\"\n          },\n          \"style\": \"primary\",\n          \"url\": \"https://your-dashboard.com/tickets/{{ $json.questionId }}\"\n        },\n        {\n          \"type\": \"button\",\n          \"text\": {\n            \"type\": \"plain_text\",\n            \"text\": \"View History\"\n          },\n          \"url\": \"https://your-dashboard.com/conversations/{{ $json.conversationId }}\"\n        }\n      ]\n    }\n  ]\n}",
        "sendBody": true,
        "specifyBody": "json"
      },
      "typeVersion": 4.2
    },
    {
      "id": "58bb256c-d358-4c2e-b3f1-a1f2c8cfd878",
      "name": "Send Auto Response",
      "type": "n8n-nodes-base.emailSend",
      "notes": "Sends automated email response\nConfigure SMTP/Gmail credentials",
      "position": [
        8032,
        1584
      ],
      "parameters": {
        "options": {},
        "subject": "={{ $json.detectedLanguage === 'ja' ? '\u304a\u554f\u3044\u5408\u308f\u305b\u3042\u308a\u304c\u3068\u3046\u3054\u3056\u3044\u307e\u3059 - ' + $json.suggestedCategory : 'Thank you for your inquiry - ' + $json.suggestedCategory }}",
        "toEmail": "={{ $json.userEmail }}",
        "fromEmail": "support@example.com"
      },
      "typeVersion": 2.1
    },
    {
      "id": "07f7566e-2222-4202-b77e-eb37a9aa42e8",
      "name": "Merge After Routing",
      "type": "n8n-nodes-base.merge",
      "notes": "Merges escalation and auto-response paths",
      "position": [
        8256,
        1488
      ],
      "parameters": {},
      "typeVersion": 3
    },
    {
      "id": "2cf2d1e3-b1bc-4985-a85a-52470963dd0c",
      "name": "Log to Analytics Dashboard",
      "type": "n8n-nodes-base.googleSheets",
      "notes": "Logs all interactions to Google Sheets\nReplace YOUR_SPREADSHEET_ID and authenticate",
      "position": [
        8480,
        1488
      ],
      "parameters": {
        "columns": {
          "value": {
            "status": "={{ $json.status }}",
            "urgency": "={{ $json.urgency }}",
            "category": "={{ $json.suggestedCategory }}",
            "keywords": "={{ $json.keywords }}",
            "language": "={{ $json.detectedLanguage }}",
            "priority": "={{ $json.priority }}",
            "question": "={{ $json.userQuestion }}",
            "userName": "={{ $json.userName }}",
            "sentiment": "={{ $json.sentiment }}",
            "timestamp": "={{ $json.timestamp }}",
            "userEmail": "={{ $json.userEmail }}",
            "aiResponse": "={{ $json.aiResponse }}",
            "questionId": "={{ $json.questionId }}",
            "confidenceScore": "={{ $json.confidenceScore }}"
          },
          "schema": [
            {
              "id": "questionId",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Question ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "questionId"
          ]
        },
        "options": {},
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_SPREADSHEET_ID"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "11f74c26-387e-4510-8691-047eeb7d87cc",
      "name": "Save to Database",
      "type": "n8n-nodes-base.postgres",
      "notes": "Saves conversation to PostgreSQL\nDisable if table doesn't exist",
      "position": [
        8704,
        1488
      ],
      "parameters": {
        "query": "=INSERT INTO support_conversations \n(conversation_id, question_id, user_email, user_name, question, ai_response, confidence_score, sentiment, priority, status, created_at)\nVALUES \n('{{ $json.conversationId }}', '{{ $json.questionId }}', '{{ $json.userEmail }}', '{{ $json.userName }}', '{{ $json.userQuestion }}', '{{ $json.aiResponse }}', {{ $json.confidenceScore }}, '{{ $json.sentiment }}', '{{ $json.priority }}', '{{ $json.status }}', CURRENT_TIMESTAMP)\nON CONFLICT (question_id) DO UPDATE SET\n  ai_response = EXCLUDED.ai_response,\n  confidence_score = EXCLUDED.confidence_score,\n  status = EXCLUDED.status,\n  updated_at = CURRENT_TIMESTAMP",
        "options": {},
        "operation": "executeQuery"
      },
      "typeVersion": 2.4
    },
    {
      "id": "239c977d-4942-4b8e-88ab-d4beabc04c75",
      "name": "Send API Response",
      "type": "n8n-nodes-base.respondToWebhook",
      "notes": "Returns structured API response with metadata",
      "position": [
        8928,
        1488
      ],
      "parameters": {
        "options": {},
        "respondWith": "json",
        "responseBody": "={{ {\n  \"success\": true,\n  \"questionId\": $json.questionId,\n  \"conversationId\": $json.conversationId,\n  \"status\": $json.status,\n  \"priority\": $json.priority,\n  \"message\": $json.status === 'auto_resolved' ? \n    ($json.detectedLanguage === 'ja' ? '\u3054\u8cea\u554f\u3042\u308a\u304c\u3068\u3046\u3054\u3056\u3044\u307e\u3059\u3002\u81ea\u52d5\u5fdc\u7b54\u30e1\u30fc\u30eb\u3092\u304a\u9001\u308a\u3057\u307e\u3057\u305f\u3002' : 'Thank you for your question. An automated response has been sent to your email.') :\n    ($json.detectedLanguage === 'ja' ? '\u3054\u8cea\u554f\u3042\u308a\u304c\u3068\u3046\u3054\u3056\u3044\u307e\u3059\u3002\u62c5\u5f53\u8005\u304c\u78ba\u8a8d\u5f8c\u3001\u3054\u9023\u7d61\u3055\u305b\u3066\u3044\u305f\u3060\u304d\u307e\u3059\u3002' : 'Thank you for your question. Our team will review and get back to you soon.'),\n  \"response\": $json.aiResponse,\n  \"metadata\": {\n    \"confidenceScore\": $json.confidenceScore,\n    \"category\": $json.suggestedCategory,\n    \"sentiment\": $json.sentiment,\n    \"language\": $json.detectedLanguage,\n    \"requiresFollowup\": $json.requiresFollowup,\n    \"estimatedResponseTime\": $json.estimatedResponseTime\n  }\n} }}"
      },
      "typeVersion": 1.1
    }
  ],
  "connections": {
    "Urgency Check": {
      "main": [
        [
          {
            "node": "Send Urgent Alert",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Merge After Urgency",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Webhook Trigger": {
      "main": [
        [
          {
            "node": "Extract & Enrich Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build AI Context": {
      "main": [
        [
          {
            "node": "AI Response Generator",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Routing Decision": {
      "main": [
        [
          {
            "node": "Slack Escalation",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Send Auto Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save to Database": {
      "main": [
        [
          {
            "node": "Send API Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Slack Escalation": {
      "main": [
        [
          {
            "node": "Merge After Routing",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Urgent Alert": {
      "main": [
        [
          {
            "node": "Merge After Urgency",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Auto Response": {
      "main": [
        [
          {
            "node": "Merge After Routing",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Merge After Routing": {
      "main": [
        [
          {
            "node": "Log to Analytics Dashboard",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge After Urgency": {
      "main": [
        [
          {
            "node": "Fetch Conversation History",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Response Generator": {
      "main": [
        [
          {
            "node": "Process & Analyze Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract & Enrich Data": {
      "main": [
        [
          {
            "node": "Sentiment & Context Analysis",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Search Knowledge Base": {
      "main": [
        [
          {
            "node": "Build AI Context",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Conversation History": {
      "main": [
        [
          {
            "node": "Search Knowledge Base",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log to Analytics Dashboard": {
      "main": [
        [
          {
            "node": "Save to Database",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Process & Analyze Response": {
      "main": [
        [
          {
            "node": "Routing Decision",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Sentiment & Context Analysis": {
      "main": [
        [
          {
            "node": "Urgency Check",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}