{
  "id": "hAijyRcR9xXmda5H",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "AI Brand Reputation Crisis Detector",
  "tags": [],
  "nodes": [
    {
      "id": "930025e9-0425-48c5-9e61-489fe3c9d024",
      "name": "Every 10 Minutes",
      "type": "n8n-nodes-base.scheduleTrigger",
      "notes": "Runs every 10 minutes for near real-time brand monitoring",
      "position": [
        96,
        176
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "minutes",
              "minutesInterval": 10
            }
          ]
        }
      },
      "notesInFlow": true,
      "typeVersion": 1.2
    },
    {
      "id": "d3467c72-9fac-47df-846e-471ac561367f",
      "name": "Monitor Twitter/X",
      "type": "n8n-nodes-base.twitter",
      "notes": "Searches for brand mentions on Twitter/X",
      "position": [
        320,
        -16
      ],
      "parameters": {
        "limit": 100,
        "operation": "search",
        "searchText": "={{ $json.brandName || 'YourBrandName' }} OR @{{ $json.brandHandle || 'yourbrand' }}",
        "additionalFields": {}
      },
      "credentials": {
        "twitterOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "1057b564-c8d2-4367-a0fe-9f7de0b14174",
      "name": "Monitor Reddit",
      "type": "n8n-nodes-base.reddit",
      "notes": "Searches for brand mentions on Reddit",
      "position": [
        320,
        176
      ],
      "parameters": {
        "limit": 50,
        "keyword": "=",
        "operation": "search",
        "subreddit": "all",
        "additionalFields": {}
      },
      "credentials": {
        "redditOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "notesInFlow": true,
      "typeVersion": 1
    },
    {
      "id": "60a65ed8-05b5-46a2-9944-3495d36fc8e1",
      "name": "Monitor News & Blogs",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "Searches news articles and blog posts via News API",
      "position": [
        320,
        368
      ],
      "parameters": {
        "url": "=https://newsapi.org/v2/everything?q={{ $json.brandName || 'YourBrandName' }}&sortBy=publishedAt&pageSize=50&apiKey=YOUR_NEWS_API_KEY",
        "options": {}
      },
      "notesInFlow": true,
      "typeVersion": 4.2
    },
    {
      "id": "97af41ff-80a7-406f-b483-e6b784bec436",
      "name": "Normalize Data Format",
      "type": "n8n-nodes-base.code",
      "notes": "Converts all platform data to unified format",
      "position": [
        544,
        176
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Normalize data from different platforms to unified format\nconst item = $input.item.json;\nlet normalized = {};\n\n// Detect platform and normalize\nif (item.tweet_id || item.id_str || item.text) {\n  // Twitter/X format\n  normalized = {\n    platform: 'twitter',\n    id: item.id_str || item.id,\n    text: item.text || item.full_text || '',\n    author: item.user?.screen_name || 'unknown',\n    authorFollowers: item.user?.followers_count || 0,\n    timestamp: item.created_at,\n    url: `https://twitter.com/${item.user?.screen_name}/status/${item.id_str}`,\n    engagement: (item.retweet_count || 0) + (item.favorite_count || 0),\n    isVerified: item.user?.verified || false\n  };\n} else if (item.subreddit || item.permalink) {\n  // Reddit format\n  normalized = {\n    platform: 'reddit',\n    id: item.id,\n    text: `${item.title || ''} ${item.selftext || ''}`,\n    author: item.author || 'unknown',\n    authorFollowers: 0,\n    timestamp: new Date(item.created_utc * 1000).toISOString(),\n    url: `https://reddit.com${item.permalink}`,\n    engagement: (item.score || 0) + (item.num_comments || 0),\n    subreddit: item.subreddit,\n    isVerified: false\n  };\n} else if (item.title && item.source) {\n  // News API format\n  normalized = {\n    platform: 'news',\n    id: item.url,\n    text: `${item.title || ''} ${item.description || ''}`,\n    author: item.author || item.source?.name || 'unknown',\n    authorFollowers: 0,\n    timestamp: item.publishedAt,\n    url: item.url,\n    engagement: 0,\n    source: item.source?.name,\n    isVerified: true // News sources are considered verified\n  };\n} else {\n  // Unknown format - try to extract what we can\n  normalized = {\n    platform: 'unknown',\n    id: item.id || Date.now().toString(),\n    text: item.text || item.content || JSON.stringify(item),\n    author: item.author || 'unknown',\n    authorFollowers: 0,\n    timestamp: item.timestamp || new Date().toISOString(),\n    url: item.url || '',\n    engagement: 0,\n    isVerified: false\n  };\n}\n\nnormalized.rawData = item;\n\nreturn { json: normalized };"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "9931cce1-ef16-4334-bad5-55d5c445b0ff",
      "name": "Remove Duplicates",
      "type": "n8n-nodes-base.filter",
      "notes": "Filters out already-analyzed mentions",
      "position": [
        768,
        176
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": false,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "5e6f7g8h-9i0j-1k2l-3m4n-o5p6q7r8s9t0",
              "operator": {
                "type": "string",
                "operation": "isNotEmpty"
              },
              "leftValue": "={{ $json.text }}"
            },
            {
              "id": "6f7g8h9i-0j1k-2l3m-4n5o-p6q7r8s9t0u1",
              "operator": {
                "type": "string",
                "operation": "isNotEmpty"
              },
              "leftValue": "={{ $json.id }}"
            }
          ]
        }
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "973eef39-a26c-48bc-8b16-c015021b3330",
      "name": "Merge Platform Data",
      "type": "n8n-nodes-base.merge",
      "notes": "Combines mentions from all platforms",
      "position": [
        992,
        176
      ],
      "parameters": {},
      "notesInFlow": true,
      "typeVersion": 3
    },
    {
      "id": "8562740d-60d9-44f3-80e0-81b41d134761",
      "name": "Track Analyzed Mentions",
      "type": "n8n-nodes-base.code",
      "notes": "Prevents duplicate analysis using workflow static data",
      "position": [
        1216,
        176
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Check if we've already analyzed this mention\nconst mentionId = $input.item.json.id;\nconst platform = $input.item.json.platform;\n\n// Create a unique key for this mention\nconst uniqueKey = `${platform}_${mentionId}`;\n\n// Use workflow static data to store analyzed mentions\nconst analyzedMentions = $getWorkflowStaticData('global').analyzedMentions || {};\n\nif (analyzedMentions[uniqueKey]) {\n  // Already analyzed this mention\n  return { json: { skip: true, reason: 'Already analyzed' } };\n}\n\n// Mark as analyzed\nanalyzedMentions[uniqueKey] = {\n  timestamp: new Date().toISOString(),\n  analyzed: true\n};\n\n// Clean up old entries (older than 7 days)\nconst sevenDaysAgo = Date.now() - (7 * 24 * 60 * 60 * 1000);\nfor (const key in analyzedMentions) {\n  const entryTime = new Date(analyzedMentions[key].timestamp).getTime();\n  if (entryTime < sevenDaysAgo) {\n    delete analyzedMentions[key];\n  }\n}\n\n// Save back to static data\n$getWorkflowStaticData('global').analyzedMentions = analyzedMentions;\n\nreturn { \n  json: { \n    skip: false, \n    ...($input.item.json),\n    uniqueKey,\n    analysisTimestamp: new Date().toISOString()\n  } \n};"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "cdbd74a0-8619-46ec-a858-f00721acb823",
      "name": "API Rate Limiter",
      "type": "n8n-nodes-base.wait",
      "notes": "Prevents API rate limit issues",
      "position": [
        1440,
        176
      ],
      "parameters": {
        "amount": 1
      },
      "notesInFlow": true,
      "typeVersion": 1.1
    },
    {
      "id": "1b32e48c-8425-4ada-b243-327572294b70",
      "name": "Only New Mentions",
      "type": "n8n-nodes-base.filter",
      "notes": "Filters to unanalyzed mentions only",
      "position": [
        1664,
        176
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": false,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "9i0j1k2l-3m4n-5o6p-7q8r-s9t0u1v2w3x4",
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ $json.skip }}",
              "rightValue": "false"
            }
          ]
        }
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "ef03f71b-7083-4e23-b0ba-7e306c3578aa",
      "name": "AI Sentiment Analysis Engine",
      "type": "n8n-nodes-base.code",
      "notes": "Analyzes sentiment and detects negative trends",
      "position": [
        1888,
        176
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// AI-powered sentiment analysis engine\nconst mention = $input.item.json;\nconst text = (mention.text || '').toLowerCase();\n\n// Sentiment keyword dictionaries\nconst negativePhrases = {\n  critical: ['scam', 'fraud', 'lawsuit', 'illegal', 'criminal', 'investigate', 'sue', 'boycott', 'terrible', 'worst', 'horrible', 'awful', 'disaster', 'catastrophe', 'dangerous', 'unsafe', 'toxic', 'predatory'],\n  severe: ['disappointed', 'unacceptable', 'disgraceful', 'shameful', 'pathetic', 'failure', 'failed', 'broken', 'useless', 'waste', 'regret', 'never again', 'avoid', 'warning', 'beware', 'don\\'t buy'],\n  moderate: ['bad', 'poor', 'not good', 'mediocre', 'subpar', 'lacking', 'issues', 'problems', 'concerns', 'unhappy', 'dissatisfied', 'frustrated', 'annoyed'],\n  mild: ['okay', 'fine', 'average', 'could be better', 'meh', 'not impressed']\n};\n\nconst positivePhrases = {\n  strong: ['amazing', 'excellent', 'outstanding', 'phenomenal', 'incredible', 'fantastic', 'brilliant', 'perfect', 'love it', 'best ever', 'highly recommend', 'game changer'],\n  moderate: ['good', 'great', 'nice', 'happy', 'satisfied', 'pleased', 'enjoy', 'like', 'recommend', 'quality'],\n  mild: ['decent', 'acceptable', 'fine', 'works', 'not bad']\n};\n\n// Calculate sentiment scores\nlet sentimentScore = 0;\nlet sentimentLevel = 'NEUTRAL';\nlet detectedPhrases = [];\n\n// Check negative phrases\nfor (const [level, phrases] of Object.entries(negativePhrases)) {\n  for (const phrase of phrases) {\n    if (text.includes(phrase)) {\n      const weight = level === 'critical' ? -10 : level === 'severe' ? -7 : level === 'moderate' ? -4 : -2;\n      sentimentScore += weight;\n      detectedPhrases.push({ phrase, sentiment: 'negative', level });\n    }\n  }\n}\n\n// Check positive phrases\nfor (const [level, phrases] of Object.entries(positivePhrases)) {\n  for (const phrase of phrases) {\n    if (text.includes(phrase)) {\n      const weight = level === 'strong' ? 8 : level === 'moderate' ? 5 : 2;\n      sentimentScore += weight;\n      detectedPhrases.push({ phrase, sentiment: 'positive', level });\n    }\n  }\n}\n\n// Amplification factors\nlet amplificationScore = 0;\n\n// High engagement amplifies impact\nif (mention.engagement > 1000) amplificationScore += 30;\nelse if (mention.engagement > 500) amplificationScore += 20;\nelse if (mention.engagement > 100) amplificationScore += 10;\nelse if (mention.engagement > 10) amplificationScore += 5;\n\n// Verified/influential accounts amplify impact\nif (mention.isVerified) amplificationScore += 15;\nif (mention.authorFollowers > 100000) amplificationScore += 25;\nelse if (mention.authorFollowers > 10000) amplificationScore += 15;\nelse if (mention.authorFollowers > 1000) amplificationScore += 5;\n\n// News platforms have high credibility\nif (mention.platform === 'news') amplificationScore += 40;\n\n// Determine sentiment level\nif (sentimentScore <= -20) {\n  sentimentLevel = 'VERY_NEGATIVE';\n} else if (sentimentScore <= -10) {\n  sentimentLevel = 'NEGATIVE';\n} else if (sentimentScore <= -3) {\n  sentimentLevel = 'SLIGHTLY_NEGATIVE';\n} else if (sentimentScore >= 15) {\n  sentimentLevel = 'VERY_POSITIVE';\n} else if (sentimentScore >= 8) {\n  sentimentLevel = 'POSITIVE';\n} else if (sentimentScore >= 3) {\n  sentimentLevel = 'SLIGHTLY_POSITIVE';\n} else {\n  sentimentLevel = 'NEUTRAL';\n}\n\n// Calculate total impact score (sentiment + amplification)\nconst impactScore = Math.abs(sentimentScore) + amplificationScore;\n\n// Determine if this is crisis-worthy\nlet crisisLevel = 'NONE';\nlet requiresCrisisResponse = false;\n\nif (sentimentScore <= -15 && impactScore >= 50) {\n  crisisLevel = 'CRITICAL';\n  requiresCrisisResponse = true;\n} else if (sentimentScore <= -10 && impactScore >= 35) {\n  crisisLevel = 'HIGH';\n  requiresCrisisResponse = true;\n} else if (sentimentScore <= -5 && impactScore >= 20) {\n  crisisLevel = 'MEDIUM';\n  requiresCrisisResponse = true;\n} else if (sentimentScore <= -3 && impactScore >= 10) {\n  crisisLevel = 'LOW';\n  requiresCrisisResponse = false;\n}\n\nreturn {\n  json: {\n    ...mention,\n    sentimentScore,\n    sentimentLevel,\n    amplificationScore,\n    impactScore,\n    detectedPhrases,\n    crisisLevel,\n    requiresCrisisResponse,\n    analysisComplete: true\n  }\n};"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "2984eae8-2455-48d5-9c81-f439007d7b1c",
      "name": "Calculate Trend Baseline",
      "type": "n8n-nodes-base.code",
      "notes": "Compares current sentiment to historical baseline",
      "position": [
        2112,
        176
      ],
      "parameters": {
        "jsCode": "// Calculate sentiment trends and detect sharp drops\nconst mentions = $input.all().map(item => item.json);\n\n// Get historical sentiment data\nconst historicalData = $getWorkflowStaticData('global').sentimentHistory || [];\n\n// Calculate current batch metrics\nconst negativeMentions = mentions.filter(m => m.sentimentScore < 0);\nconst positiveMentions = mentions.filter(m => m.sentimentScore > 0);\nconst neutralMentions = mentions.filter(m => m.sentimentScore === 0);\n\nconst avgSentiment = mentions.reduce((sum, m) => sum + m.sentimentScore, 0) / mentions.length || 0;\nconst avgImpact = mentions.reduce((sum, m) => sum + m.impactScore, 0) / mentions.length || 0;\nconst negativeRatio = negativeMentions.length / mentions.length || 0;\n\nconst currentMetrics = {\n  timestamp: new Date().toISOString(),\n  totalMentions: mentions.length,\n  avgSentiment,\n  avgImpact,\n  negativeRatio,\n  negativeMentions: negativeMentions.length,\n  positiveMentions: positiveMentions.length,\n  neutralMentions: neutralMentions.length\n};\n\n// Add to historical data\nhistoricalData.push(currentMetrics);\n\n// Keep only last 72 hours of data (assuming 10-min intervals = 6 per hour)\nconst maxDataPoints = 72 * 6; // 432 data points\nif (historicalData.length > maxDataPoints) {\n  historicalData.shift();\n}\n\n// Calculate baseline (average of last 24 hours)\nconst last24Hours = historicalData.slice(-144); // 24 hours * 6 intervals\nconst baseline = {\n  avgSentiment: last24Hours.reduce((sum, d) => sum + d.avgSentiment, 0) / last24Hours.length || 0,\n  avgImpact: last24Hours.reduce((sum, d) => sum + d.avgImpact, 0) / last24Hours.length || 0,\n  negativeRatio: last24Hours.reduce((sum, d) => sum + d.negativeRatio, 0) / last24Hours.length || 0\n};\n\n// Detect sharp drops\nconst sentimentDrop = baseline.avgSentiment - currentMetrics.avgSentiment;\nconst impactIncrease = currentMetrics.avgImpact - baseline.avgImpact;\nconst negativeRatioIncrease = currentMetrics.negativeRatio - baseline.negativeRatio;\n\nlet trendAlert = 'NORMAL';\nlet trendSeverity = 0;\nlet trendIndicators = [];\n\n// Critical trend: massive sentiment drop\nif (sentimentDrop > 15) {\n  trendSeverity = 100;\n  trendAlert = 'CRISIS';\n  trendIndicators.push(`\ud83d\udd34 Sentiment dropped by ${sentimentDrop.toFixed(1)} points`);\n}\n// High alert: significant sentiment drop\nelse if (sentimentDrop > 10) {\n  trendSeverity = 75;\n  trendAlert = 'HIGH_ALERT';\n  trendIndicators.push(`\ud83d\udfe0 Sentiment dropped by ${sentimentDrop.toFixed(1)} points`);\n}\n// Medium alert: moderate sentiment drop\nelse if (sentimentDrop > 5) {\n  trendSeverity = 50;\n  trendAlert = 'MEDIUM_ALERT';\n  trendIndicators.push(`\ud83d\udfe1 Sentiment dropped by ${sentimentDrop.toFixed(1)} points`);\n}\n\n// Check negative ratio spike\nif (negativeRatioIncrease > 0.3) {\n  trendSeverity = Math.max(trendSeverity, 75);\n  trendAlert = trendAlert === 'NORMAL' ? 'HIGH_ALERT' : trendAlert;\n  trendIndicators.push(`\ud83d\udfe0 Negative mentions spiked by ${(negativeRatioIncrease * 100).toFixed(1)}%`);\n} else if (negativeRatioIncrease > 0.15) {\n  trendSeverity = Math.max(trendSeverity, 50);\n  trendAlert = trendAlert === 'NORMAL' ? 'MEDIUM_ALERT' : trendAlert;\n  trendIndicators.push(`\ud83d\udfe1 Negative mentions increased by ${(negativeRatioIncrease * 100).toFixed(1)}%`);\n}\n\n// Check impact surge\nif (impactIncrease > 20) {\n  trendSeverity = Math.max(trendSeverity, 65);\n  trendIndicators.push(`\u26a1 Impact score surged by ${impactIncrease.toFixed(1)} points`);\n}\n\n// Save updated historical data\n$getWorkflowStaticData('global').sentimentHistory = historicalData;\n\n// Return enriched mentions with trend context\nreturn mentions.map(mention => ({\n  json: {\n    ...mention,\n    trendMetrics: currentMetrics,\n    baseline,\n    trendAlert,\n    trendSeverity,\n    trendIndicators,\n    sentimentDrop,\n    negativeRatioIncrease\n  }\n}));"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "34f454c5-a87a-4144-b4af-daee4f3af656",
      "name": "Filter Crisis Triggers",
      "type": "n8n-nodes-base.switch",
      "notes": "Routes based on crisis severity",
      "position": [
        2336,
        176
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "",
                    "rightValue": ""
                  }
                ]
              }
            }
          ]
        },
        "options": {}
      },
      "notesInFlow": true,
      "typeVersion": 3.1
    },
    {
      "id": "0b730149-0ecf-49d9-991d-20350abae57b",
      "name": "Aggregate Crisis Data",
      "type": "n8n-nodes-base.code",
      "notes": "Combines multiple crisis mentions into single alert",
      "position": [
        2560,
        176
      ],
      "parameters": {
        "jsCode": "// Aggregate all crisis-level mentions\nconst crisisMentions = $input.all().map(item => item.json);\n\n// Sort by impact score\ncrisisMentions.sort((a, b) => b.impactScore - a.impactScore);\n\n// Calculate aggregate metrics\nconst topMentions = crisisMentions.slice(0, 5); // Top 5 most impactful\nconst platforms = [...new Set(crisisMentions.map(m => m.platform))];\nconst totalEngagement = crisisMentions.reduce((sum, m) => sum + m.engagement, 0);\nconst avgSentiment = crisisMentions.reduce((sum, m) => sum + m.sentimentScore, 0) / crisisMentions.length;\nconst avgImpact = crisisMentions.reduce((sum, m) => sum + m.impactScore, 0) / crisisMentions.length;\n\n// Determine overall crisis severity\nlet overallSeverity = 'MEDIUM';\nif (avgImpact >= 60 || crisisMentions.length >= 10) {\n  overallSeverity = 'CRITICAL';\n} else if (avgImpact >= 40 || crisisMentions.length >= 5) {\n  overallSeverity = 'HIGH';\n}\n\n// Extract common themes\nconst allPhrases = crisisMentions.flatMap(m => m.detectedPhrases || []);\nconst phraseFrequency = {};\nallPhrases.forEach(p => {\n  const key = p.phrase;\n  phraseFrequency[key] = (phraseFrequency[key] || 0) + 1;\n});\n\nconst topThemes = Object.entries(phraseFrequency)\n  .sort((a, b) => b[1] - a[1])\n  .slice(0, 5)\n  .map(([phrase, count]) => ({ phrase, count }));\n\nconst crisisData = {\n  crisisId: `CRISIS-${Date.now()}`,\n  timestamp: new Date().toISOString(),\n  severity: overallSeverity,\n  totalMentions: crisisMentions.length,\n  platforms,\n  totalEngagement,\n  avgSentiment: avgSentiment.toFixed(2),\n  avgImpact: avgImpact.toFixed(2),\n  topMentions: topMentions.map(m => ({\n    platform: m.platform,\n    text: m.text.substring(0, 150) + '...',\n    author: m.author,\n    url: m.url,\n    sentiment: m.sentimentLevel,\n    impact: m.impactScore\n  })),\n  topThemes,\n  trendIndicators: crisisMentions[0]?.trendIndicators || [],\n  sentimentDrop: crisisMentions[0]?.sentimentDrop || 0,\n  allMentions: crisisMentions\n};\n\nreturn [{ json: crisisData }];"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "ae7de7b6-8e00-45b5-a9be-8404f836981a",
      "name": "Generate Crisis Brief",
      "type": "n8n-nodes-base.code",
      "notes": "Creates executive crisis brief and response plan",
      "position": [
        2784,
        176
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Generate comprehensive crisis brief\nconst crisis = $input.item.json;\nconst timestamp = new Date(crisis.timestamp).toLocaleString();\n\nconst brief = `\ud83d\udea8 BRAND REPUTATION CRISIS ALERT \ud83d\udea8\n\nCrisis ID: ${crisis.crisisId}\nSeverity: ${crisis.severity}\nDetected: ${timestamp}\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\ud83d\udcca CRISIS METRICS\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\n\u2022 Total Mentions: ${crisis.totalMentions}\n\u2022 Affected Platforms: ${crisis.platforms.join(', ')}\n\u2022 Total Engagement: ${crisis.totalEngagement.toLocaleString()}\n\u2022 Avg Sentiment Score: ${crisis.avgSentiment} (baseline comparison)\n\u2022 Avg Impact Score: ${crisis.avgImpact}\n${crisis.sentimentDrop > 0 ? `\u2022 Sentiment Drop: -${crisis.sentimentDrop.toFixed(1)} points` : ''}\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\u26a0\ufe0f KEY ISSUES DETECTED\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\n${crisis.topThemes.map((theme, i) => `${i + 1}. \"${theme.phrase}\" - mentioned ${theme.count}x`).join('\\n')}\n\n${crisis.trendIndicators.length > 0 ? `\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\ud83d\udcc8 TREND ALERTS\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\n${crisis.trendIndicators.map((ind, i) => `${i + 1}. ${ind}`).join('\\n')}\n` : ''}\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\ud83d\udd25 TOP IMPACTFUL MENTIONS\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\n${crisis.topMentions.map((m, i) => `${i + 1}. [${m.platform.toUpperCase()}] @${m.author} (Impact: ${m.impact})\n   \"${m.text}\"\n   \ud83d\udd17 ${m.url}\n`).join('\\n')}\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\ud83c\udfaf RECOMMENDED IMMEDIATE ACTIONS\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\n${crisis.severity === 'CRITICAL' ? `\n\u26a1 CRITICAL RESPONSE REQUIRED:\n\n1. \ud83d\udea8 Convene crisis management team IMMEDIATELY\n2. \ud83d\udce2 Prepare holding statement within 1 hour\n3. \ud83d\udd0d Investigate root cause with urgency\n4. \ud83d\udcf1 Monitor all social channels continuously\n5. \ud83e\udd1d Reach out to top influencers/affected parties\n6. \ud83d\udce7 Notify executive leadership and PR team\n7. \ud83d\udee1\ufe0f Activate social media response protocols\n8. \ud83d\udcca Set up real-time sentiment monitoring dashboard\n` : crisis.severity === 'HIGH' ? `\n\u26a0\ufe0f HIGH PRIORITY RESPONSE:\n\n1. \ud83d\udd14 Alert crisis management team\n2. \ud83d\udd0d Investigate issue and gather facts\n3. \ud83d\udcdd Draft response statement (4-6 hour window)\n4. \ud83d\udcf1 Increase social monitoring frequency\n5. \ud83d\udc65 Identify and engage with key voices\n6. \ud83d\udce7 Brief PR and customer service teams\n7. \ud83d\udcca Track sentiment evolution hourly\n` : `\n\ud83d\udccb STANDARD RESPONSE:\n\n1. \ud83d\udcca Continue monitoring situation\n2. \ud83d\udd0d Investigate mentioned issues\n3. \ud83d\udcdd Prepare response if trend continues\n4. \ud83d\udc65 Engage with concerned customers\n5. \ud83d\udce7 Brief relevant teams\n`}\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\ud83d\udccb CRISIS RESPONSE CHECKLIST\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\n\u2610 Situation assessment completed\n\u2610 Crisis team assembled\n\u2610 Root cause identified\n\u2610 Response strategy approved\n\u2610 Statement drafted and reviewed\n\u2610 Stakeholders notified\n\u2610 Response published\n\u2610 Monitoring intensified\n\u2610 Follow-up plan created\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\nGenerated by AI Brand Reputation Crisis Detector\nThis is an automated alert - human review required`;\n\nconst slackMessage = {\n  channel: '#crisis-management',\n  text: `\ud83d\udea8 *${crisis.severity} BRAND REPUTATION CRISIS DETECTED* \ud83d\udea8`,\n  attachments: [\n    {\n      color: crisis.severity === 'CRITICAL' ? 'danger' : 'warning',\n      title: `Crisis ID: ${crisis.crisisId}`,\n      text: `${crisis.totalMentions} negative mentions detected across ${crisis.platforms.join(', ')}`,\n      fields: [\n        {\n          title: 'Severity',\n          value: crisis.severity,\n          short: true\n        },\n        {\n          title: 'Total Engagement',\n          value: crisis.totalEngagement.toLocaleString(),\n          short: true\n        },\n        {\n          title: 'Avg Sentiment',\n          value: crisis.avgSentiment,\n          short: true\n        },\n        {\n          title: 'Avg Impact',\n          value: crisis.avgImpact,\n          short: true\n        }\n      ],\n      actions: [\n        {\n          type: 'button',\n          text: '\ud83d\udea8 Activate Crisis Response',\n          url: 'https://your-crisis-dashboard.com'\n        },\n        {\n          type: 'button',\n          text: '\ud83d\udcca View Dashboard',\n          url: 'https://your-analytics-dashboard.com'\n        }\n      ]\n    }\n  ]\n};\n\nreturn {\n  json: {\n    ...crisis,\n    brief,\n    slackMessage,\n    emailSubject: `\ud83d\udea8 ${crisis.severity} BRAND CRISIS - Immediate Action Required`,\n    emailBody: brief\n  }\n};"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "cd1985eb-468f-4701-94d1-20acaf59ae0c",
      "name": "Alert Crisis Team - Slack",
      "type": "n8n-nodes-base.slack",
      "notes": "Immediately notifies crisis management team",
      "position": [
        3008,
        176
      ],
      "parameters": {
        "resource": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        }
      },
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      },
      "notesInFlow": true,
      "typeVersion": 2.1
    },
    {
      "id": "39c90e61-31f6-4243-ac61-b28170501145",
      "name": "Alert Crisis Team - Email",
      "type": "n8n-nodes-base.emailSend",
      "notes": "Sends detailed crisis brief to leadership",
      "position": [
        3232,
        176
      ],
      "parameters": {
        "options": {
          "ccEmail": "user@example.com, user@example.com"
        },
        "subject": "={{ $json.emailSubject }}",
        "toEmail": "user@example.com, user@example.com, user@example.com",
        "fromEmail": "user@example.com"
      },
      "credentials": {
        "smtp": {
          "name": "<your credential>"
        }
      },
      "notesInFlow": true,
      "typeVersion": 2.1
    },
    {
      "id": "de278e52-4482-4df8-a007-b1ecf4f9174a",
      "name": "Create JIRA Crisis Ticket",
      "type": "n8n-nodes-base.jira",
      "notes": "Creates high-priority ticket for crisis tracking",
      "position": [
        3456,
        176
      ],
      "parameters": {
        "project": {
          "__rl": true,
          "mode": "id",
          "value": "=",
          "__regex": "^([0-9]{2,})"
        },
        "summary": "={{ $json.emailSubject }}",
        "issueType": "Bug",
        "additionalFields": {
          "labels": "crisis,reputation,urgent",
          "priority": "Highest"
        }
      },
      "credentials": {
        "jiraSoftwareCloudApi": {
          "name": "<your credential>"
        }
      },
      "notesInFlow": true,
      "typeVersion": 1
    },
    {
      "id": "91ccc0aa-461c-4c87-acd8-a01a69d621ef",
      "name": "Log Crisis Event",
      "type": "n8n-nodes-base.code",
      "notes": "Records crisis in database for analysis",
      "position": [
        3680,
        176
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Log crisis event to workflow storage\nconst crisis = $input.item.json;\n\nconst crisisEvent = {\n  crisisId: crisis.crisisId,\n  timestamp: crisis.timestamp,\n  severity: crisis.severity,\n  totalMentions: crisis.totalMentions,\n  platforms: crisis.platforms,\n  totalEngagement: crisis.totalEngagement,\n  avgSentiment: parseFloat(crisis.avgSentiment),\n  avgImpact: parseFloat(crisis.avgImpact),\n  topThemes: crisis.topThemes,\n  responseInitiated: true,\n  resolved: false\n};\n\nconsole.log('\ud83d\udea8 CRISIS EVENT LOGGED:');\nconsole.log(JSON.stringify(crisisEvent, null, 2));\n\n// Store in workflow static data\nconst crisisLog = $getWorkflowStaticData('global').crisisLog || [];\ncrisisLog.push(crisisEvent);\n\n// Keep only last 50 crises\nif (crisisLog.length > 50) {\n  crisisLog.shift();\n}\n\n$getWorkflowStaticData('global').crisisLog = crisisLog;\n\nreturn {\n  json: {\n    success: true,\n    crisisEvent,\n    totalCrisesLogged: crisisLog.length,\n    message: `Crisis ${crisisEvent.crisisId} logged and response initiated`\n  }\n};"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "e2fc634b-0864-4cee-8d61-d9834b5a8067",
      "name": "Log Routine Monitoring",
      "type": "n8n-nodes-base.code",
      "notes": "Records non-crisis mentions for trend analysis",
      "position": [
        3904,
        176
      ],
      "parameters": {
        "jsCode": "// Log routine monitoring data\nconst mentions = $input.all().map(item => item.json);\n\nconst summary = {\n  timestamp: new Date().toISOString(),\n  totalMentions: mentions.length,\n  avgSentiment: mentions.reduce((sum, m) => sum + m.sentimentScore, 0) / mentions.length || 0,\n  positive: mentions.filter(m => m.sentimentScore > 0).length,\n  neutral: mentions.filter(m => m.sentimentScore === 0).length,\n  negative: mentions.filter(m => m.sentimentScore < 0).length,\n  platforms: [...new Set(mentions.map(m => m.platform))]\n};\n\nconsole.log('\ud83d\udcca ROUTINE MONITORING:');\nconsole.log(JSON.stringify(summary, null, 2));\n\n// Store summary\nconst monitoringLog = $getWorkflowStaticData('global').monitoringLog || [];\nmonitoringLog.push(summary);\n\n// Keep only last 1000 summaries\nif (monitoringLog.length > 1000) {\n  monitoringLog.shift();\n}\n\n$getWorkflowStaticData('global').monitoringLog = monitoringLog;\n\nreturn [{\n  json: {\n    success: true,\n    summary,\n    message: 'Routine monitoring logged'\n  }\n}];"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "dbf1757c-4212-48c0-80bb-04924c30aae8",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -720,
        -496
      ],
      "parameters": {
        "width": 636,
        "height": 1288,
        "content": "## AI Brand Reputation Crisis Detector\n\nThis workflow monitors brand mentions across multiple platforms (Twitter/X, Reddit, News) and automatically detects reputation crises based on sentiment analysis and trend detection.\n\n## How it works\n\n1. **Multi-platform monitoring**: Every 10 minutes, scans Twitter/X, Reddit, and news sites for brand mentions\n2. **Data normalization**: Converts all platform data into unified format\n3. **Smart filtering**: Removes duplicates and already-analyzed mentions\n4. **AI sentiment analysis**: Analyzes each mention for:\n   - Sentiment score (positive/negative/neutral)\n   - Amplification factors (engagement, verified accounts, news sources)\n   - Crisis-level phrases and keywords\n5. **Trend detection**: Compares current sentiment to 24-hour baseline:\n   - Detects sharp sentiment drops\n   - Identifies negative mention spikes\n   - Calculates impact surge\n6. **Crisis classification**: Assigns severity (CRITICAL/HIGH/MEDIUM/LOW)\n7. **Automated response**: For crises, triggers immediate alerts:\n   - Executive crisis brief with action plan\n   - Slack alerts to crisis team\n   - Email to leadership and PR team\n   - JIRA ticket creation\n   - Crisis event logging\n\n## Setup steps\n\n1. **Connect platforms**:\n   - Twitter/X: Add OAuth credentials to \"Monitor Twitter/X\" node\n   - Reddit: Add OAuth credentials to \"Monitor Reddit\" node\n   - News API: Get API key from newsapi.org and add to \"Monitor News & Blogs\" node\n\n2. **Configure brand monitoring**:\n   - Update brand name and handles in search queries\n   - Add additional platforms if needed (LinkedIn, Facebook, Instagram)\n\n3. **Set up alerting**:\n   - Slack: Add credentials and update channel names\n   - Email: Add SMTP settings and recipient lists\n   - JIRA: Add credentials and project ID\n\n4. **Adjust sensitivity**:\n   - Modify sentiment keyword dictionaries in \"AI Sentiment Analysis Engine\"\n   - Adjust crisis threshold scores\n   - Customize amplification factors\n\n5. **Test thoroughly**:\n   - Run manual execution with test data\n   - Verify alert routing and content\n   - Test false positive handling\n\n6. **Activate**: Enable for continuous 24/7 monitoring\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "7e3ee568-5e52-49e2-b819-8ffc42eadda3",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        48,
        -128
      ],
      "parameters": {
        "color": 6,
        "width": 640,
        "height": 672,
        "content": "## \ud83d\udce1 Multi-Platform Monitoring"
      },
      "typeVersion": 1
    },
    {
      "id": "6f9bfe0e-9664-47b7-b30b-9eeed4c84492",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        720,
        16
      ],
      "parameters": {
        "color": 4,
        "width": 1088,
        "height": 320,
        "content": "## \ud83d\udd04 Data Normalization & Deduplication"
      },
      "typeVersion": 1
    },
    {
      "id": "730e6388-d6a5-452f-8342-72de4d325953",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1816,
        0
      ],
      "parameters": {
        "color": 6,
        "width": 688,
        "height": 336,
        "content": "## \ud83e\udd16 AI Sentiment Analysis & Trend Detection"
      },
      "typeVersion": 1
    },
    {
      "id": "b614b8ce-f893-4a30-a739-a9c18798d793",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2520,
        -32
      ],
      "parameters": {
        "color": 4,
        "width": 1296,
        "height": 368,
        "content": "## \ud83d\udea8 Crisis Response Activation"
      },
      "typeVersion": 1
    },
    {
      "id": "11931922-1856-4481-8160-c2eda2d92e28",
      "name": "Sticky Note8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3840,
        -16
      ],
      "parameters": {
        "color": 6,
        "width": 304,
        "height": 352,
        "content": "## \ud83d\udcca Routine Logging"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "675eb895-dfbd-4574-82d3-529d8220d1c9",
  "connections": {
    "Monitor Reddit": {
      "main": [
        [
          {
            "node": "Normalize Data Format",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "API Rate Limiter": {
      "main": [
        [
          {
            "node": "Only New Mentions",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Every 10 Minutes": {
      "main": [
        [
          {
            "node": "Monitor Twitter/X",
            "type": "main",
            "index": 0
          },
          {
            "node": "Monitor Reddit",
            "type": "main",
            "index": 0
          },
          {
            "node": "Monitor News & Blogs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log Crisis Event": {
      "main": [
        [
          {
            "node": "Log Routine Monitoring",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Monitor Twitter/X": {
      "main": [
        [
          {
            "node": "Normalize Data Format",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Only New Mentions": {
      "main": [
        [
          {
            "node": "AI Sentiment Analysis Engine",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Remove Duplicates": {
      "main": [
        [
          {
            "node": "Merge Platform Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge Platform Data": {
      "main": [
        [
          {
            "node": "Track Analyzed Mentions",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Monitor News & Blogs": {
      "main": [
        [
          {
            "node": "Normalize Data Format",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Aggregate Crisis Data": {
      "main": [
        [
          {
            "node": "Generate Crisis Brief",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Crisis Brief": {
      "main": [
        [
          {
            "node": "Alert Crisis Team - Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Data Format": {
      "main": [
        [
          {
            "node": "Remove Duplicates",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter Crisis Triggers": {
      "main": [
        [
          {
            "node": "Aggregate Crisis Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Track Analyzed Mentions": {
      "main": [
        [
          {
            "node": "API Rate Limiter",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Calculate Trend Baseline": {
      "main": [
        [
          {
            "node": "Filter Crisis Triggers",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Alert Crisis Team - Email": {
      "main": [
        [
          {
            "node": "Create JIRA Crisis Ticket",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Alert Crisis Team - Slack": {
      "main": [
        [
          {
            "node": "Alert Crisis Team - Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create JIRA Crisis Ticket": {
      "main": [
        [
          {
            "node": "Log Crisis Event",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Sentiment Analysis Engine": {
      "main": [
        [
          {
            "node": "Calculate Trend Baseline",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}