{
  "id": "XOs7YXaXmcGasosl",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Dynamic Seating & Venue Layout Planner",
  "tags": [],
  "nodes": [
    {
      "id": "6ebed595-6ce0-4738-9350-639fe6eaa8dc",
      "name": "Webhook Trigger",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -1584,
        336
      ],
      "parameters": {
        "path": "seating-planner",
        "options": {},
        "httpMethod": "POST"
      },
      "typeVersion": 2
    },
    {
      "id": "f9099584-6f17-4392-ba9f-4819eefc857c",
      "name": "Sticky Note - Trigger",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1648,
        -112
      ],
      "parameters": {
        "color": 4,
        "width": 208,
        "height": 696,
        "content": "## Trigger Seating Request\n\nReceives venue requirements and attendee data via webhook.\n\nExpected payload:\n{\n  \"eventType\": \"Conference/Wedding/Banquet\",\n  \"venueCapacity\": 500,\n  \"attendeeCount\": 350,\n  \"layoutPreference\": \"Theater/Classroom/Banquet\"\n}"
      },
      "typeVersion": 1
    },
    {
      "id": "c7e2cfc4-5c30-4a37-9481-b08a7c338759",
      "name": "Validate Request Data",
      "type": "n8n-nodes-base.code",
      "position": [
        -1360,
        336
      ],
      "parameters": {
        "jsCode": "// Validate and parse incoming request\nconst payload = $input.first().json.body || $input.first().json;\n\nconst requestData = {\n  eventType: payload.eventType || \"Conference\",\n  venueCapacity: parseInt(payload.venueCapacity) || 500,\n  attendeeCount: parseInt(payload.attendeeCount) || 350,\n  layoutPreference: payload.layoutPreference || \"Theater\",\n  venueDimensions: payload.venueDimensions || { width: 30, length: 40 }, // in meters\n  specialRequirements: payload.specialRequirements || [],\n  accessibilityNeeds: parseInt(payload.accessibilityNeeds) || 10,\n  vipCount: parseInt(payload.vipCount) || 0,\n  requestId: payload.requestId || `seat-${Date.now()}`,\n  timestamp: new Date().toISOString()\n};\n\n// Validate capacity\nif (requestData.attendeeCount > requestData.venueCapacity) {\n  return {\n    json: {\n      error: true,\n      message: \"Attendee count exceeds venue capacity\",\n      requestData\n    }\n  };\n}\n\nreturn { json: requestData };"
      },
      "typeVersion": 2
    },
    {
      "id": "493e8a46-496a-4169-a6bf-6527169feba3",
      "name": "Fetch Attendee Data",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -1136,
        192
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultName": "Attendees"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_SPREADSHEET_ID",
          "cachedResultName": "Venue Data"
        },
        "authentication": "serviceAccount"
      },
      "credentials": {
        "googleApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4
    },
    {
      "id": "b93eb9e9-f6fa-451c-aec8-c510b30fc57f",
      "name": "Sticky Note - Fetch Data",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1408,
        -112
      ],
      "parameters": {
        "color": 3,
        "width": 176,
        "height": 688,
        "content": "## Fetch Attendee Data\n\nRetrieve attendee information including names, groups, accessibility needs, and VIP status from Google Sheets."
      },
      "typeVersion": 1
    },
    {
      "id": "afa08e18-f492-4d0a-a818-91c914180cf3",
      "name": "Fetch Venue Templates",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -1136,
        480
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=1",
          "cachedResultName": "Venue Layouts"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_SPREADSHEET_ID",
          "cachedResultName": "Venue Data"
        },
        "authentication": "serviceAccount"
      },
      "credentials": {
        "googleApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4
    },
    {
      "id": "3134f27d-2601-4599-a4d7-4627c06833a3",
      "name": "Combine All Data",
      "type": "n8n-nodes-base.code",
      "position": [
        -912,
        336
      ],
      "parameters": {
        "jsCode": "// Combine all data for processing\nconst requestData = $input.all()[0].json;\nconst attendees = $input.all()[1].json;\nconst venueTemplates = $input.all()[2].json;\n\n// Structure combined data\nconst combinedData = {\n  request: requestData,\n  attendees: Array.isArray(attendees) ? attendees : [attendees],\n  venueTemplates: Array.isArray(venueTemplates) ? venueTemplates : [venueTemplates],\n  processingTimestamp: new Date().toISOString()\n};\n\nreturn { json: combinedData };"
      },
      "typeVersion": 2
    },
    {
      "id": "fcc3ef45-7cea-4b8f-976d-34a945785bdb",
      "name": "Sticky Note - Calculate",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1168,
        -192
      ],
      "parameters": {
        "color": 5,
        "width": 192,
        "height": 864,
        "content": "## Calculate Totals\n\nAggregate attendee data, venue constraints, and layout requirements for optimal planning."
      },
      "typeVersion": 1
    },
    {
      "id": "55f73cc6-3003-4ff9-b202-e333b86afdcb",
      "name": "Optimize Seating Layout",
      "type": "n8n-nodes-base.code",
      "position": [
        -688,
        336
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nconst request = data.request;\nconst attendees = data.attendees;\nconst templates = data.venueTemplates;\n\n// Select appropriate layout template\nfunction selectLayoutTemplate(eventType, layoutPref, templates) {\n  const template = templates.find(t => \n    t.eventType === eventType && t.layoutType === layoutPref\n  ) || templates[0] || {\n    layoutType: layoutPref,\n    seatsPerRow: 20,\n    rowSpacing: 1.2,\n    aisleWidth: 1.5,\n    stageDepth: 5\n  };\n  \n  return template;\n}\n\n// Calculate optimal layout dimensions\nfunction calculateLayout(attendeeCount, venueSize, template) {\n  const seatsPerRow = template.seatsPerRow || 20;\n  const totalRows = Math.ceil(attendeeCount / seatsPerRow);\n  const rowSpacing = template.rowSpacing || 1.2;\n  const aisleWidth = template.aisleWidth || 1.5;\n  \n  // Calculate number of aisles needed\n  const aislesNeeded = Math.floor(seatsPerRow / 10);\n  \n  // Calculate actual width needed\n  const seatWidth = 0.6; // meters\n  const widthNeeded = (seatsPerRow * seatWidth) + (aislesNeeded * aisleWidth);\n  const lengthNeeded = (totalRows * rowSpacing) + (template.stageDepth || 5);\n  \n  return {\n    totalRows,\n    seatsPerRow,\n    aislesNeeded,\n    dimensions: {\n      width: widthNeeded,\n      length: lengthNeeded\n    },\n    feasible: widthNeeded <= venueSize.width && lengthNeeded <= venueSize.length\n  };\n}\n\n// Group attendees by type\nfunction categorizeAttendees(attendees) {\n  const vips = attendees.filter(a => a.vipStatus === true || a.type === 'VIP');\n  const accessibility = attendees.filter(a => a.accessibility === true || a.accessibilityNeeds);\n  const groups = {};\n  \n  attendees.forEach(a => {\n    const group = a.group || a.company || 'General';\n    if (!groups[group]) groups[group] = [];\n    groups[group].push(a);\n  });\n  \n  return { vips, accessibility, groups };\n}\n\n// Generate seating assignments\nfunction generateSeatingPlan(layout, categorized, totalAttendees) {\n  const seatingPlan = [];\n  let currentRow = 1;\n  let currentSeat = 1;\n  \n  // Assign VIPs to front rows\n  categorized.vips.forEach((vip, index) => {\n    seatingPlan.push({\n      attendeeId: vip.id || vip.name,\n      attendeeName: vip.name,\n      section: 'VIP',\n      row: Math.floor(index / layout.seatsPerRow) + 1,\n      seat: (index % layout.seatsPerRow) + 1,\n      type: 'VIP',\n      notes: vip.notes || ''\n    });\n  });\n  \n  // Reserve accessible seating near aisles\n  let accessibleSeatsAssigned = 0;\n  categorized.accessibility.forEach((person, index) => {\n    const rowNum = Math.floor(layout.totalRows / 2) + Math.floor(index / 2);\n    seatingPlan.push({\n      attendeeId: person.id || person.name,\n      attendeeName: person.name,\n      section: 'Accessible',\n      row: rowNum,\n      seat: index % 2 === 0 ? 1 : layout.seatsPerRow, // Aisle seats\n      type: 'Accessible',\n      notes: person.accessibilityNeeds || 'Wheelchair accessible'\n    });\n    accessibleSeatsAssigned++;\n  });\n  \n  // Assign groups together\n  let generalSeatCounter = categorized.vips.length;\n  Object.keys(categorized.groups).forEach(groupName => {\n    const groupMembers = categorized.groups[groupName];\n    \n    groupMembers.forEach((member, index) => {\n      // Skip if already assigned (VIP or accessible)\n      if (seatingPlan.find(s => s.attendeeId === (member.id || member.name))) {\n        return;\n      }\n      \n      const rowNum = Math.floor(generalSeatCounter / layout.seatsPerRow) + 1;\n      const seatNum = (generalSeatCounter % layout.seatsPerRow) + 1;\n      \n      seatingPlan.push({\n        attendeeId: member.id || member.name,\n        attendeeName: member.name,\n        section: 'General',\n        row: rowNum,\n        seat: seatNum,\n        type: 'Group',\n        group: groupName,\n        notes: member.notes || ''\n      });\n      \n      generalSeatCounter++;\n    });\n  });\n  \n  return seatingPlan;\n}\n\n// Main processing\nconst template = selectLayoutTemplate(\n  request.eventType,\n  request.layoutPreference,\n  templates\n);\n\nconst layout = calculateLayout(\n  request.attendeeCount,\n  request.venueDimensions,\n  template\n);\n\nconst categorized = categorizeAttendees(attendees);\nconst seatingPlan = generateSeatingPlan(layout, categorized, request.attendeeCount);\n\n// Calculate statistics\nconst stats = {\n  totalSeats: layout.totalRows * layout.seatsPerRow,\n  assignedSeats: seatingPlan.length,\n  availableSeats: (layout.totalRows * layout.seatsPerRow) - seatingPlan.length,\n  utilizationRate: ((seatingPlan.length / (layout.totalRows * layout.seatsPerRow)) * 100).toFixed(2),\n  vipSeats: categorized.vips.length,\n  accessibleSeats: categorized.accessibility.length,\n  groupCount: Object.keys(categorized.groups).length\n};\n\n// Generate output\nconst result = {\n  requestId: request.requestId,\n  timestamp: new Date().toISOString(),\n  eventType: request.eventType,\n  layoutType: request.layoutPreference,\n  venue: {\n    capacity: request.venueCapacity,\n    dimensions: request.venueDimensions,\n    feasible: layout.feasible\n  },\n  layout: {\n    totalRows: layout.totalRows,\n    seatsPerRow: layout.seatsPerRow,\n    aisles: layout.aislesNeeded,\n    calculatedDimensions: layout.dimensions\n  },\n  seatingPlan: seatingPlan,\n  statistics: stats,\n  visualMap: generateVisualMap(layout, seatingPlan)\n};\n\n// Generate ASCII visual map\nfunction generateVisualMap(layout, seating) {\n  const map = [];\n  map.push('\\n=== VENUE LAYOUT MAP ===\\n');\n  map.push('[STAGE]'.padStart(layout.seatsPerRow * 2, ' '));\n  map.push('\\n');\n  \n  for (let row = 1; row <= layout.totalRows; row++) {\n    let rowStr = `R${row.toString().padStart(2, '0')} `;\n    \n    for (let seat = 1; seat <= layout.seatsPerRow; seat++) {\n      const assignment = seating.find(s => s.row === row && s.seat === seat);\n      \n      if (assignment) {\n        if (assignment.type === 'VIP') rowStr += 'V ';\n        else if (assignment.type === 'Accessible') rowStr += 'A ';\n        else rowStr += 'X ';\n      } else {\n        rowStr += '\u25cb ';\n      }\n      \n      // Add aisle\n      if (seat % 10 === 0 && seat !== layout.seatsPerRow) {\n        rowStr += '| ';\n      }\n    }\n    \n    map.push(rowStr);\n  }\n  \n  map.push('\\n\\nLegend: V=VIP | A=Accessible | X=Assigned | \u25cb=Available\\n');\n  \n  return map.join('\\n');\n}\n\nreturn { json: result };"
      },
      "typeVersion": 2
    },
    {
      "id": "241cbdaf-4e19-4243-8bff-000f8543ed52",
      "name": "Sticky Note - Optimize",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -928,
        -112
      ],
      "parameters": {
        "width": 352,
        "height": 752,
        "content": "## AI Optimization\n\nUse algorithms to calculate optimal seating based on:\n- Venue dimensions\n- Attendee groups\n- Accessibility needs\n- VIP placement\n- Aisle placement"
      },
      "typeVersion": 1
    },
    {
      "id": "cd660d9f-7d3c-4593-8ae9-d854f6cbc514",
      "name": "Format Recommendations",
      "type": "n8n-nodes-base.code",
      "position": [
        -464,
        336
      ],
      "parameters": {
        "jsCode": "const layoutData = $input.first().json;\n\n// Format recommendations in natural language\nconst recommendations = [];\n\nif (!layoutData.venue.feasible) {\n  recommendations.push('\u26a0\ufe0f WARNING: Current layout exceeds venue dimensions. Consider reducing seats per row or attendee count.');\n}\n\nif (layoutData.statistics.utilizationRate > 95) {\n  recommendations.push('\u26a0\ufe0f High capacity utilization. Consider adding buffer space for comfort.');\n}\n\nif (layoutData.statistics.utilizationRate < 70) {\n  recommendations.push('\u2713 Good space utilization with room for comfort and movement.');\n}\n\nif (layoutData.layout.aisles < 2) {\n  recommendations.push('\ud83d\udca1 Consider adding more aisles for better traffic flow.');\n}\n\nif (layoutData.statistics.accessibleSeats > 0) {\n  recommendations.push(`\u2713 ${layoutData.statistics.accessibleSeats} accessible seats reserved near aisles.`);\n}\n\nif (layoutData.statistics.vipSeats > 0) {\n  recommendations.push(`\u2713 ${layoutData.statistics.vipSeats} VIP seats assigned in front rows.`);\n}\n\nrecommendations.push(`\u2713 ${layoutData.statistics.groupCount} groups seated together for better networking.`);\n\n// Create formatted output\nconst formattedOutput = {\n  ...layoutData,\n  recommendations: recommendations,\n  summary: `Successfully generated seating plan for ${layoutData.statistics.assignedSeats} attendees in ${layoutData.layout.totalRows} rows with ${layoutData.statistics.availableSeats} buffer seats.`,\n  exportReady: true\n};\n\nreturn { json: formattedOutput };"
      },
      "typeVersion": 2
    },
    {
      "id": "2e43af7a-7d3c-4077-b15d-b86a0b83a962",
      "name": "Sticky Note - Format",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -560,
        32
      ],
      "parameters": {
        "color": 3,
        "height": 528,
        "content": "## Format Recommendations\n\nStructure seating plan with:\n- Visual layout map\n- Seat assignments\n- Statistics & metrics\n- Optimization tips"
      },
      "typeVersion": 1
    },
    {
      "id": "3b5e5ec2-317b-4977-bdbf-0b3536e20b3e",
      "name": "Save Master Plan",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -224,
        96
      ],
      "parameters": {
        "columns": {
          "value": {},
          "schema": [],
          "mappingMode": "autoMapInputData",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=2",
          "cachedResultName": "Seating Plans"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_SPREADSHEET_ID",
          "cachedResultName": "Venue Data"
        },
        "authentication": "serviceAccount"
      },
      "credentials": {
        "googleApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4
    },
    {
      "id": "acfda3e7-b8ab-4d29-aba4-a616f3fb2cdb",
      "name": "Save Individual Assignments",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -16,
        528
      ],
      "parameters": {
        "columns": {
          "mappingMode": "autoMapInputData"
        },
        "options": {},
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=3",
          "cachedResultName": "Seat Assignments"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_SPREADSHEET_ID",
          "cachedResultName": "Venue Data"
        },
        "authentication": "serviceAccount"
      },
      "credentials": {
        "googleApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4
    },
    {
      "id": "6cdcdd87-3938-46f7-856e-47da5213884d",
      "name": "Sticky Note - Save",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -256,
        288
      ],
      "parameters": {
        "color": 2,
        "width": 368,
        "height": 436,
        "content": "## Update Sheets\n\nSave seating plan to Google Sheets:\n- Master plan summary\n- Individual seat assignments\n- Layout specifications"
      },
      "typeVersion": 1
    },
    {
      "id": "9f0f8821-d72a-440b-958d-2cf4ee20f553",
      "name": "Send Response",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        -224,
        -80
      ],
      "parameters": {
        "options": {
          "responseCode": 200,
          "responseHeaders": {
            "entries": [
              {
                "name": "Content-Type",
                "value": "application/json"
              }
            ]
          }
        },
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify($json, null, 2) }}"
      },
      "typeVersion": 1
    },
    {
      "id": "126e21b6-1913-452d-bd8e-c65c4109aab5",
      "name": "Sticky Note - Response",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -288,
        -304
      ],
      "parameters": {
        "color": 5,
        "width": 272,
        "height": 576,
        "content": "## Send Alert\n\nReturn complete seating plan with:\n- Visual layout map\n- Seat assignments list\n- Statistics & recommendations\n- Export-ready format"
      },
      "typeVersion": 1
    },
    {
      "id": "7ae9a9d9-a170-4a1f-aca5-37d393ba9938",
      "name": "Split Seat Assignments",
      "type": "n8n-nodes-base.code",
      "position": [
        -240,
        528
      ],
      "parameters": {
        "jsCode": "const layoutData = $input.first().json;\n\n// Split seating plan into individual seat records\nconst seatAssignments = layoutData.seatingPlan.map(seat => ({\n  requestId: layoutData.requestId,\n  timestamp: layoutData.timestamp,\n  attendeeId: seat.attendeeId,\n  attendeeName: seat.attendeeName,\n  section: seat.section,\n  row: seat.row,\n  seat: seat.seat,\n  type: seat.type,\n  group: seat.group || '',\n  notes: seat.notes || ''\n}));\n\nreturn seatAssignments.map(seat => ({ json: seat }));"
      },
      "typeVersion": 2
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "d1d5db44-9513-485d-8c2b-4a480fe4190e",
  "connections": {
    "Webhook Trigger": {
      "main": [
        [
          {
            "node": "Validate Request Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Combine All Data": {
      "main": [
        [
          {
            "node": "Optimize Seating Layout",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Attendee Data": {
      "main": [
        [
          {
            "node": "Combine All Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Venue Templates": {
      "main": [
        [
          {
            "node": "Combine All Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate Request Data": {
      "main": [
        [
          {
            "node": "Fetch Attendee Data",
            "type": "main",
            "index": 0
          },
          {
            "node": "Fetch Venue Templates",
            "type": "main",
            "index": 0
          },
          {
            "node": "Combine All Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Recommendations": {
      "main": [
        [
          {
            "node": "Send Response",
            "type": "main",
            "index": 0
          },
          {
            "node": "Save Master Plan",
            "type": "main",
            "index": 0
          },
          {
            "node": "Split Seat Assignments",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Seat Assignments": {
      "main": [
        [
          {
            "node": "Save Individual Assignments",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Optimize Seating Layout": {
      "main": [
        [
          {
            "node": "Format Recommendations",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}