Erstellung von täglichen Jira-Abschlusszusammenfassungen und Wochenberichten mit Azure OpenAI (GPT-4o-mini) und Gmail

Experte

Dies ist ein Automatisierungsworkflow mit 26 Nodes. Hauptsächlich werden Code, Jira, Gmail, GoogleSheets, Agent und andere Nodes verwendet. Generierung von täglichen Jira-Zusammenfassungen und wöchentlichen Berichten mit Azure OpenAI und Gmail

Voraussetzungen
  • Google-Konto + Gmail API-Anmeldedaten
  • Google Sheets API-Anmeldedaten
  • OpenAI API Key

Kategorie

-
Workflow-Vorschau
Visualisierung der Node-Verbindungen, mit Zoom und Pan
Workflow exportieren
Kopieren Sie die folgende JSON-Konfiguration und importieren Sie sie in n8n
{
  "id": "T20oXbS75AjzqlND",
  "meta": {
    "instanceId": "8443f10082278c46aa5cf3acf8ff0f70061a2c58bce76efac814b16290845177",
    "templateCredsSetupCompleted": true
  },
  "name": "Generate EOD Jira Summaries & Weekly Report with Azure OpenAI (GPT-4o-mini) and Gmail",
  "tags": [],
  "nodes": [
    {
      "id": "cf39d6c2-8075-48bd-90e2-f5aabe04235e",
      "name": "Azure OpenAI-Chat-Modell",
      "type": "@n8n/n8n-nodes-langchain.lmChatAzureOpenAi",
      "position": [
        672,
        640
      ],
      "parameters": {
        "model": "gpt-4o-mini",
        "options": {}
      },
      "credentials": {
        "azureOpenAiApi": {
          "id": "C3WzT18XqF8OdVM6",
          "name": "Azure Open AI account"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "bb0d663a-30fd-40dc-affd-b7bedb5d08bf",
      "name": "Azure OpenAI-Chat-Modell1",
      "type": "@n8n/n8n-nodes-langchain.lmChatAzureOpenAi",
      "position": [
        608,
        1600
      ],
      "parameters": {
        "model": "gpt-4o-mini",
        "options": {}
      },
      "credentials": {
        "azureOpenAiApi": {
          "id": "C3WzT18XqF8OdVM6",
          "name": "Azure Open AI account"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "654069da-1c35-4475-8a67-1771a9301892",
      "name": "Structured Output Parser",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        736,
        1600
      ],
      "parameters": {
        "jsonSchemaExample": "{\n    \"output\": \"1) **Weekly Overview**  \\nThis week (Oct 13–17, 2025) saw a **total of 5 items completed**, though a significant **backlog of 32 items remains**, indicating an area for improvement in throughput.\\n\\n2) **Weekly Key Metrics**  \\n- **Total items processed (Mon–Fri):** 50  \\n- **Completed (statusCategory: Done or resolution present):** 5  \\n- **In Progress (status.name: In Progress):** 5  \\n- **Backlog/To Do (statusCategory.key: new or status.name: Backlog/To Do):** 32  \\n- **Bugs vs Tasks (issuetype.name counts):** Bugs: 15, Tasks: 15  \\n- **Top assignees (by count, up to 3):** Jyothi Swarup: 50  \\n- **Priority distribution (by priority.name):** Medium: 50  \\n\\n3) **Day-by-Day Highlights**  \\n- **Monday:**  \\n  - Completed 1 task (SCRUM-1: Fix login API timeout)  \\n  - 5 items in progress (SCRUM-5, SCRUM-2, SCRUM-4, SCRUM-6)  \\n- **Tuesday:**  \\n  - No changes in item status, remained in backlog  \\n- **Wednesday:**  \\n  - No changes, all items unchanged  \\n- **Thursday:**  \\n  - SCRUM-3 and SCRUM-4 remain in the backlog, no new progress  \\n- **Friday:**  \\n  - Status unchanged for remaining items  \\n  - Continued backlog accumulation  \\n\\n4) **Progress & Trends**  \\n- Backlog continues to grow with no items moved to completion since Monday.  \\n- Completion rate stabilizing at around **1 item/day only.**  \\n- Backlog items remain unchanged for most of the week.  \\n- All assignee workload appears **highly concentrated**, indicating possible risk.  \\n\\n5) **Blockers & Risks (Week)**  \\n- **Significant backlog:** Many items (SCRUM-2, SCRUM-3, SCRUM-4, SCRUM-6) remain stagnant.  \\n- No visible resolution timelines for in-progress items (particularly SCRUM-5) may lead to increasing risk of missed deadlines.  \\n\\n6) **Recommendations (Next Week)**  \\n- Prioritize backlog resolution by assigning estimates and deadlines for stalled items.  \\n- Focus and urgency required for SCRUM-5 to ensure progress with a clear resolution timeline.  \\n- Consider redistributing tasks or adding resources to handle workload effectively.  \\n- Schedule daily stand-ups to track progress on backlog items and identify blockers.  \\n- Reassess team capacity to meet outstanding sprint deadlines and customer expectations.  \\n\\n7) **Completed Work (Week)**  \\n- SCRUM-1: Fix login API timeout; resolved on 2025-10-13  \\n\\n8) **Data Snapshot (Appendix)**  \\n- { \\\"issuekey\\\": \\\"SCRUM-1\\\", \\\"summary\\\": \\\"Fix login API timeout\\\", \\\"status.name\\\": \\\"Done\\\", \\\"statusCategory.name\\\": \\\"Done\\\", \\\"resolution.name\\\": \\\"Done\\\", \\\"assignee.displayName\\\": \\\"Jyothi Swarup\\\", \\\"priority.name\\\": \\\"Medium\\\", \\\"created\\\": \\\"2025-10-13T13:08:19.220+0530\\\", \\\"updated\\\": \\\"2025-10-13T16:14:36.945+0530\\\" }  \\n- { \\\"issuekey\\\": \\\"SCRUM-2\\\", \\\"summary\\\": \\\"Resolve crash on profile photo upload\\\", \\\"status.name\\\": \\\"Backlog\\\", \\\"statusCategory.name\\\": \\\"To Do\\\", \\\"resolution.name\\\": null, \\\"assignee.displayName\\\": \\\"Jyothi Swarup\\\", \\\"priority.name\\\": \\\"Medium\\\", \\\"created\\\": \\\"2025-10-13T13:08:20.563+0530\\\", \\\"updated\\\": \\\"2025-10-13T16:14:41.031+0530\\\" }  \\n- { \\\"issuekey\\\": \\\"SCRUM-5\\\", \\\"summary\\\": \\\"Address janky scroll in feed list\\\", \\\"status.name\\\": \\\"In Progress\\\", \\\"statusCategory.name\\\": \\\"In Progress\\\", \\\"resolution.name\\\": null, \\\"assignee.displayName\\\": \\\"Jyothi Swarup\\\", \\\"priority.name\\\": \\\"Medium\\\", \\\"created\\\": \\\"2025-10-13T13:08:29.354+0530\\\", \\\"updated\\\": \\\"2025-10-13T16:14:49.842+0530\\\" }  \"\n  }"
      },
      "typeVersion": 1.3
    },
    {
      "id": "88de2233-3d12-4183-a700-4c40f9c91935",
      "name": "Structured Output Parser1",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        800,
        640
      ],
      "parameters": {
        "jsonSchemaExample": "{\n    \"output\": \"1) EOD Summary  \\n**Today, one item was successfully completed**, reflecting an overall positive outcome and productive effort by the team. Progress was made on several tasks, while a few remained in the backlog.\\n\\n2) Key Metrics (Today)  \\n- Total items processed: 10  \\n- Completed (statusCategory: Done or resolution present): 1  \\n- In Progress (status.name: In Progress): 1  \\n- Backlog/To Do (statusCategory: To Do or status.name: Backlog/To Do): 8  \\n- Bugs vs Tasks (issuetype.name counts): Bugs: 5, Tasks: 5  \\n- Top assignees (by count, up to 3): Jyothi Swarup: 10  \\n- Priority distribution (by priority.name): Medium: 10  \\n\\n3) Notable Updates Today  \\n- SCRUM-1: Done; summary: “Fix login API timeout”; resolutiondate: 2025-10-13T16:10:59.421+0530 IST  \\n- SCRUM-5: In Progress; summary: “Address janky scroll in feed list”; updated: 2025-10-13T16:14:49.842+0530 IST  \\n- SCRUM-2: Backlog; summary: “Resolve crash on profile photo upload”; updated: 2025-10-13T16:14:41.031+0530 IST  \\n- SCRUM-4: Backlog; summary: “Fix dark mode color contrast in buttons”; updated: 2025-10-13T16:14:45.183+0530 IST  \\n- SCRUM-6: Backlog; summary: “Resolve push notification tap not navigating”; updated: 2025-10-13T16:14:51.576+0530 IST  \\n\\n4) Blockers & Risks  \\n- SCRUM-2, SCRUM-3, SCRUM-4, and SCRUM-6 are all currently blocked as they remain in the Backlog.  \\n- **SCRUM-5** is the only task designated as In Progress, though no resolution timeline is indicated. All other items need to be moved forward to avoid further backlog accumulation.\\n\\n5) Actions for Tomorrow  \\n- Assign estimates to Scrum tasks currently in the backlog.  \\n- Increase focus on SCRUM-5 to progress towards completion.  \\n- Identify and address blockers causing delay in Backlog items.  \\n- Re-prioritize items based on urgency and team capacity.  \\n- Conduct a quick review of upcoming sprint timelines to align tasks accordingly.\\n\\n6) Data Snapshot (Appendix)  \\n- { \\\"issuekey\\\": \\\"SCRUM-1\\\", \\\"summary\\\": \\\"Fix login API timeout\\\", \\\"status.name\\\": \\\"Done\\\", \\\"statusCategory.name\\\": \\\"Done\\\", \\\"resolution.name\\\": \\\"Done\\\", \\\"assignee.displayName\\\": \\\"Jyothi Swarup\\\", \\\"priority.name\\\": \\\"Medium\\\", \\\"created\\\": \\\"2025-10-13T13:08:19.220+0530\\\", \\\"updated\\\": \\\"2025-10-13T16:14:36.945+0530\\\" }  \\n- { \\\"issuekey\\\": \\\"SCRUM-2\\\", \\\"summary\\\": \\\"Resolve crash on profile photo upload\\\", \\\"status.name\\\": \\\"Backlog\\\", \\\"statusCategory.name\\\": \\\"To Do\\\", \\\"resolution.name\\\": null, \\\"assignee.displayName\\\": \\\"Jyothi Swarup\\\", \\\"priority.name\\\": \\\"Medium\\\", \\\"created\\\": \\\"2025-10-13T13:08:20.563+0530\\\", \\\"updated\\\": \\\"2025-10-13T16:14:41.031+0530\\\" }  \\n- { \\\"issuekey\\\": \\\"SCRUM-5\\\", \\\"summary\\\": \\\"Address janky scroll in feed list\\\", \\\"status.name\\\": \\\"In Progress\\\", \\\"statusCategory.name\\\": \\\"In Progress\\\", \\\"resolution.name\\\": null, \\\"assignee.displayName\\\": \\\"Jyothi Swarup\\\", \\\"priority.name\\\": \\\"Medium\\\", \\\"created\\\": \\\"2025-10-13T13:08:29.354+0530\\\", \\\"updated\\\": \\\"2025-10-13T16:14:49.842+0530\\\" }\"\n  }"
      },
      "typeVersion": 1.3
    },
    {
      "id": "4014c2f1-5ff9-4617-b780-f345669b3a1a",
      "name": "Haftnotiz",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -336,
        496
      ],
      "parameters": {
        "content": "## Daily Evening Trigger  \nSchedules and initiates the EOD workflow each workday evening automatically."
      },
      "typeVersion": 1
    },
    {
      "id": "3d75eeb6-2cac-44a0-8b7a-2462f6fdfe61",
      "name": "Haftnotiz1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        112,
        304
      ],
      "parameters": {
        "height": 176,
        "content": "## Get ALL issues (Jira)  \nRetrieves all Jira issues for the day, including statuses, priorities, and assignees, to power the EOD summary."
      },
      "typeVersion": 1
    },
    {
      "id": "2644c493-fb58-474a-bc2e-89fcf93f8299",
      "name": "Get ALL issues",
      "type": "n8n-nodes-base.jira",
      "position": [
        208,
        528
      ],
      "parameters": {
        "options": {},
        "operation": "getAll",
        "returnAll": true
      },
      "credentials": {
        "jiraSoftwareCloudApi": {
          "id": "AnaUUmFzt0vUQADt",
          "name": "jyothi"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "f4cee73e-d692-4835-b5a7-c0c94808cb13",
      "name": "Flatten Input",
      "type": "n8n-nodes-base.code",
      "position": [
        432,
        528
      ],
      "parameters": {
        "jsCode": "// n8n Code node: merge all incoming items into a single output array in one item\n\nconst inputItems = $input.all();\nconst combined = [];\n\n// Normalize any value to an array of plain objects\nfunction normalizeToArray(val) {\n  if (typeof val === 'string') {\n    const trimmed = val.trim();\n    try {\n      const parsed = JSON.parse(trimmed);\n      return Array.isArray(parsed) ? parsed : [parsed];\n    } catch {\n      return [{ raw: trimmed }];\n    }\n  }\n  if (Array.isArray(val)) return val;\n  if (val && typeof val === 'object') return [val];\n  return [{ value: val }];\n}\n\n// Merge all items' json into one array\nfor (const item of inputItems) {\n  const source = item.json !== undefined ? item.json : item;\n  const arr = normalizeToArray(source);\n  for (const el of arr) {\n    const obj = el && typeof el === 'object' ? el : { value: el };\n    combined.push(obj);\n  }\n}\n\n// Return a single n8n item containing the whole array\nreturn [\n  {\n    json: {\n      combined,            // All input collapsed into one array\n      count: combined.length\n    }\n  }\n];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "7692b76d-68c2-46f0-8d6c-eff609de74b7",
      "name": "Create Summary",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        656,
        416
      ],
      "parameters": {
        "text": "={{ $json.combined }}",
        "options": {
          "systemMessage": "You are an End‑of‑Day (EOD) Report generator for engineering teams. Your job is to read a pasted text blob representing the day’s work (e.g., combined Jira issue array, logs, API responses) and produce a consistent EOD summary every single time using the exact template and rules below. Do not ask questions. Infer context only from the input.\n\nINPUT FORMAT\n- The input may be a single object containing { combined: [...], count: N } or a raw array of issue/work items.\n- Treat JSON keys/values and log lines as source of truth.\n- Today’s local time context: Asia/Kolkata (IST), unless clearly indicated otherwise.\n\nOUTPUT TEMPLATE\n1) EOD Summary\n- One concise paragraph describing today’s overall outcome and the most important takeaway (e.g., completion, progress, blockers).\n\n2) Key Metrics (Today)\n- Total items processed:\n- Completed (statusCategory: Done or resolution present):\n- In Progress (status.name: In Progress):\n- Backlog/To Do (statusCategory: To Do or status.name: Backlog/To Do):\n- Bugs vs Tasks (issuetype.name counts):\n- Top assignees (by count, up to 3):\n- Priority distribution (by priority.name):\n\n3) Notable Updates Today\n- 3–6 bullets referencing specific keys and summaries (e.g., SCRUM-1: Done; summary: “Fix login API timeout”; resolutiondate/timestamp if present, in IST label).\n\n4) Blockers & Risks\n- Bullets inferred from statuses, null fields (e.g., timeoriginalestimate), overdue sprint windows, inconsistent “active” vs past endDate, or items showing no progress (created vs updated).\n\n5) Actions for Tomorrow\n- 4–7 prioritized, action‑oriented steps tied to blockers and carryover (assign, add estimate, re‑prioritize, resolve conflicts, test/monitor, etc.).\n\n6) Data Snapshot (Appendix)\n- Quote minimal exact fields for 3–5 representative records (issue key, summary, status.name, statusCategory.name, resolution.name, assignee.displayName, priority.name, created, updated). Use original field names exactly.\n\nCLASSIFICATION RULES\n- Completed = statusCategory.key: done OR resolution present.\n- In Progress = status.name: In Progress OR statusCategory.key: indeterminate.\n- Backlog/To Do = status.name: Backlog/To Do OR statusCategory.key: new.\n- Bugs vs Tasks from issuetype.name.\n- Use input’s combined array if present; otherwise use the root array.\n- When timestamps are reported in readable form, label clearly as IST; otherwise preserve originals.\n\nFORMATTING RULES\n- Be concise; no fluff.\n- Headings and section order must never change.\n- Preserve field names exactly (e.g., statuscategorychangedate).\n- Use bold sparingly for 2–4 critical items/terms.\n- If a section has no data, write “None”.\n- Do not add links unless present in the input.\n\nERROR HANDLING\n- If the input appears incomplete or malformed, write “Input appears incomplete or malformed” in EOD Summary, then proceed with whatever can be extracted.\n\nCONSISTENCY CHECK\n- Ensure all six sections are present, labels match exactly, counts are internally consistent, and referenced keys/summaries match the input."
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 2.2
    },
    {
      "id": "514fc953-ea89-46e4-b1c0-c05367d978df",
      "name": "Append Summary",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1008,
        528
      ],
      "parameters": {
        "columns": {
          "value": {
            "Date": "={{ $now.format('dd-MMM-yyyy') }}",
            "JSON": "={{ $('Flatten Input').item.json.combined }}",
            "Summary": "={{ $json.output }}"
          },
          "schema": [
            {
              "id": "Date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "JSON",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "JSON",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Summary",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Summary",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/14iOjPbhS1kw2sFJy-N-hGads94iz38OjKzlMq8dkgc0/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "14iOjPbhS1kw2sFJy-N-hGads94iz38OjKzlMq8dkgc0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/14iOjPbhS1kw2sFJy-N-hGads94iz38OjKzlMq8dkgc0/edit?usp=drivesdk",
          "cachedResultName": "JIRA Daily Reporting"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "ajCmdXdhjJqZW6RE",
          "name": "automations"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "30e6b160-c87c-40ca-b2cd-75f5ae93d9ff",
      "name": "Daily Evening Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -16,
        528
      ],
      "parameters": {
        "rule": {
          "interval": [
            {}
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "1e5d7fbe-718a-472f-8d44-efc621042073",
      "name": "Friday Evening Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -80,
        1376
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "triggerAtDay": [
                5
              ],
              "triggerAtHour": 20
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "f4c8a646-d963-4b84-b442-91ecad3b31d8",
      "name": "Get all stored data",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        144,
        1376
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/14iOjPbhS1kw2sFJy-N-hGads94iz38OjKzlMq8dkgc0/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "14iOjPbhS1kw2sFJy-N-hGads94iz38OjKzlMq8dkgc0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/14iOjPbhS1kw2sFJy-N-hGads94iz38OjKzlMq8dkgc0/edit?usp=drivesdk",
          "cachedResultName": "JIRA Daily Reporting"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "ajCmdXdhjJqZW6RE",
          "name": "automations"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "d26c622b-92f7-4826-adeb-ddf57df9daf2",
      "name": "Flatten the input",
      "type": "n8n-nodes-base.code",
      "position": [
        368,
        1376
      ],
      "parameters": {
        "jsCode": "// n8n Code node: merge all incoming items into a single output array in one item\n\nconst inputItems = $input.all();\nconst combined = [];\n\n// Normalize any value to an array of plain objects\nfunction normalizeToArray(val) {\n  if (typeof val === 'string') {\n    const trimmed = val.trim();\n    try {\n      const parsed = JSON.parse(trimmed);\n      return Array.isArray(parsed) ? parsed : [parsed];\n    } catch {\n      return [{ raw: trimmed }];\n    }\n  }\n  if (Array.isArray(val)) return val;\n  if (val && typeof val === 'object') return [val];\n  return [{ value: val }];\n}\n\n// Merge all items' json into one array\nfor (const item of inputItems) {\n  const source = item.json !== undefined ? item.json : item;\n  const arr = normalizeToArray(source);\n  for (const el of arr) {\n    const obj = el && typeof el === 'object' ? el : { value: el };\n    combined.push(obj);\n  }\n}\n\n// Return a single n8n item containing the whole array\nreturn [\n  {\n    json: {\n      combined,            // All input collapsed into one array\n      count: combined.length\n    }\n  }\n];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "a626ce54-881d-4dbc-88ae-19adad2f6389",
      "name": "Create Weekly Summary",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        592,
        1376
      ],
      "parameters": {
        "text": "={{ $json.combined }}",
        "options": {
          "systemMessage": "You are a Weekly Summary generator for engineering teams. Your job is to read five day-level inputs (Monday through Friday)—each containing data (arrays/objects), JSON details, and an End‑of‑Day (EOD) summary—and produce a consistent Weekly Summary every single time using the exact template and rules below. Do not ask questions. Infer context only from the input.\n\nINPUT FORMAT\n- The input will include five day entries: Monday, Tuesday, Wednesday, Thursday, Friday.\n- Each day may have:\n  - Data: arrays/objects of issues/work items.\n  - JSON: raw or stringified JSON representing items.\n  - Summary: an EOD summary string following a known template.\n- Treat JSON keys/values and EOD text as source of truth.\n- If multiple structures are present (e.g., combined arrays, raw arrays, stringified JSON), parse/normalize and merge.\n\nOUTPUT TEMPLATE\n1) Weekly Overview\n- One concise paragraph stating the week window (Mon–Fri), overall outcome, and the single most important takeaway (e.g., completion count, major blocker cleared, quality trend).\n\n2) Weekly Key Metrics\n- Total items processed (Mon–Fri):\n- Completed (statusCategory: Done or resolution present):\n- In Progress (status.name: In Progress):\n- Backlog/To Do (statusCategory.key: new or status.name: Backlog/To Do):\n- Bugs vs Tasks (issuetype.name counts):\n- Top assignees (by count, up to 3):\n- Priority distribution (by priority.name):\n\n3) Day-by-Day Highlights\n- Monday: 2–4 bullets of notable events (keys, summaries, key timestamps), or “None”.\n- Tuesday: 2–4 bullets, or “None”.\n- Wednesday: 2–4 bullets, or “None”.\n- Thursday: 2–4 bullets, or “None”.\n- Friday: 2–4 bullets, or “None”.\n\n4) Progress & Trends\n- 3–6 bullets comparing days (e.g., rising backlog, stabilization in login, throughput changes, increase/decrease in Done, assignee load shifts).\n\n5) Blockers & Risks (Week)\n- Bullets inferred from the aggregate: persistent backlog items, missing estimates, conflicts (e.g., active sprint with past endDate), stalled items (unchanged status across days), or repeated failures.\n\n6) Recommendations (Next Week)\n- 5–8 prioritized, action‑oriented steps tied to blockers, throughput, and quality trends. Keep each specific and measurable.\n\n7) Completed Work (Week)\n- 3–8 bullets referencing key completions with issue keys, summaries, resolution/resolutiondate/timestamps (label IST if converting).\n\n8) Data Snapshot (Appendix)\n- Quote minimal exact fields for 5–10 representative records across the week:\n  - issue key, summary, status.name, statusCategory.name/key, resolution.name, assignee.displayName, priority.name, created, updated.\n  - Preserve original field names exactly as found.\n\nCLASSIFICATION & AGGREGATION RULES\n- Completed = statusCategory.key: done OR resolution present.\n- In Progress = status.name: In Progress OR statusCategory.key: indeterminate.\n- Backlog/To Do = status.name: Backlog/To Do OR statusCategory.key: new.\n- Bugs vs Tasks from issuetype.name.\n- Normalize sources in this order per day: combined array → root array/object → stringified JSON → EOD Summary counts (as fallback only).\n- When computing weekly metrics, sum unique items across all days (deduplicate by key if present).\n- Age/staleness: use created vs updated; note items unchanged across multiple days.\n- Timezone: Prefer Asia/Kolkata (IST) when converting; if preserving originals, label as-is.\n\nFORMATTING RULES\n- Be concise; no fluff.\n- Headings and section order must never change.\n- Preserve field names exactly (e.g., statuscategorychangedate).\n- Use bold sparingly for 3–6 critical items/terms.\n- If a section has no data, write “None”.\n- Do not add links unless present in the input.\n\nERROR HANDLING\n- If one or more days are missing or malformed, state “Some daily inputs appear incomplete or malformed” in Weekly Overview, then proceed with whatever can be extracted.\n- If a metric cannot be computed due to missing fields, set it to “Unknown” and briefly explain under Blockers & Risks.\n\nCONSISTENCY CHECK\n- Ensure all eight sections are present, labels match exactly, counts are internally consistent, and referenced keys/summaries match the input."
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 2.2
    },
    {
      "id": "82ae1eaa-b298-4a81-a839-248558ce2fd9",
      "name": "Create E-Mail",
      "type": "n8n-nodes-base.code",
      "position": [
        944,
        1376
      ],
      "parameters": {
        "jsCode": "// filename: n8n-generate-weekly-summary-email.js\n\n/**\n * n8n Code node (JavaScript) – Fixes “Code doesn't return items properly”\n * and returns a valid array of items with the generated HTML email.\n *\n * Input expectation:\n * - Each incoming item has a field `output` (string) containing the weekly summary text\n *   with sections 1) .. 8) as provided by your AI Agent node.\n *\n * Output:\n * - Returns an array with ONE item:\n *     { json: { html: \"<!-- full HTML email -->\", subject: \"Weekly Summary\", plainTextPreview: \"...\" } }\n *\n * If multiple input items exist, it uses the first one with `output` present.\n *\n * Place this code in your “Code” node and ensure the previous node passes an item\n * with `output` in `item.json.output`.\n */\n\n// --------------- Helper functions ---------------\n\n// Basic HTML escaping\nfunction escapeHtml(str) {\n  return String(str)\n    .replace(/&/g, '&amp;')\n    .replace(/</g, '&lt;')\n    .replace(/>/g, '&gt;')\n    .replace(/\"/g, '&quot;');\n}\n\n// Convert \"1) **Weekly Overview**\" -> \"Weekly Overview\"\nfunction cleanHeading(headingText) {\n  let h = headingText.replace(/^\\d\\)\\s*/, '');\n  h = h.replace(/\\*\\*/g, '').trim();\n  return h;\n}\n\n// Inline formatting: bold **text**, issue keys as pills\nfunction inlineFormat(text) {\n  let t = escapeHtml(text);\n  t = t.replace(/\\*\\*(.+?)\\*\\*/g, '<strong>$1</strong>');\n  t = t.replace(/\\b([A-Z]+-\\d+)\\b/g, '<span class=\"pill\">$1</span>');\n  return t;\n}\n\n// Render section content: bullets, paragraphs, snapshot code blocks\nfunction renderSectionContent(content) {\n  if (!content) return '<p class=\"muted\">None</p>';\n\n  const lines = content.split('\\n');\n  const blocks = [];\n  let currentList = null;\n\n  const flushList = () => {\n    if (currentList && currentList.items.length) {\n      const li = currentList.items.map(i => `<li>${inlineFormat(i)}</li>`).join('');\n      blocks.push(`<ul class=\"metric-list\">${li}</ul>`);\n    }\n    currentList = null;\n  };\n\n  for (let rawLine of lines) {\n    const line = rawLine.trim();\n\n    if (line.length === 0) {\n      flushList();\n      continue;\n    }\n    if (/^-\\s+/.test(line)) {\n      if (!currentList) currentList = { items: [] };\n      currentList.items.push(line.replace(/^-\\s+/, '').trim());\n      continue;\n    }\n    flushList();\n\n    // JSON-like snapshot lines -> code block\n    if (/^\\{.+\\}$/.test(line) || line.startsWith('{ \"') || line.startsWith('- {')) {\n      const cleaned = line.replace(/^-+\\s*/, '');\n      blocks.push(`<div class=\"code\">${escapeHtml(cleaned)}</div>`);\n    } else {\n      blocks.push(`<p>${inlineFormat(line)}</p>`);\n    }\n  }\n\n  flushList();\n  return blocks.join('\\n');\n}\n\n// Build email HTML from the `output` string\nfunction buildEmailHtml(outputText) {\n  // Find section headings like \"1) **Weekly Overview**\"\n  const headingRegex = /\\n?\\s*(\\d\\)\\s\\*\\*?[^\\n]+?\\*\\*?\\s*)/g;\n  const parts = [];\n  let match;\n\n  while ((match = headingRegex.exec(outputText)) !== null) {\n    const headingText = match[1];\n    const startIndexForContent = headingRegex.lastIndex;\n    const cleanedHeading = cleanHeading(headingText);\n\n    // Set previous section content boundary\n    if (parts.length > 0) {\n      parts[parts.length - 1].content = outputText.slice(parts[parts.length - 1].startIndex, match.index).trim();\n    }\n\n    parts.push({\n      heading: cleanedHeading,\n      startIndex: startIndexForContent,\n      content: '',\n    });\n  }\n\n  if (parts.length > 0) {\n    const last = parts[parts.length - 1];\n    last.content = outputText.slice(last.startIndex).trim();\n  } else {\n    // Fallback: whole text as one section\n    parts.push({\n      heading: 'Weekly Summary',\n      content: outputText.trim(),\n    });\n  }\n\n  const sectionHtml = parts.map(({ heading, content }) => {\n    return `\n      <section class=\"card\">\n        <h2 class=\"section-title\">${escapeHtml(heading)}</h2>\n        ${renderSectionContent(content)}\n      </section>\n    `;\n  }).join('\\n');\n\n  const generatedAtIst = escapeHtml(new Date().toLocaleString('en-IN', { timeZone: 'Asia/Kolkata' }));\n\n  const html = `\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\" />\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n<title>Weekly Summary</title>\n<style>\n  :root {\n    --bg: #f7f8fa;\n    --card-bg: #ffffff;\n    --text: #111827;\n    --muted: #6b7280;\n    --primary: #2563eb;\n    --border: #e5e7eb;\n  }\n  body {\n    margin: 0;\n    background: var(--bg);\n    color: var(--text);\n    font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Inter, Oxygen, Ubuntu, Cantarell, \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\", Arial, sans-serif;\n    line-height: 1.6;\n  }\n  .container {\n    max-width: 760px;\n    margin: 0 auto;\n    padding: 24px 16px;\n  }\n  .header {\n    background: linear-gradient(135deg, #eef2ff, #f0fdf4);\n    border: 1px solid var(--border);\n    border-radius: 14px;\n    padding: 20px;\n    margin-bottom: 16px;\n  }\n  .title {\n    margin: 0;\n    font-size: 22px;\n    font-weight: 700;\n  }\n  .subtitle {\n    margin: 6px 0 0;\n    font-size: 14px;\n    color: var(--muted);\n  }\n  .card {\n    background: var(--card-bg);\n    border: 1px solid var(--border);\n    border-radius: 12px;\n    padding: 18px;\n    margin: 12px 0;\n    box-shadow: 0 2px 6px rgba(31, 41, 55, 0.06);\n  }\n  .section-title {\n    margin: 0 0 12px;\n    font-size: 18px;\n    font-weight: 700;\n    color: var(--text);\n    border-left: 3px solid var(--primary);\n    padding-left: 10px;\n  }\n  p { margin: 10px 0; }\n  ul.metric-list { padding-left: 18px; margin: 8px 0; }\n  ul.metric-list li { margin: 6px 0; }\n  .pill {\n    display: inline-block;\n    font-size: 12px;\n    padding: 4px 8px;\n    border-radius: 999px;\n    background: #eef2ff;\n    color: #1e3a8a;\n    border: 1px solid #e5e7eb;\n    margin-right: 6px;\n  }\n  .code {\n    font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n    font-size: 12px;\n    background: #f3f4f6;\n    border: 1px solid var(--border);\n    border-radius: 8px;\n    padding: 8px;\n    white-space: pre-wrap;\n    word-break: break-word;\n    margin: 8px 0;\n  }\n  .footer {\n    text-align: center;\n    color: var(--muted);\n    font-size: 12px;\n    margin-top: 18px;\n  }\n  @media (max-width: 480px) {\n    .container { padding: 18px 12px; }\n    .title { font-size: 20px; }\n    .section-title { font-size: 17px; }\n  }\n</style>\n</head>\n<body>\n  <div class=\"container\">\n    <header class=\"header\">\n      <h1 class=\"title\">Weekly Summary</h1>\n      <p class=\"subtitle\">Generated automatically from your weekly report data.</p>\n    </header>\n\n    ${sectionHtml}\n\n    <footer class=\"footer\">\n      Sent via automated workflow · ${generatedAtIst} IST\n    </footer>\n  </div>\n</body>\n</html>\n  `.trim();\n\n  return html;\n}\n\n// Create a short plain text preview (for email providers that show a preview line)\nfunction buildPlainPreview(outputText) {\n  // Take the first line after Weekly Overview for a preview\n  const firstLine = outputText.split('\\n').find(l => l.trim().length > 0) || 'Weekly Summary';\n  return firstLine.replace(/\\*\\*/g, '').replace(/\\s+/g, ' ').trim().slice(0, 160);\n}\n\n// --------------- Main n8n code ---------------\n\nconst items = $input.all();\n\n// Pick the first item that has `output`\nlet outputText = null;\nfor (const it of items) {\n  if (it && it.json && typeof it.json.output === 'string' && it.json.output.trim().length > 0) {\n    outputText = it.json.output;\n    break;\n  }\n}\n\n// If not found, try the first item's whole JSON converted to string\nif (!outputText) {\n  if (items.length > 0 && items[0].json) {\n    outputText = JSON.stringify(items[0].json);\n  } else {\n    outputText = 'Weekly Summary\\n\\nNo output text found in incoming items.';\n  }\n}\n\n// Build HTML and preview\nconst html = buildEmailHtml(outputText);\nconst preview = buildPlainPreview(outputText);\n\n// Return one n8n item with the email payload\nreturn [\n  {\n    json: {\n      subject: 'Weekly Summary',\n      html,\n      plainTextPreview: preview,\n    },\n  },\n];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "9d53e156-2c55-412f-a342-ac7b15be99f9",
      "name": "E-Mail to Stakeholders",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1168,
        1376
      ],
      "webhookId": "32493ed3-072e-43f9-a3ef-7623fdf6e4cf",
      "parameters": {
        "sendTo": "jyothi.swarup@techdome.net.in",
        "message": "={{ $json.html }}",
        "options": {},
        "subject": "={{ $json.subject }}"
      },
      "credentials": {
        "gmailOAuth2": {
          "id": "70f5n8rPahCANHs7",
          "name": "jyothi"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "551aec75-3b84-4fe9-a859-c224e194463f",
      "name": "Haftnotiz2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        352,
        688
      ],
      "parameters": {
        "height": 176,
        "content": "## Flatten Input  \nNormalizes and flattens the Jira JSON into a lighter structure so downstream nodes can parse consistently."
      },
      "typeVersion": 1
    },
    {
      "id": "74294bfe-8fcb-4b01-b3de-015ba940405e",
      "name": "Haftnotiz3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        640,
        176
      ],
      "parameters": {
        "height": 192,
        "content": "## Chat Model (EOD)  \nGenerates a structured End‑of‑Day summary from the flattened issue data using the configured Azure OpenAI model."
      },
      "typeVersion": 1
    },
    {
      "id": "c02f0d08-1761-4f59-bdde-1c430082776f",
      "name": "Haftnotiz4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        944,
        704
      ],
      "parameters": {
        "height": 192,
        "content": "## Append Summary (Sheet)  \nWrites the EOD summary and the day’s metadata into the Excel/Sheet store for later weekly aggregation."
      },
      "typeVersion": 1
    },
    {
      "id": "8539c40a-70dc-4e66-a2a4-02fe9deca977",
      "name": "Haftnotiz5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -400,
        1360
      ],
      "parameters": {
        "height": 176,
        "content": "## Friday Evening Trigger  \nStarts the weekly compilation workflow every Friday evening to build and send the weekly report."
      },
      "typeVersion": 1
    },
    {
      "id": "affe1837-b2b5-4337-80a0-59adca265027",
      "name": "Haftnotiz6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        64,
        1168
      ],
      "parameters": {
        "height": 176,
        "content": "## Get all stored data (Sheet)  \nReads the week’s EOD entries from the sheet, providing the full set of daily summaries for the weekly report."
      },
      "typeVersion": 1
    },
    {
      "id": "2e86ba0f-1810-478b-b68b-f5e949b442e8",
      "name": "Haftnotiz7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        304,
        1536
      ],
      "parameters": {
        "height": 176,
        "content": "## Flatten the input (Weekly)  \nConverts the read rows into a unified format for the weekly AI summarization step."
      },
      "typeVersion": 1
    },
    {
      "id": "5b3bc309-60b3-467c-bc62-3a04b7b52e32",
      "name": "Haftnotiz8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        576,
        1168
      ],
      "parameters": {
        "height": 176,
        "content": "## Chat Model (Weekly)  \nProduces a consistent Weekly Summary by analyzing the five daily EOD entries (Monday–Friday)."
      },
      "typeVersion": 1
    },
    {
      "id": "6ab5b8a2-7aa4-4795-aa2b-2514b5045776",
      "name": "Haftnotiz9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        880,
        1536
      ],
      "parameters": {
        "height": 176,
        "content": "## Create Email  \nTransforms the weekly summary into styled, mobile‑friendly HTML with a clear subject and preview."
      },
      "typeVersion": 1
    },
    {
      "id": "91a7270d-1ad6-4d10-9182-29068b710763",
      "name": "Haftnotiz10",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1104,
        1168
      ],
      "parameters": {
        "height": 176,
        "content": "## Email to Stakeholders  \nSends the final weekly report email to the stakeholder list using the configured email provider."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "8897253f-0b1a-4ea3-bf93-9b00f633c6e3",
  "connections": {
    "Create Email": {
      "main": [
        [
          {
            "node": "Email to Stakeholders",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "f4cee73e-d692-4835-b5a7-c0c94808cb13": {
      "main": [
        [
          {
            "node": "7692b76d-68c2-46f0-8d6c-eff609de74b7",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "7692b76d-68c2-46f0-8d6c-eff609de74b7": {
      "main": [
        [
          {
            "node": "514fc953-ea89-46e4-b1c0-c05367d978df",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "2644c493-fb58-474a-bc2e-89fcf93f8299": {
      "main": [
        [
          {
            "node": "f4cee73e-d692-4835-b5a7-c0c94808cb13",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "d26c622b-92f7-4826-adeb-ddf57df9daf2": {
      "main": [
        [
          {
            "node": "a626ce54-881d-4dbc-88ae-19adad2f6389",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "f4c8a646-d963-4b84-b442-91ecad3b31d8": {
      "main": [
        [
          {
            "node": "d26c622b-92f7-4826-adeb-ddf57df9daf2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "a626ce54-881d-4dbc-88ae-19adad2f6389": {
      "main": [
        [
          {
            "node": "Create Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "30e6b160-c87c-40ca-b2cd-75f5ae93d9ff": {
      "main": [
        [
          {
            "node": "2644c493-fb58-474a-bc2e-89fcf93f8299",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "1e5d7fbe-718a-472f-8d44-efc621042073": {
      "main": [
        [
          {
            "node": "f4c8a646-d963-4b84-b442-91ecad3b31d8",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Azure OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "7692b76d-68c2-46f0-8d6c-eff609de74b7",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Azure OpenAI Chat Model1": {
      "ai_languageModel": [
        [
          {
            "node": "a626ce54-881d-4dbc-88ae-19adad2f6389",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "654069da-1c35-4475-8a67-1771a9301892": {
      "ai_outputParser": [
        [
          {
            "node": "a626ce54-881d-4dbc-88ae-19adad2f6389",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "88de2233-3d12-4183-a700-4c40f9c91935": {
      "ai_outputParser": [
        [
          {
            "node": "7692b76d-68c2-46f0-8d6c-eff609de74b7",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    }
  }
}
Häufig gestellte Fragen

Wie verwende ich diesen Workflow?

Kopieren Sie den obigen JSON-Code, erstellen Sie einen neuen Workflow in Ihrer n8n-Instanz und wählen Sie "Aus JSON importieren". Fügen Sie die Konfiguration ein und passen Sie die Anmeldedaten nach Bedarf an.

Für welche Szenarien ist dieser Workflow geeignet?

Experte

Ist es kostenpflichtig?

Dieser Workflow ist völlig kostenlos. Beachten Sie jedoch, dass Drittanbieterdienste (wie OpenAI API), die im Workflow verwendet werden, möglicherweise kostenpflichtig sind.

Workflow-Informationen
Schwierigkeitsgrad
Experte
Anzahl der Nodes26
Kategorie-
Node-Typen9
Schwierigkeitsbeschreibung

Für fortgeschrittene Benutzer, komplexe Workflows mit 16+ Nodes

Autor
Rahul Joshi

Rahul Joshi

@rahul08

Rahul Joshi is a seasoned technology leader specializing in the n8n automation tool and AI-driven workflow automation. With deep expertise in building open-source workflow automation and self-hosted automation platforms, he helps organizations eliminate manual processes through intelligent n8n ai agent automation solutions.

Externe Links
Auf n8n.io ansehen

Diesen Workflow teilen

Kategorien

Kategorien: 34