{
  "id": "JZ8C3IFRtHrntshw",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Error Alert Aggregator \u2013 Email and Jira",
  "tags": [],
  "nodes": [
    {
      "id": "bd7d01ff-0a95-4103-acca-15e3b4730abc",
      "name": "Hourly Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -48,
        320
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "4933f19d-19ae-4954-af44-6f7530c3b989",
      "name": "Fetch Raw Logs",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        144,
        320
      ],
      "parameters": {
        "url": "https://example.com/api/logs",
        "options": {},
        "authentication": "genericCredentialType"
      },
      "typeVersion": 4
    },
    {
      "id": "16b27462-2737-4e6d-8975-1cdb72e977e9",
      "name": "Has Logs?",
      "type": "n8n-nodes-base.if",
      "position": [
        352,
        320
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "number": [
            {
              "value1": "={{ Array.isArray($json.logs) ? $json.logs.length : 0 }}",
              "value2": 0,
              "operation": "larger"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "dab45cea-73ba-46a7-8914-a91421437c87",
      "name": "Parse & Flatten Logs",
      "type": "n8n-nodes-base.code",
      "position": [
        544,
        320
      ],
      "parameters": {
        "jsCode": "// Flatten the incoming log payload\nconst logs = items[0].json.logs || [];\nreturn logs.map(l => ({ json: l }));"
      },
      "typeVersion": 2
    },
    {
      "id": "59332f01-639f-43ff-b94c-6d547d4f3788",
      "name": "Batch Logs",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        752,
        320
      ],
      "parameters": {
        "options": {},
        "batchSize": 20
      },
      "typeVersion": 3
    },
    {
      "id": "78737363-ca76-4f32-a07d-835b9a62f8ce",
      "name": "Deduplicate Batch",
      "type": "n8n-nodes-base.code",
      "position": [
        944,
        320
      ],
      "parameters": {
        "jsCode": "// Basic in-batch deduplication\nconst seen = new Set();\nreturn items.filter(item => {\n  const key = `${item.json.id || ''}-${item.json.message}-${item.json.timestamp}`;\n  if (seen.has(key)) return false;\n  seen.add(key);\n  item.json.dedupeKey = key;\n  return true;\n});"
      },
      "typeVersion": 2
    },
    {
      "id": "0a19aa04-4a7d-452b-938f-13f43c5edf9d",
      "name": "Any New Errors?",
      "type": "n8n-nodes-base.if",
      "position": [
        1152,
        320
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "boolean": [
            {
              "value1": "={{ Object.keys($json).length > 0 }}",
              "operation": "isTrue"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "66df7074-8c01-4848-96da-e52b63163798",
      "name": "Assess Severity",
      "type": "n8n-nodes-base.code",
      "position": [
        1344,
        320
      ],
      "parameters": {
        "jsCode": "// Add a severity flag\nconst crit = /critical|fatal|panic/i.test($json.level || $json.message);\nreturn [{ json: { ...$json, severity: crit ? 'critical' : 'normal' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "73bc91dc-dd2e-4a75-aa09-0d4f8e20880e",
      "name": "Critical Errors?",
      "type": "n8n-nodes-base.if",
      "position": [
        1552,
        320
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "string": [
            {
              "value1": "={{ $json.severity }}",
              "value2": "critical",
              "operation": "equals"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "692ca2f0-67d5-4f3c-b7a5-5508453d1b69",
      "name": "Critical Alert Email",
      "type": "n8n-nodes-base.emailSend",
      "position": [
        1744,
        224
      ],
      "parameters": {
        "options": {},
        "subject": "Critical Error Alert \u2013 {{ $json.message }}",
        "toEmail": "user@example.com",
        "fromEmail": "user@example.com"
      },
      "typeVersion": 2
    },
    {
      "id": "6b0ced6c-9774-4061-bb19-c23b6694ff0e",
      "name": "Prepare Jira Issue",
      "type": "n8n-nodes-base.code",
      "position": [
        1744,
        432
      ],
      "parameters": {
        "jsCode": "// Build minimal issue payload\nreturn [{\n  json: {\n    projectKey: 'PROJ',\n    summary: `[${$json.severity.toUpperCase()}] ${($json.message || '').slice(0, 80)}`,\n    description: `Error details (auto-generated):\\n\\n${JSON.stringify($json, null, 2)}`\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "bc38ddcd-acec-4b72-a58e-5b384ff3861d",
      "name": "Rate Limit Wait",
      "type": "n8n-nodes-base.wait",
      "position": [
        1952,
        432
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "4e4fdca4-c527-4485-82dc-b98f67461731",
      "name": "Create Jira Issue",
      "type": "n8n-nodes-base.jira",
      "position": [
        2144,
        432
      ],
      "parameters": {},
      "credentials": {},
      "typeVersion": 3
    },
    {
      "id": "cb731cbb-69b6-466e-b14e-09e72d31f9e9",
      "name": "Collect Issue Keys",
      "type": "n8n-nodes-base.merge",
      "position": [
        2352,
        320
      ],
      "parameters": {},
      "typeVersion": 2
    },
    {
      "id": "d9a8a48d-faa1-4d5b-ac02-c8f284642dc9",
      "name": "Generate Summary",
      "type": "n8n-nodes-base.code",
      "position": [
        2544,
        320
      ],
      "parameters": {
        "jsCode": "// Build aggregated stats for summary email\nconst all = items.map(i => i.json);\nconst total = all.length;\nconst critical = all.filter(i => /critical|fatal|panic/i.test(i.summary)).length;\nreturn [{ json: { total, critical, issues: all, timestamp: new Date().toISOString() } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "f3dae16a-2b8f-427c-a3ff-7019b4b1d0b6",
      "name": "Format Summary Email",
      "type": "n8n-nodes-base.set",
      "position": [
        2752,
        320
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "f0146d34-e922-41cf-9abf-6c0beb2edf81",
      "name": "Daily Summary Email",
      "type": "n8n-nodes-base.emailSend",
      "position": [
        2944,
        320
      ],
      "parameters": {
        "options": {},
        "subject": "{{ $json.subject }}",
        "toEmail": "user@example.com",
        "fromEmail": "user@example.com"
      },
      "typeVersion": 2
    },
    {
      "id": "6324f7bd-1b39-4d93-b253-d01f3cb3cf40",
      "name": "Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -960,
        -48
      ],
      "parameters": {
        "width": 550,
        "height": 754,
        "content": "# Error Alert Aggregator\n\n## How it works\nThe workflow polls your log source every hour, retrieves fresh error events and converts them into individual items. Each batch is normalised, deduplicated and assessed for severity. Critical errors trigger an instant email to the on-call team while every unique error is transformed into a Jira ticket for proper tracking. Finally, a concise digest summarises the run and lands in your inbox so your team always knows what happened.\n\n## Setup steps\n1. Create HTTP, Jira and SMTP credentials in n8n.\n2. Replace the placeholder log API URL in **Fetch Raw Logs**.\n3. Adjust batch size or deduplication logic as needed.\n4. Update the Jira project key and issue type in **Prepare Jira Issue**.\n5. Enter recipients in both Email nodes.\n6. Activate the workflow and verify with test data.\n7. Fine-tune severity rules or scheduling to match your environment."
      },
      "typeVersion": 1
    },
    {
      "id": "89d647da-dcf0-463f-9355-ccb677a9d4cd",
      "name": "Section \u2013 Fetch",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -112,
        96
      ],
      "parameters": {
        "color": 7,
        "width": 834,
        "height": 574,
        "content": "## Trigger & Data Fetch\nThis group starts the automation on a fixed hourly schedule and pulls raw log data from your monitoring or logging platform. The Schedule Trigger guarantees a predictable cadence, while the HTTP Request node can be pointed at any JSON-based endpoint (REST API, AWS Gateway, ELK, etc.). The first IF node quickly exits the pipeline if the payload is empty, avoiding unnecessary processing and email noise. Make sure to secure the HTTP credentials and adjust polling frequency to respect rate limits."
      },
      "typeVersion": 1
    },
    {
      "id": "281dca7e-7d24-4d14-bf5b-b1428e2cd131",
      "name": "Section \u2013 Process",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        720,
        96
      ],
      "parameters": {
        "color": 7,
        "width": 914,
        "height": 558,
        "content": "## Processing & Deduplication\nAfter retrieval, the logs are flattened into individual items, batched in groups of 20 and run through an in-memory deduplication routine. This reduces noise when identical errors repeat. The subsequent logic node determines whether any unique errors remain. If yes, each record is tagged with a severity flag based on keywords. You can extend this code to incorporate numeric levels or external severity look-ups. Everything beyond this point assumes each item is a unique, actionable error."
      },
      "typeVersion": 1
    },
    {
      "id": "0e950580-7f33-4ab0-b663-0dbbcf43b324",
      "name": "Section \u2013 Notify & Store",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1632,
        96
      ],
      "parameters": {
        "color": 7,
        "width": 1474,
        "height": 558,
        "content": "## Notification & Storage\nCritical events trigger an immediate alert email so your on-call engineers respond without delay. Regardless of severity, each error is turned into a Jira issue, rate-limited by a brief wait node to avoid API abuse. All created issues flow into a Merge node that feeds a summary builder. The final set and email nodes craft a human-readable digest containing counts, critical breakdown and newly minted Jira keys\u2014perfect for daily reporting or ChatOps ingestion."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "172bf323-863b-45f5-bf41-1dc7c186039c",
  "connections": {
    "Has Logs?": {
      "main": [
        [
          {
            "node": "Parse & Flatten Logs",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Generate Summary",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Batch Logs": {
      "main": [
        [
          {
            "node": "Deduplicate Batch",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Raw Logs": {
      "main": [
        [
          {
            "node": "Has Logs?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Hourly Trigger": {
      "main": [
        [
          {
            "node": "Fetch Raw Logs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Any New Errors?": {
      "main": [
        [
          {
            "node": "Assess Severity",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Generate Summary",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Assess Severity": {
      "main": [
        [
          {
            "node": "Critical Errors?",
            "type": "main",
            "index": 0
          },
          {
            "node": "Prepare Jira Issue",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Critical Errors?": {
      "main": [
        [
          {
            "node": "Critical Alert Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Summary": {
      "main": [
        [
          {
            "node": "Format Summary Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Deduplicate Batch": {
      "main": [
        [
          {
            "node": "Any New Errors?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Collect Issue Keys": {
      "main": [
        [
          {
            "node": "Generate Summary",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Jira Issue": {
      "main": [
        [
          {
            "node": "Rate Limit Wait",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Critical Alert Email": {
      "main": [
        [
          {
            "node": "Collect Issue Keys",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Format Summary Email": {
      "main": [
        [
          {
            "node": "Daily Summary Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse & Flatten Logs": {
      "main": [
        [
          {
            "node": "Batch Logs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}