{"meta":{"instanceId":"db30e8ae4100235addbd4638770997b7ef11878d049073c888ba440ca84c55fc"},"nodes":[{"id":"4d549fd9-751b-4cde-a0ef-452a3e5ac9a4","name":"Receive Meeting Data","type":"n8n-nodes-base.webhook","position":[-1184,96],"webhookId":"meeting-intelligence","parameters":{"path":"meeting-transcript","options":{},"httpMethod":"POST","responseMode":"lastNode"},"typeVersion":2.1},{"id":"0b4180cc-4562-476f-bef6-e2613bb0ec89","name":"Parse Meeting Input","type":"n8n-nodes-base.code","position":[-928,96],"parameters":{"jsCode":"// Extract and structure meeting data\nconst body = $input.first().json.body;\n\n// Support multiple input formats\nconst meetingData = {\n  title: body.title || body.meeting_title || body.subject || 'Untitled Meeting',\n  date: body.date || body.meeting_date || new Date().toISOString(),\n  attendees: body.attendees || body.participants || [],\n  transcript: body.transcript || body.notes || body.content || '',\n  duration: body.duration || 60,\n  meeting_url: body.meeting_url || body.zoom_link || '',\n  recording_url: body.recording_url || '',\n  organizer: body.organizer || body.host || 'Unknown'\n};\n\n// Parse attendees if comma-separated string\nif (typeof meetingData.attendees === 'string') {\n  meetingData.attendees = meetingData.attendees.split(',').map(a => a.trim());\n}\n\n// Extract key metadata\nmeetingData.word_count = meetingData.transcript.split(/\\s+/).length;\nmeetingData.has_recording = !!meetingData.recording_url;\nmeetingData.attendee_count = meetingData.attendees.length;\n\nreturn {\n  json: meetingData\n};"},"typeVersion":2},{"id":"56da8b95-4fcc-43f0-8765-f7c73b5ba6cd","name":"AI Meeting Analysis","type":"n8n-nodes-base.openAi","position":[-672,96],"parameters":{"prompt":{"messages":[{"role":"system","content":"You are an executive assistant AI specializing in meeting analysis. Extract and structure information from meeting transcripts. Return ONLY valid JSON with these exact keys:\n\n{\n  \"executive_summary\": \"2-3 sentence overview\",\n  \"key_decisions\": [\"decision 1\", \"decision 2\"],\n  \"action_items\": [\n    {\"task\": \"description\", \"owner\": \"name\", \"due_date\": \"YYYY-MM-DD or 'not specified'\", \"priority\": \"High/Medium/Low\"},\n  ],\n  \"discussion_topics\": [\"topic 1\", \"topic 2\"],\n  \"open_questions\": [\"question 1\"],\n  \"next_steps\": [\"step 1\", \"step 2\"],\n  \"risks_identified\": [\"risk 1\"],\n  \"follow_up_meeting_needed\": true/false,\n  \"sentiment\": \"Positive/Neutral/Negative\",\n  \"engagement_level\": \"High/Medium/Low\"\n}"},{"content":"Meeting: {{ $json.title }}\nDate: {{ $json.date }}\nAttendees: {{ $json.attendees.join(', ') }}\nDuration: {{ $json.duration }} minutes\n\nTranscript:\n{{ $json.transcript }}"}]},"options":{"maxTokens":1500,"temperature":0.3},"resource":"chat","requestOptions":{}},"typeVersion":1.1},{"id":"7ed07e80-5776-4837-a951-6c6259661bf4","name":"Synthesize Intelligence","type":"n8n-nodes-base.code","position":[-432,96],"parameters":{"jsCode":"const meetingData = $('Parse Meeting Input').first().json;\nconst aiResponse = JSON.parse($input.first().json.choices[0].message.content);\n\n// Calculate priority scores\nfunction calculatePriorityScore(actionItem) {\n  const priorityScores = { 'High': 3, 'Medium': 2, 'Low': 1 };\n  const hasOwner = actionItem.owner && actionItem.owner !== 'not specified' ? 1 : 0;\n  const hasDueDate = actionItem.due_date && actionItem.due_date !== 'not specified' ? 1 : 0;\n  return (priorityScores[actionItem.priority] || 2) * 10 + hasOwner * 5 + hasDueDate * 5;\n}\n\n// Enrich action items\nconst enrichedActionItems = aiResponse.action_items.map((item, index) => ({\n  id: `${Date.now()}-${index}`,\n  task: item.task,\n  owner: item.owner || 'Unassigned',\n  due_date: item.due_date !== 'not specified' ? item.due_date : '',\n  priority: item.priority,\n  priority_score: calculatePriorityScore(item),\n  status: 'Not Started',\n  meeting_title: meetingData.title,\n  meeting_date: meetingData.date,\n  created_at: new Date().toISOString()\n}));\n\n// Sort by priority score\nenrichedActionItems.sort((a, b) => b.priority_score - a.priority_score);\n\nreturn {\n  json: {\n    // Meeting metadata\n    meeting_id: `meeting-${Date.now()}`,\n    meeting_title: meetingData.title,\n    meeting_date: meetingData.date,\n    attendees: meetingData.attendees,\n    attendee_count: meetingData.attendee_count,\n    duration: meetingData.duration,\n    organizer: meetingData.organizer,\n    meeting_url: meetingData.meeting_url,\n    recording_url: meetingData.recording_url,\n    \n    // AI Analysis\n    executive_summary: aiResponse.executive_summary,\n    key_decisions: aiResponse.key_decisions,\n    action_items: enrichedActionItems,\n    action_item_count: enrichedActionItems.length,\n    high_priority_count: enrichedActionItems.filter(a => a.priority === 'High').length,\n    discussion_topics: aiResponse.discussion_topics,\n    open_questions: aiResponse.open_questions,\n    next_steps: aiResponse.next_steps,\n    risks_identified: aiResponse.risks_identified,\n    follow_up_meeting_needed: aiResponse.follow_up_meeting_needed,\n    sentiment: aiResponse.sentiment,\n    engagement_level: aiResponse.engagement_level,\n    \n    // Calculated flags\n    requires_urgent_attention: enrichedActionItems.some(a => a.priority === 'High'),\n    has_unassigned_tasks: enrichedActionItems.some(a => a.owner === 'Unassigned'),\n    completeness_score: calculateCompletenessScore(enrichedActionItems, aiResponse)\n  }\n};\n\nfunction calculateCompletenessScore(actionItems, analysis) {\n  let score = 50; // Base score\n  \n  // Penalties\n  if (actionItems.length === 0) score -= 20;\n  if (actionItems.filter(a => a.owner === 'Unassigned').length > 0) score -= 10;\n  if (actionItems.filter(a => !a.due_date).length > 0) score -= 10;\n  if (analysis.open_questions.length > 3) score -= 10;\n  \n  // Bonuses\n  if (analysis.key_decisions.length > 0) score += 15;\n  if (analysis.next_steps.length > 0) score += 10;\n  if (actionItems.every(a => a.owner !== 'Unassigned')) score += 15;\n  if (actionItems.every(a => a.due_date)) score += 10;\n  \n  return Math.max(0, Math.min(100, score));\n}"},"typeVersion":2},{"id":"34518591-be29-49dd-8e99-353d467d6651","name":"Post Meeting Summary","type":"n8n-nodes-base.slack","position":[-176,-16],"webhookId":"76516aa6-29e5-49aa-b8ee-f665b17c8f4f","parameters":{"text":"📋 *Meeting Summary: {{ $json.meeting_title }}*\n\n🗓️ *Date:* {{ $json.meeting_date.split('T')[0] }} | *Duration:* {{ $json.duration }}min\n👥 *Attendees:* {{ $json.attendee_count }} people\n📊 *Completeness:* {{ $json.completeness_score }}%\n\n*Executive Summary:*\n{{ $json.executive_summary }}\n\n*✅ Key Decisions ({{ $json.key_decisions.length }}):*\n{{ $json.key_decisions.map((d, i) => `${i+1}. ${d}`).join('\\n') }}\n\n*🎯 Action Items ({{ $json.action_item_count }}):*\n{{ $json.action_items.slice(0, 5).map(a => `• [${a.priority}] ${a.task} - *${a.owner}* ${a.due_date ? '(Due: ' + a.due_date + ')' : ''}`).join('\\n') }}\n{{ $json.action_item_count > 5 ? `\\n...and ${$json.action_item_count - 5} more` : '' }}\n\n{{ $json.has_unassigned_tasks ? '⚠️ *Warning:* Some tasks are unassigned' : '' }}\n{{ $json.recording_url ? '🎥 <' + $json.recording_url + '|Watch Recording>' : '' }}","otherOptions":{"mrkdwn":true},"authentication":"oAuth2"},"typeVersion":2.3},{"id":"92dc15fc-7b21-4c15-bbf0-3760dfc51c3f","name":"Create Meeting Note","type":"n8n-nodes-base.notion","position":[-176,288],"parameters":{"title":"={{ $json.meeting_title }}","pageId":{"__rl":true,"mode":"url","value":""},"blockUi":{"blockValues":[{"type":"heading_2","richText":"Key Decisions"},{"type":"bulleted_list_item","richText":"={{ $json.key_decisions.join('\\n') }}"},{"type":"heading_2","richText":"Discussion Topics"},{"type":"bulleted_list_item","richText":"={{ $json.discussion_topics.join('\\n') }}"}]},"options":{}},"typeVersion":2.2},{"id":"4e90cb7c-c616-405e-bd56-820e14a2d5db","name":"Split Action Items","type":"n8n-nodes-base.code","position":[-176,464],"parameters":{"jsCode":"// Split action items into separate items for individual processing\nconst meetingData = $input.first().json;\nconst actionItems = meetingData.action_items || [];\n\nreturn actionItems.map(item => ({\n  json: {\n    // Action item details\n    ...item,\n    \n    // Meeting context\n    meeting_id: meetingData.meeting_id,\n    meeting_title: meetingData.meeting_title,\n    meeting_date: meetingData.meeting_date,\n    meeting_url: meetingData.meeting_url\n  }\n}));"},"typeVersion":2},{"id":"37cf70e2-4c17-42db-b419-31642186692b","name":"Create Task in Notion","type":"n8n-nodes-base.notion","position":[80,464],"parameters":{"title":"={{ $json.task }}","pageId":{"__rl":true,"mode":"url","value":""},"options":{}},"typeVersion":2.2},{"id":"0090cb65-513d-48a1-8624-c0af4367cf72","name":"Email Task Owner","type":"n8n-nodes-base.gmail","position":[336,464],"webhookId":"8d0a7475-3b27-49d1-8153-71d34da54cfd","parameters":{"sendTo":"={{ $json.owner }}@company.com","message":"=<h2>New Action Item from Meeting</h2>\n\n<p><strong>Meeting:</strong> {{ $json.meeting_title }}<br>\n<strong>Date:</strong> {{ $json.meeting_date.split('T')[0] }}</p>\n\n<h3>Your Task:</h3>\n<p>{{ $json.task }}</p>\n\n<p><strong>Priority:</strong> <span style=\"color: {{ $json.priority === 'High' ? 'red' : $json.priority === 'Medium' ? 'orange' : 'green' }}\">{{ $json.priority }}</span><br>\n<strong>Due Date:</strong> {{ $json.due_date || 'Not specified' }}</p>\n\n{{ $json.meeting_url ? '<p><a href=\"' + $json.meeting_url + '\">View Meeting Details</a></p>' : '' }}\n\n<hr>\n<p style=\"font-size: 12px; color: #666;\">This action item was automatically extracted from the meeting transcript using AI.</p>","options":{},"subject":"=Action Item Assigned: {{ $json.task }}"},"typeVersion":2.1},{"id":"ca5d79f0-d7f8-4b2f-b6a4-ab1ac50690af","name":"Create Calendar Reminder","type":"n8n-nodes-base.googleCalendar","position":[336,192],"parameters":{"end":"={{ $json.due_date ? $json.due_date + 'T10:00:00' : $now.plus(7, 'days').plus(1, 'hour').toISO() }}","start":"={{ $json.due_date ? $json.due_date + 'T09:00:00' : $now.plus(7, 'days').toISO() }}","calendar":{"__rl":true,"mode":"list","value":""},"additionalFields":{"attendees":"={{ $json.owner }}@company.com"}},"typeVersion":1.3},{"id":"a46e8d15-e156-4593-89aa-1f4fe784ce4f","name":"Log Meeting Metrics","type":"n8n-nodes-base.googleSheets","position":[576,96],"parameters":{"columns":{"value":{"Date":"={{ $('Synthesize Intelligence').item.json.meeting_date.split('T')[0] }}","Duration":"={{ $('Synthesize Intelligence').item.json.duration }}","Attendees":"={{ $('Synthesize Intelligence').item.json.attendee_count }}","Decisions":"={{ $('Synthesize Intelligence').item.json.key_decisions.length }}","Sentiment":"={{ $('Synthesize Intelligence').item.json.sentiment }}","Meeting_ID":"={{ $('Synthesize Intelligence').item.json.meeting_id }}","Action_Items":"={{ $('Synthesize Intelligence').item.json.action_item_count }}","Completeness":"={{ $('Synthesize Intelligence').item.json.completeness_score }}","High_Priority":"={{ $('Synthesize Intelligence').item.json.high_priority_count }}","Meeting_Title":"={{ $('Synthesize Intelligence').item.json.meeting_title }}","Follow_Up_Needed":"={{ $('Synthesize Intelligence').item.json.follow_up_meeting_needed }}","Unassigned_Tasks":"={{ $('Synthesize Intelligence').item.json.has_unassigned_tasks }}"},"mappingMode":"defineBelow"},"options":{},"operation":"append","sheetName":{"__rl":true,"mode":"id","value":"gid=0"},"documentId":{"__rl":true,"mode":"id","value":"GOOGLE_SHEET_ID"}},"typeVersion":4.7},{"id":"13570864-18fe-483b-a331-439cdcc81dc5","name":"Return Success Response","type":"n8n-nodes-base.respondToWebhook","position":[832,96],"parameters":{"options":{},"respondWith":"json","responseBody":"={{ { \n  \"success\": true,\n  \"meeting_id\": $('Synthesize Intelligence').item.json.meeting_id,\n  \"action_items_created\": $('Synthesize Intelligence').item.json.action_item_count,\n  \"completeness_score\": $('Synthesize Intelligence').item.json.completeness_score,\n  \"summary\": $('Synthesize Intelligence').item.json.executive_summary\n} }}"},"typeVersion":1.1},{"id":"de8a0840-b92c-43e1-b5a4-47f2c4edb2af","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-1216,-16],"parameters":{"width":176,"height":96,"content":"Captures incoming meeting info via webhook."},"typeVersion":1},{"id":"a14d44a4-172f-48b5-81fb-bd94c4ac47a8","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[-960,-16],"parameters":{"width":176,"height":96,"content":"Extracts and structures raw meeting details."},"typeVersion":1},{"id":"9d72607d-4665-4b48-9cb5-54bf718474b3","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[-704,-16],"parameters":{"width":176,"height":96,"content":"Uses AI to analyze transcript and summarize."},"typeVersion":1},{"id":"656a1b1d-9a0f-49cd-98bb-babb307d1eba","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[-480,-16],"parameters":{"width":176,"height":96,"content":"Combines AI insights with meeting metadata."},"typeVersion":1},{"id":"71c5bb24-1bb8-4fbb-bb9b-dcdaa119956e","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[-224,-128],"parameters":{"width":176,"height":96,"content":"Sends structured summary to Slack channel."},"typeVersion":1},{"id":"997f27ca-9d82-4f0f-aa58-88ba8fc18aff","name":"Sticky Note5","type":"n8n-nodes-base.stickyNote","position":[-208,608],"parameters":{"width":176,"height":96,"content":"Separates each action item for processing."},"typeVersion":1},{"id":"9b9d86f2-5eba-474d-a7e4-e33e017d3348","name":"Sticky Note6","type":"n8n-nodes-base.stickyNote","position":[-208,176],"parameters":{"width":176,"height":96,"content":"Separates each action item for processing."},"typeVersion":1},{"id":"e0f4eab2-5150-4400-a935-dcec3b1dffc2","name":"Sticky Note7","type":"n8n-nodes-base.stickyNote","position":[48,352],"parameters":{"width":176,"height":96,"content":"Adds action items as Notion tasks."},"typeVersion":1},{"id":"61feedaa-7f20-4e4b-b71f-fcee7ba03849","name":"Sticky Note8","type":"n8n-nodes-base.stickyNote","position":[304,624],"parameters":{"width":176,"height":96,"content":"Sends email with assigned task details."},"typeVersion":1},{"id":"5aae0d6a-0081-4958-8149-17cec8f23481","name":"Sticky Note9","type":"n8n-nodes-base.stickyNote","position":[288,80],"parameters":{"width":176,"height":96,"content":"Adds meeting tasks to Google Calendar."},"typeVersion":1},{"id":"f1dacc31-4f37-4534-a508-aad4147d87a5","name":"Sticky Note10","type":"n8n-nodes-base.stickyNote","position":[544,-16],"parameters":{"width":176,"height":96,"content":"Records analytics in Google Sheets."},"typeVersion":1},{"id":"fd9bb129-1132-42bd-bd10-43f0f0eb9603","name":"Sticky Note11","type":"n8n-nodes-base.stickyNote","position":[800,-16],"parameters":{"width":182,"height":96,"content":"Sends JSON confirmation to webhook."},"typeVersion":1},{"id":"1e490953-37ae-4054-b8a1-b0933c604262","name":"Sticky Note12","type":"n8n-nodes-base.stickyNote","position":[-1632,-32],"parameters":{"width":352,"height":432,"content":"### 🧠 Workflow Summary 💼🤖📅\n\nThis workflow automates the entire meeting management process — from data capture to follow-up.\nIt starts by receiving meeting data, then uses AI to extract summaries, decisions, and action items.\n\nMeeting notes are saved to Notion, tasks are created and emailed to their owners, and calendar reminders are added automatically.\n\nAll meeting metrics are logged in Google Sheets for tracking and insights, while Slack instantly delivers summaries to your team.\nEverything runs seamlessly and requires zero manual work — just plug in your meeting data and let automation handle the rest.\n\n👉 **Connect with me on [LinkedIn](https://www.linkedin.com/in/daniel-shashko)**\n"},"typeVersion":1}],"pinData":{},"connections":{"Email Task Owner":{"main":[[{"node":"Log Meeting Metrics","type":"main","index":0}]]},"Split Action Items":{"main":[[{"node":"Create Task in Notion","type":"main","index":0}]]},"AI Meeting Analysis":{"main":[[{"node":"Synthesize Intelligence","type":"main","index":0}]]},"Create Meeting Note":{"main":[[{"node":"Create Calendar Reminder","type":"main","index":0}]]},"Log Meeting Metrics":{"main":[[{"node":"Return Success Response","type":"main","index":0}]]},"Parse Meeting Input":{"main":[[{"node":"AI Meeting Analysis","type":"main","index":0}]]},"Post Meeting Summary":{"main":[[{"node":"Log Meeting Metrics","type":"main","index":0}]]},"Receive Meeting Data":{"main":[[{"node":"Parse Meeting Input","type":"main","index":0}]]},"Create Task in Notion":{"main":[[{"node":"Email Task Owner","type":"main","index":0}]]},"Synthesize Intelligence":{"main":[[{"node":"Post Meeting Summary","type":"main","index":0},{"node":"Create Meeting Note","type":"main","index":0},{"node":"Split Action Items","type":"main","index":0}]]},"Create Calendar Reminder":{"main":[[{"node":"Log Meeting Metrics","type":"main","index":0}]]}}}