{
  "id": "J6XedhUeomqoJFea",
  "meta": {
    "builderVariant": "mcp",
    "aiBuilderAssisted": true,
    "templateCredsSetupCompleted": true
  },
  "name": "GMB Site Builder - Generate, Preview & Approve",
  "tags": [
    {
      "id": "f0gXs9Tkz6gpr3Ue",
      "name": "gmb-site-builder",
      "createdAt": "2026-07-24T15:37:24.555Z",
      "updatedAt": "2026-07-24T15:37:24.555Z"
    }
  ],
  "nodes": [
    {
      "id": "85ad53e3-cf92-404a-8507-e45fdd09638a",
      "name": "GMB Chat",
      "type": "@n8n/n8n-nodes-langchain.chatTrigger",
      "position": [
        -512,
        -496
      ],
      "parameters": {
        "public": true,
        "options": {
          "title": "GMB Site Builder",
          "subtitle": "Paste your Google Business Profile details to start.",
          "responseMode": "responseNodes",
          "allowedOrigins": "*",
          "inputPlaceholder": "Paste GMB details, or ask for a change..."
        },
        "initialMessages": "Hi! Paste your Google Business Profile details (name, city, category, phone, hours, services) and I will build your one-page website."
      },
      "typeVersion": 1.4
    },
    {
      "id": "0fa7693a-3f3e-4b3b-9c16-8ff179a9e8d7",
      "name": "Intake Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        -336,
        -496
      ],
      "parameters": {
        "options": {
          "maxIterations": 5,
          "systemMessage": "You are the intake half of a website builder for Google Business Profile (GMB) listings. You talk to the business owner and decide what happens next.\n\nAlways answer with these three fields:\n- action: one of \"build\", \"publish\", \"reply\"\n- message: what to say to the user, in plain friendly text\n- brief: the business brief you have gathered so far\n\nOUTPUT SHAPE - this matters:\n- Return action, message and brief as TOP-LEVEL fields.\n- Do NOT nest them inside an \"output\" key, a \"result\" key, or any other wrapper.\n- Only action and message are always required. brief may be omitted entirely, or contain just the fields you actually know. Never invent a value to fill a field.\n\nHow to choose action:\n- \"build\" once you have AT MINIMUM businessName, city, category, and one contact method (phone or email). Also use \"build\" for any change request to an existing page, e.g. \"make the hero darker\", \"add a booking section\", \"swap the colors\". Do not ask more questions when the user asks for a change - just rebuild.\n- \"publish\" when the user clearly approves going live, e.g. \"publish\", \"go live\", \"looks good, ship it\".\n- \"reply\" for everything else: greetings, questions, and when you still need details.\n\nWhen you need details, ask for the missing ones in a single short message. Offer choices as a NUMBERED LIST so the user can answer with just a number. The chat has no buttons, so never say \"click below\".\n\nAlways carry forward every brief field you already know - never blank a field you previously captured. Keep message under 70 words. Never put HTML in message.",
          "enableStreaming": false
        },
        "hasOutputParser": true
      },
      "typeVersion": 3.1
    },
    {
      "id": "fabd716b-ffac-40d7-9088-dad0646a1e23",
      "name": "Intake Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "position": [
        -416,
        -288
      ],
      "parameters": {
        "model": "anthropic/claude-sonnet-4.6",
        "options": {
          "temperature": 0.3
        }
      },
      "credentials": {
        "openRouterApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "fec10b90-1b44-4c99-905c-bc63ff75bedd",
      "name": "Chat Memory",
      "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
      "position": [
        -288,
        -304
      ],
      "parameters": {
        "contextWindowLength": 20
      },
      "typeVersion": 1.4
    },
    {
      "id": "7f864612-dedf-470d-89c2-610670957f48",
      "name": "Action Schema",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        -144,
        -256
      ],
      "parameters": {
        "autoFix": true,
        "schemaType": "manual",
        "inputSchema": "{\n  \"type\": \"object\",\n  \"required\": [\"action\", \"message\"],\n  \"properties\": {\n    \"action\": { \"type\": \"string\", \"enum\": [\"build\", \"publish\", \"reply\"] },\n    \"message\": { \"type\": \"string\" },\n    \"brief\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"businessName\": { \"type\": \"string\" },\n        \"city\": { \"type\": \"string\" },\n        \"category\": { \"type\": \"string\" },\n        \"phone\": { \"type\": \"string\" },\n        \"email\": { \"type\": \"string\" },\n        \"address\": { \"type\": \"string\" },\n        \"hours\": { \"type\": \"string\" },\n        \"services\": { \"type\": \"array\", \"items\": { \"type\": \"string\" } },\n        \"usp\": { \"type\": \"string\" },\n        \"tone\": { \"type\": \"string\" },\n        \"colors\": { \"type\": \"string\" }\n      }\n    }\n  }\n}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "579b5842-427a-4f9a-b36b-e3c7a3261d85",
      "name": "Route Action",
      "type": "n8n-nodes-base.switch",
      "position": [
        -16,
        -512
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "ae3a8c20-dd5d-4232-9406-480e2c9ebc9e",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.output.action }}",
                    "rightValue": "build"
                  }
                ]
              }
            },
            {
              "conditions": {
                "options": {
                  "version": 3,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "2cd9d812-3657-441f-aad0-833346dbf65b",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.output.action }}",
                    "rightValue": "publish"
                  }
                ]
              }
            }
          ]
        },
        "options": {
          "fallbackOutput": "extra",
          "renameFallbackOutput": "reply"
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "532cd6cb-751d-443f-acbf-cce74bbc4baf",
      "name": "Load Previous Version",
      "type": "n8n-nodes-base.dataTable",
      "onError": "continueRegularOutput",
      "position": [
        336,
        -512
      ],
      "parameters": {
        "limit": 1,
        "filters": {
          "conditions": [
            {
              "keyName": "sessionId",
              "keyValue": "={{ $(\"GMB Chat\").item.json.sessionId }}"
            }
          ]
        },
        "orderBy": true,
        "matchType": "allConditions",
        "operation": "get",
        "dataTableId": {
          "__rl": true,
          "mode": "id",
          "value": "AfMfWvlyRa7xuoPm"
        },
        "orderByColumn": "version"
      },
      "typeVersion": 1.1,
      "alwaysOutputData": true
    },
    {
      "id": "d35f944c-c813-4a2e-8288-7aefaf7d910c",
      "name": "Builder Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        576,
        -512
      ],
      "parameters": {
        "text": "=BUSINESS BRIEF (JSON):\n{{ $json.briefJson }}\n\nIS THIS AN EDIT OF AN EXISTING PAGE: {{ $json.isEdit }}\n\nLATEST USER MESSAGE (treat as the change request when this is an edit):\n{{ $json.changeRequest }}\n\nPREVIOUS VERSION OF THE PAGE:\n{{ $json.prevSafe }}\n\nReturn the complete updated index.html now.",
        "options": {
          "maxIterations": 3,
          "systemMessage": "You are a senior front-end developer. You output ONE complete, production-ready `index.html` file for a local business landing page.\n\nHARD RULES:\n- Output ONLY raw HTML. No markdown fences, no commentary, no explanation before or after.\n- Start at <!doctype html> and end at </html>.\n- Everything inline: one <style> block in <head>, one <script> block before </body> if needed. No external CSS or JS files, no build step, no frameworks.\n- No external images. Use CSS gradients, solid colour blocks, and inline SVG icons only. A broken image is worse than no image.\n- Mobile-first and fully responsive. Must look right at 375px and at 1440px.\n- Semantic HTML5, proper <title>, meta description, meta viewport, Open Graph tags, and JSON-LD LocalBusiness structured data built from the brief.\n- Accessible: real contrast, focus states, alt text or aria-labels on every icon and control.\n\nPAGE STRUCTURE (adapt sensibly to the business):\nsticky header with business name and a call button, hero with headline + subhead + primary CTA, services or menu grid, why-choose-us / USP strip, about paragraph, opening hours block, testimonials (write plausible generic ones, never invent named real people), contact section with phone / email / address and an embedded map placeholder built from CSS (no external iframe), footer with hours and copyright.\n\nEDIT MODE: when a previous version is supplied, you MUST return that same page with only the requested change applied. Preserve all other content, copy, structure and styling exactly. Do not regenerate the page from scratch and do not silently drop sections.\n\nCopy should be specific to the business and city in the brief. Never use lorem ipsum. Never use placeholder text like \"Your text here\".",
          "enableStreaming": false
        },
        "promptType": "define"
      },
      "typeVersion": 3.1
    },
    {
      "id": "e91b32b8-b07a-40b9-b42f-a14425b01459",
      "name": "Extract HTML",
      "type": "n8n-nodes-base.code",
      "position": [
        880,
        -512
      ],
      "parameters": {
        "jsCode": "const PREVIEW_BASE = \"https://n8n.salmanpro.me/webhook/cfffa3a6-4149-43b4-9ba4-54dbd91e4ab5/preview/\";\nconst raw = String($input.first().json.output || \"\");\nlet html = raw.trim();\nconst tick = String.fromCharCode(96);\nconst fence = tick + tick + tick;\nconst fs = html.indexOf(fence);\nif (fs !== -1) {\n  const after = html.slice(fs + 3);\n  const nl = after.indexOf(\"\\n\");\n  const body = nl === -1 ? after : after.slice(nl + 1);\n  const fe = body.indexOf(fence);\n  html = (fe === -1 ? body : body.slice(0, fe)).trim();\n}\nconst dt = html.toLowerCase().indexOf(\"<!doctype\");\nif (dt > 0) { html = html.slice(dt); }\nif (!html) { throw new Error(\"Builder Agent returned no HTML.\"); }\nconst ctx = $(\"Build Context\").first().json;\nreturn [{ json: { siteId: ctx.siteId, sessionId: ctx.sessionId, businessName: ctx.businessName, subdomainSlug: ctx.subdomainSlug, version: ctx.version, brief_object: ctx.brief_object, html: html, previewUrl: PREVIEW_BASE + ctx.siteId } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "b737eb25-29f7-4f49-ba9f-4f29c3d1b676",
      "name": "Save Site Version",
      "type": "n8n-nodes-base.dataTable",
      "position": [
        1312,
        -496
      ],
      "parameters": {
        "columns": {
          "value": {
            "html": "={{ $json.html }}",
            "siteId": "={{ $json.siteId }}",
            "status": "generated",
            "version": "={{ $json.version }}",
            "sessionId": "={{ $json.sessionId }}",
            "brief_object": "={{ $json.brief_object }}",
            "businessName": "={{ $json.businessName }}",
            "subdomainSlug": "={{ $json.subdomainSlug }}"
          },
          "schema": [
            {
              "id": "siteId",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "siteId",
              "defaultMatch": false
            },
            {
              "id": "sessionId",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "sessionId",
              "defaultMatch": false
            },
            {
              "id": "businessName",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "businessName",
              "defaultMatch": false
            },
            {
              "id": "subdomainSlug",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "subdomainSlug",
              "defaultMatch": false
            },
            {
              "id": "html",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "html",
              "defaultMatch": false
            },
            {
              "id": "brief_object",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "brief_object",
              "defaultMatch": false
            },
            {
              "id": "status",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "status",
              "defaultMatch": false
            },
            {
              "id": "version",
              "type": "number",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "version",
              "defaultMatch": false
            },
            {
              "id": "driveFileId",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "driveFileId",
              "defaultMatch": false
            },
            {
              "id": "driveLink",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "driveLink",
              "defaultMatch": false
            },
            {
              "id": "liveUrl",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "liveUrl",
              "defaultMatch": false
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "dataTableId": {
          "__rl": true,
          "mode": "id",
          "value": "AfMfWvlyRa7xuoPm"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "b5ad4f21-9a24-42b8-ad30-9d62b86de6e1",
      "name": "HTML to File",
      "type": "n8n-nodes-base.convertToFile",
      "onError": "continueRegularOutput",
      "position": [
        1536,
        -496
      ],
      "parameters": {
        "options": {
          "encoding": "utf8",
          "fileName": "index.html"
        },
        "operation": "toText",
        "sourceProperty": "html"
      },
      "typeVersion": 1.1
    },
    {
      "id": "ade3b51b-a308-4bb2-b3a4-c20ffa749d22",
      "name": "Archive to Drive",
      "type": "n8n-nodes-base.googleDrive",
      "onError": "continueRegularOutput",
      "position": [
        1760,
        -496
      ],
      "parameters": {
        "name": "={{ $(\"Extract HTML\").item.json.subdomainSlug }}-v{{ $(\"Extract HTML\").item.json.version }}.html",
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "options": {
          "simplifyOutput": true
        },
        "folderId": {
          "__rl": true,
          "mode": "id",
          "value": "1v2tHkXqB6jIHfj1f7HlMmxQ0vTs-llSi"
        }
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "4c915c67-0056-4131-9606-fdb9fffc8434",
      "name": "Log Run to Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "onError": "continueRegularOutput",
      "position": [
        1984,
        -496
      ],
      "parameters": {
        "columns": {
          "value": {
            "city": "={{ JSON.parse($(\"Extract HTML\").item.json.brief_object || \"{}\").city || \"\" }}",
            "status": "generated",
            "site_id": "={{ $(\"Extract HTML\").item.json.siteId }}",
            "version": "={{ $(\"Extract HTML\").item.json.version }}",
            "timestamp": "={{ $now.toISO() }}",
            "drive_link": "={{ $json.webViewLink || \"\" }}",
            "preview_url": "={{ $(\"Extract HTML\").item.json.previewUrl }}",
            "business_name": "={{ $(\"Extract HTML\").item.json.businessName }}",
            "drive_file_id": "={{ $json.id || \"\" }}",
            "subdomain_slug": "={{ $(\"Extract HTML\").item.json.subdomainSlug }}"
          },
          "schema": [
            {
              "id": "site_id",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "site_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "timestamp",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "business_name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "business_name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "city",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "city",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "subdomain_slug",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "subdomain_slug",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "preview_url",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "preview_url",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "drive_link",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "drive_link",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "drive_file_id",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "drive_file_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "version",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "version",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow"
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "1h_JaVYL1PHTsrKXbR1dtCNhjlGbBXvmqCMQx4MsGMyk"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "faf1b464-26f4-467e-89d8-e3b809f1a425",
      "name": "Mark Approved",
      "type": "n8n-nodes-base.dataTable",
      "onError": "continueRegularOutput",
      "position": [
        368,
        0
      ],
      "parameters": {
        "columns": {
          "value": {
            "status": "approved"
          },
          "schema": [
            {
              "id": "siteId",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "siteId",
              "defaultMatch": false
            },
            {
              "id": "sessionId",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "sessionId",
              "defaultMatch": false
            },
            {
              "id": "businessName",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "businessName",
              "defaultMatch": false
            },
            {
              "id": "subdomainSlug",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "subdomainSlug",
              "defaultMatch": false
            },
            {
              "id": "html",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "html",
              "defaultMatch": false
            },
            {
              "id": "brief_object",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "brief_object",
              "defaultMatch": false
            },
            {
              "id": "status",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "status",
              "defaultMatch": false
            },
            {
              "id": "version",
              "type": "number",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "version",
              "defaultMatch": false
            },
            {
              "id": "driveFileId",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "driveFileId",
              "defaultMatch": false
            },
            {
              "id": "driveLink",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "driveLink",
              "defaultMatch": false
            },
            {
              "id": "liveUrl",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "liveUrl",
              "defaultMatch": false
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "filters": {
          "conditions": [
            {
              "keyName": "sessionId",
              "keyValue": "={{ $(\"GMB Chat\").item.json.sessionId }}"
            }
          ]
        },
        "options": {},
        "matchType": "allConditions",
        "operation": "update",
        "dataTableId": {
          "__rl": true,
          "mode": "id",
          "value": "AfMfWvlyRa7xuoPm"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "2482a147-72de-40c9-9ea8-86c1d547451b",
      "name": "Chat Reply - Info",
      "type": "n8n-nodes-base.set",
      "position": [
        352,
        192
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "chat-out-info",
              "name": "output",
              "type": "string",
              "value": "={{ $json.output.message }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "d1192be3-c9bb-48a6-884c-ea9aafe450f9",
      "name": "Preview Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -480,
        624
      ],
      "parameters": {
        "path": "preview/:siteId",
        "options": {
          "allowedOrigins": "*"
        },
        "responseMode": "responseNode"
      },
      "typeVersion": 2.1
    },
    {
      "id": "3380b39d-89dc-4528-8486-a8cec1040b42",
      "name": "Load Site HTML",
      "type": "n8n-nodes-base.dataTable",
      "onError": "continueRegularOutput",
      "position": [
        -256,
        624
      ],
      "parameters": {
        "limit": 1,
        "filters": {
          "conditions": [
            {
              "keyName": "siteId",
              "keyValue": "={{ $(\"Preview Webhook\").item.json.params.siteId }}"
            }
          ]
        },
        "orderBy": true,
        "matchType": "allConditions",
        "operation": "get",
        "dataTableId": {
          "__rl": true,
          "mode": "id",
          "value": "AfMfWvlyRa7xuoPm"
        },
        "orderByColumn": "version"
      },
      "typeVersion": 1.1,
      "alwaysOutputData": true
    },
    {
      "id": "274f2687-2543-42b0-9a1e-682202459a1a",
      "name": "Inject Publish Bar",
      "type": "n8n-nodes-base.code",
      "position": [
        -32,
        624
      ],
      "parameters": {
        "jsCode": "const PUBLISH_BASE = \"https://n8n.salmanpro.me/webhook/c98e0946-402a-421b-943d-62866bcdbdd2/publish/\";\nconst row = $input.first().json || {};\nconst siteId = $(\"Preview Webhook\").first().json.params.siteId;\nif (!row.html) {\n  return [{ json: { html: \"<!doctype html><html><head><meta charset=\\\"utf-8\\\"><title>Preview not found</title></head><body style=\\\"font-family:system-ui;padding:48px;text-align:center\\\"><h1>Preview not found</h1><p>No generated site matches <code>\" + siteId + \"</code>.</p></body></html>\" } }];\n}\nconst endpoint = PUBLISH_BASE + siteId;\nconst deployed = String(row.status) === \"deployed\";\nconst liveUrl = row.liveUrl ? String(row.liveUrl) : (\"https://\" + row.subdomainSlug + \".dripranks.com\");\nconst btnLabel = deployed ? \"Update Website\" : \"Publish Live\";\nconst btnColor = deployed ? \"#2563eb\" : \"#22c55e\";\nconst btnText = deployed ? \"#eff6ff\" : \"#052e16\";\nconst liveLink = deployed ? (\"<a href=\\\"\" + liveUrl + \"\\\" target=\\\"_blank\\\" rel=\\\"noopener\\\" style=\\\"color:#93c5fd;font-size:13px;text-decoration:underline\\\">View live \u2197</a>\") : \"\";\nconst bar = \"<div style=\\\"position:fixed;left:0;right:0;bottom:0;z-index:2147483647;background:#0f172a;color:#fff;font-family:system-ui,-apple-system,sans-serif;padding:12px 18px;display:flex;gap:16px;align-items:center;justify-content:space-between;box-shadow:0 -2px 16px rgba(0,0,0,.35)\\\"><span style=\\\"font-size:14px\\\">Preview - v\" + row.version + \" - \" + row.businessName + \"</span><span style=\\\"display:flex;gap:14px;align-items:center\\\">\" + liveLink + \"<button id=\\\"n8nPublishBtn\\\" style=\\\"background:\" + btnColor + \";color:\" + btnText + \";border:0;border-radius:8px;padding:10px 20px;font-weight:700;font-size:14px;cursor:pointer\\\">\" + btnLabel + \"</button></span></div>\" + \"<script>(function(){var b=document.getElementById(\\\"n8nPublishBtn\\\");b.addEventListener(\\\"click\\\",function(){b.disabled=true;b.textContent=\\\"Publishing...\\\";fetch(\\\"\" + endpoint + \"\\\",{method:\\\"POST\\\",headers:{\\\"Content-Type\\\":\\\"application/json\\\"},body:\\\"{}\\\"}).then(function(r){return r.json();}).then(function(d){b.textContent=(d&&d.message)?d.message:\\\"Live\\\";b.style.background=\\\"#2563eb\\\";b.style.color=\\\"#eff6ff\\\";setTimeout(function(){location.reload();},1400);}).catch(function(){b.textContent=\\\"Failed - retry\\\";b.disabled=false;});});})();<\\/script>\";\nlet html = String(row.html);\nconst idx = html.toLowerCase().lastIndexOf(\"</body>\");\nhtml = idx === -1 ? html + bar : html.slice(0, idx) + bar + html.slice(idx);\nreturn [{ json: { html: html, siteId: siteId } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "6a118d95-e7de-46cf-90aa-03534143db00",
      "name": "Serve Preview Page",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        192,
        624
      ],
      "parameters": {
        "options": {
          "responseCode": 200,
          "responseHeaders": {
            "entries": [
              {
                "name": "Content-Type",
                "value": "text/html; charset=utf-8"
              },
              {
                "name": "Cache-Control",
                "value": "no-store"
              }
            ]
          }
        },
        "respondWith": "text",
        "responseBody": "={{ $json.html }}"
      },
      "typeVersion": 1.5
    },
    {
      "id": "c68ceaf4-6df3-4105-96cb-5bacee0bdf2a",
      "name": "Publish Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        704,
        640
      ],
      "parameters": {
        "path": "publish/:siteId",
        "options": {
          "allowedOrigins": "*"
        },
        "httpMethod": "POST",
        "responseMode": "responseNode"
      },
      "typeVersion": 2.1
    },
    {
      "id": "994b7091-6779-45d5-b25a-e9fe6dce3a2d",
      "name": "Mark Deployed",
      "type": "n8n-nodes-base.dataTable",
      "onError": "continueRegularOutput",
      "position": [
        1680,
        640
      ],
      "parameters": {
        "columns": {
          "value": {
            "status": "deployed",
            "liveUrl": "=https://{{ $('Load Site For Deploy').item.json.subdomainSlug }}.dripranks.com"
          },
          "schema": [
            {
              "id": "siteId",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "siteId",
              "defaultMatch": false
            },
            {
              "id": "sessionId",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "sessionId",
              "defaultMatch": false
            },
            {
              "id": "businessName",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "businessName",
              "defaultMatch": false
            },
            {
              "id": "subdomainSlug",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "subdomainSlug",
              "defaultMatch": false
            },
            {
              "id": "html",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "html",
              "defaultMatch": false
            },
            {
              "id": "brief_object",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "brief_object",
              "defaultMatch": false
            },
            {
              "id": "status",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "status",
              "defaultMatch": false
            },
            {
              "id": "version",
              "type": "number",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "version",
              "defaultMatch": false
            },
            {
              "id": "driveFileId",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "driveFileId",
              "defaultMatch": false
            },
            {
              "id": "driveLink",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "driveLink",
              "defaultMatch": false
            },
            {
              "id": "liveUrl",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "liveUrl",
              "defaultMatch": false
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "filters": {
          "conditions": [
            {
              "keyName": "siteId",
              "keyValue": "={{ $('Publish Webhook').item.json.params.siteId }}"
            }
          ]
        },
        "options": {},
        "matchType": "allConditions",
        "operation": "update",
        "dataTableId": {
          "__rl": true,
          "mode": "id",
          "value": "AfMfWvlyRa7xuoPm"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "84263cb8-276e-4626-9f9f-1cdb59779285",
      "name": "Confirm Approval",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        1904,
        640
      ],
      "parameters": {
        "options": {
          "responseCode": 200
        },
        "respondWith": "json",
        "responseBody": "={{ { \"ok\": true, \"siteId\": $('Publish Webhook').item.json.params.siteId, \"status\": \"deployed\", \"liveUrl\": \"https://\" + $('Load Site For Deploy').item.json.subdomainSlug + \".dripranks.com\", \"message\": \"Your site is live\" } }}"
      },
      "typeVersion": 1.5
    },
    {
      "id": "0bc6751e-989e-45ad-acc9-423967e6bb86",
      "name": "Load Site For Deploy",
      "type": "n8n-nodes-base.dataTable",
      "onError": "continueRegularOutput",
      "position": [
        928,
        640
      ],
      "parameters": {
        "limit": 1,
        "filters": {
          "conditions": [
            {
              "keyName": "siteId",
              "keyValue": "={{ $('Publish Webhook').item.json.params.siteId }}"
            }
          ]
        },
        "orderBy": true,
        "matchType": "allConditions",
        "operation": "get",
        "dataTableId": {
          "__rl": true,
          "mode": "id",
          "value": "AfMfWvlyRa7xuoPm"
        },
        "orderByColumn": "version"
      },
      "typeVersion": 1.1,
      "alwaysOutputData": true
    },
    {
      "id": "6f743004-5100-491a-9cf2-9eb04f60e931",
      "name": "Create Subdomain",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueRegularOutput",
      "position": [
        1152,
        640
      ],
      "parameters": {
        "url": "https://developers.hostinger.com/api/hosting/v1/accounts/u653589239/websites/dripranks.com/subdomains",
        "method": "POST",
        "options": {
          "response": {
            "response": {
              "neverError": true,
              "fullResponse": true
            }
          }
        },
        "jsonBody": "={{ { \"subdomain\": $('Load Site For Deploy').item.json.subdomainSlug } }}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth"
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "1aeb9c94-675d-4b78-a041-1d3054e1fabb",
      "name": "Upload To Hostinger",
      "type": "n8n-nodes-base.ftp",
      "position": [
        1376,
        640
      ],
      "parameters": {
        "path": "=/public_html/{{ $('Load Site For Deploy').item.json.subdomainSlug }}/index.html",
        "options": {},
        "operation": "upload",
        "binaryData": false,
        "fileContent": "={{ $('Load Site For Deploy').item.json.html }}"
      },
      "credentials": {
        "ftp": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "0c22e74b-fb0d-418f-ab92-88b76518b3de",
      "name": "Builder Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "position": [
        576,
        -352
      ],
      "parameters": {
        "model": "anthropic/claude-sonnet-4.6",
        "options": {
          "timeout": 600000,
          "temperature": 0.6
        }
      },
      "credentials": {
        "openRouterApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "1716aa9e-562c-4f96-bbbb-b88d79c3397d",
      "name": "Respond Published",
      "type": "@n8n/n8n-nodes-langchain.chat",
      "position": [
        624,
        0
      ],
      "parameters": {
        "message": "Marked as approved and queued for deployment. The Hostinger subdomain + live deploy step is Section 2 of this build and is not wired up yet - your page is saved and ready for it.",
        "options": {}
      },
      "typeVersion": 1.3
    },
    {
      "id": "b1533e55-fe5d-4692-8f89-712cea30ac68",
      "name": "Respond",
      "type": "@n8n/n8n-nodes-langchain.chat",
      "position": [
        608,
        192
      ],
      "parameters": {
        "message": "={{ $json.output.message }}",
        "options": {}
      },
      "typeVersion": 1.3
    },
    {
      "id": "fe4518ea-39f8-4cae-9c31-e4059cfe34ff",
      "name": "Respond Preview",
      "type": "@n8n/n8n-nodes-langchain.chat",
      "position": [
        2208,
        -496
      ],
      "parameters": {
        "message": "=Done - version {{ $(\"Extract HTML\").item.json.version }} of **{{ $(\"Extract HTML\").item.json.businessName }}** is ready.\n\nPreview it here: {{ $(\"Extract HTML\").item.json.previewUrl }}\n\nOpen the link, scroll through, then either tell me what to change (e.g. \"make the hero darker\") or hit **Publish Live** at the bottom of the preview.",
        "options": {}
      },
      "typeVersion": 1.3
    },
    {
      "id": "3e7131cb-3cae-49e6-b509-86ac0df0133e",
      "name": "Overview & Setup",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1312,
        -1040
      ],
      "parameters": {
        "width": 700,
        "height": 2064,
        "content": "# \ud83c\udfd7\ufe0f GMB Site Builder \u2014 AI Website Generator + 1-Click Hostinger Publish\n\nPaste a local business's Google Business Profile details into chat \u2192 an AI builds a complete one-page website \u2192 preview it on a live link \u2192 publish it to its own subdomain in one click. Great for **cold outreach**: send a prospect a real site already made for their business.\n\n## \ud83e\udde9 The 3 workflows (one canvas, three triggers)\n\n### \ud83d\udfe6 Workflow 1 \u2014 Create Website \u00b7 Chat\nChat Trigger \u2192 **Intake Agent** returns `{action, message, brief}` \u2192 **Switch** routes **build / publish / reply** \u2192 **Builder Agent** writes one complete, self-contained `index.html` \u2192 saved as a new **version** in the *Generated Websites* Data Table \u2192 archived to Drive + logged to Sheets \u2192 chat replies with the preview link. Edits are conversational (\"make the hero darker\") and modify the existing page.\n\n### \ud83d\udfe9 Workflow 2 \u2014 Show Preview \u00b7 GET /preview/:siteId\nWebhook loads the latest HTML for that site \u2192 injects a floating **Publish Live** bar \u2192 serves it as real `text/html`. Same link every time. Bar shows **Publish Live**, then **Update Website** once live.\n\n### \ud83d\udfe7 Workflow 3 \u2014 Publish on Hostinger \u00b7 POST /publish/:siteId\nLoad latest site \u2192 **Create Subdomain** via Hostinger API \u2192 **FTP upload** `index.html` to the subdomain folder \u2192 mark row `deployed` + save `liveUrl` \u2192 return `https://<slug>.<your-domain>`. Publish = Update (same overwrite).\n\n## \ud83d\udd27 CUSTOMIZE BEFORE YOU RUN\n\n**1) Credentials \u2014 select your own on these nodes**\n\u2022 `Intake Model`, `Builder Model` \u2192 OpenRouter creds (or swap for your provider/model)\n\u2022 `Create Subdomain` \u2192 HTTP Bearer Auth = your Hostinger API token\n\u2022 `Upload To Hostinger` \u2192 FTP (host, port 21, user, password from hPanel \u2192 FTP Accounts)\n\u2022 `Archive to Drive` \u2192 Google Drive \u00b7 `Log Run to Sheet` \u2192 Google Sheets\n\n**2) Data Table `Generated Websites`**\nCreate a Data Table with columns: `siteId, sessionId, businessName, subdomainSlug, html, brief_object, status, version, driveFileId, driveLink, liveUrl`. Select it on every Data Table node: `Load Previous Version`, `Save Site Version`, `Mark Approved`, `Load Site HTML`, `Mark Deployed`, `Load Site For Deploy`.\n\n**3) Your hosting username + domain \u2192 `Create Subdomain` node URL**\n`.../api/hosting/v1/accounts/YOUR_USERNAME/websites/YOURDOMAIN.com/subdomains`\nReplace `YOUR_USERNAME` (hPanel hosting username, e.g. u1234567) and `YOURDOMAIN.com`.\n\n**4) Your domain in every live-URL builder \u2192 replace `YOURDOMAIN.com`**\nNodes: `Extract HTML` (previewUrl), `Inject Publish Bar` (liveUrl fallback), `Mark Deployed` (liveUrl), `Confirm Approval` (liveUrl).\n\n**5) FTP upload path \u2192 `Upload To Hostinger` node \u2192 `path`**\nDefault `/public_html/<slug>/index.html` (FTP chrooted to the domain root). If your host differs, run an FTP `list` on `/` first, then set the correct base.\n\n**6) \u26a0\ufe0f Webhook URLs inside the Code nodes (do NOT skip)**\nOn import, both webhooks get NEW ids, so the hardcoded URLs must be updated:\n\u2022 `Extract HTML` \u2192 `PREVIEW_BASE` = your **Preview Webhook** Production URL (ends `/preview/`)\n\u2022 `Inject Publish Bar` \u2192 `PUBLISH_BASE` = your **Publish Webhook** Production URL (ends `/publish/`)\nCopy each from the webhook node's \"Production URL\" field.\n\n**7) Storage IDs**\n\u2022 `Archive to Drive` \u2192 `folderId` = your Drive folder\n\u2022 `Log Run to Sheet` \u2192 `documentId` + `sheetName` = your Sheet + tab. Row-1 headers: `site_id | timestamp | business_name | city | subdomain_slug | preview_url | drive_link | drive_file_id | status | version`\n\n**8) Model (optional)** \u2014 `Intake Model` / `Builder Model` default to `anthropic/claude-sonnet-4.6`; change to any OpenRouter model.\n\n## \ud83d\udcdd Good to know\n\u2022 **Slug** = business name \u2192 lowercase + hyphens + random 4-char tag (collision-safe).\n\u2022 Uploaded `index.html` serves OVER Hostinger's `default.php` placeholder \u2014 no need to delete it.\n\u2022 Keep editing a site in the SAME chat (or use its Update button) so it reuses the same subdomain; a new chat starts a new site.\n\u2022 Drive & Sheets steps are continue-on-error, so a Google hiccup never breaks the preview link.\n\u2022 New subdomains need a moment for SSL \u2014 don't treat a 200 as \"instantly live.\"\n"
      },
      "typeVersion": 1
    },
    {
      "id": "ff2f6611-36a9-485e-a5f4-7a3dbee98e0f",
      "name": "Section 1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -544,
        -672
      ],
      "parameters": {
        "color": 7,
        "width": 792,
        "height": 576,
        "content": "## 1 \u00b7 Chat intake & routing\nAn AI agent collects the business brief and returns build / publish / reply as structured JSON. The Switch sends each to its own branch."
      },
      "typeVersion": 1
    },
    {
      "id": "5242e24f-e206-4c6d-afaa-f879122dd065",
      "name": "Section 2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        272,
        -672
      ],
      "parameters": {
        "color": 7,
        "width": 976,
        "height": 448,
        "content": "## 2 \u00b7 Generate the website\nLoads the previous version (so edits update it), builds the prompt, and the builder agent writes a full index.html. Extract HTML cleans the output."
      },
      "typeVersion": 1
    },
    {
      "id": "4aef74a8-129f-44a0-9bdd-30835a2730a7",
      "name": "Section 3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1264,
        -672
      ],
      "parameters": {
        "color": 7,
        "width": 1136,
        "height": 368,
        "content": "## 3 \u00b7 Store, archive & reply\nSaves the new version to the Data Table, archives the file to Drive, logs the run to Sheets, then sends the preview link back to chat."
      },
      "typeVersion": 1
    },
    {
      "id": "e4f1261f-7d4f-42f0-9375-5b2baeea03e6",
      "name": "Section 4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        288,
        -192
      ],
      "parameters": {
        "color": 7,
        "width": 496,
        "height": 544,
        "content": "## Chat replies \u2014 approve / info\nIf the user approves in chat, the row is marked approved. Otherwise it replies with the agent's message asking for missing details."
      },
      "typeVersion": 1
    },
    {
      "id": "79c6452c-8e6b-475f-a93a-e392ddd24925",
      "name": "Section 5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -528,
        496
      ],
      "parameters": {
        "color": 7,
        "width": 992,
        "height": 288,
        "content": "## 4 \u00b7 Serve the live preview\nGET /preview/:siteId loads the latest HTML, injects a floating Publish / Update bar, and serves it as a real web page."
      },
      "typeVersion": 1
    },
    {
      "id": "bf6dec6c-313c-4ec6-8796-5fbd29f7ecd6",
      "name": "Section 6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        640,
        512
      ],
      "parameters": {
        "color": 7,
        "width": 928,
        "height": 288,
        "content": "## 5 \u00b7 Publish to Hostinger\nPOST /publish/:siteId loads the site, creates the subdomain via the Hostinger API, then uploads index.html over FTP."
      },
      "typeVersion": 1
    },
    {
      "id": "5dbf620a-0742-4080-bd97-2a7b5186c05f",
      "name": "Section 7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1584,
        496
      ],
      "parameters": {
        "color": 7,
        "width": 512,
        "height": 304,
        "content": "## Save live URL & confirm\nMarks the row deployed with its live URL and returns that URL to the preview page."
      },
      "typeVersion": 1
    },
    {
      "id": "cbcf629c-bccd-4d83-a462-d125f3721b3c",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -560,
        -816
      ],
      "parameters": {
        "color": 2,
        "width": 2976,
        "height": 1184,
        "content": "# Workflow 1"
      },
      "typeVersion": 1
    },
    {
      "id": "7573b9a6-3e74-4543-b71f-b1e0620de9d8",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -560,
        400
      ],
      "parameters": {
        "color": 2,
        "width": 1056,
        "height": 416,
        "content": "# Workflow 2\n"
      },
      "typeVersion": 1
    },
    {
      "id": "1e90d1d1-07e4-43fc-9aba-f8d132088de7",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        608,
        400
      ],
      "parameters": {
        "color": 2,
        "width": 1520,
        "height": 448,
        "content": "# Workflow 3\n"
      },
      "typeVersion": 1
    }
  ],
  "active": true,
  "settings": {
    "timezone": "Asia/Karachi",
    "binaryMode": "separate",
    "availableInMCP": true,
    "executionOrder": "v1",
    "executionTimeout": 900,
    "saveDataErrorExecution": "all"
  },
  "versionId": "6e2b8d7c-8c21-42ff-980e-35f411e1d7fe",
  "nodeGroups": [],
  "connections": {
    "GMB Chat": {
      "main": [
        [
          {
            "node": "Intake Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Chat Memory": {
      "ai_memory": [
        [
          {
            "node": "Intake Agent",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "Extract HTML": {
      "main": [
        [
          {
            "node": "Save Site Version",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTML to File": {
      "main": [
        [
          {
            "node": "Archive to Drive",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Intake Agent": {
      "main": [
        [
          {
            "node": "Route Action",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Intake Model": {
      "ai_languageModel": [
        [
          {
            "node": "Intake Agent",
            "type": "ai_languageModel",
            "index": 0
          },
          {
            "node": "Action Schema",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Route Action": {
      "main": [
        [
          {
            "node": "Load Previous Version",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Mark Approved",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Chat Reply - Info",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Action Schema": {
      "ai_outputParser": [
        [
          {
            "node": "Intake Agent",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Builder Agent": {
      "main": [
        [
          {
            "node": "Extract HTML",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Builder Model": {
      "ai_languageModel": [
        [
          {
            "node": "Builder Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Mark Approved": {
      "main": [
        [
          {
            "node": "Respond Published",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mark Deployed": {
      "main": [
        [
          {
            "node": "Confirm Approval",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Load Site HTML": {
      "main": [
        [
          {
            "node": "Inject Publish Bar",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Preview Webhook": {
      "main": [
        [
          {
            "node": "Load Site HTML",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Publish Webhook": {
      "main": [
        [
          {
            "node": "Load Site For Deploy",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Archive to Drive": {
      "main": [
        [
          {
            "node": "Log Run to Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Subdomain": {
      "main": [
        [
          {
            "node": "Upload To Hostinger",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log Run to Sheet": {
      "main": [
        [
          {
            "node": "Respond Preview",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Chat Reply - Info": {
      "main": [
        [
          {
            "node": "Respond",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save Site Version": {
      "main": [
        [
          {
            "node": "HTML to File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Inject Publish Bar": {
      "main": [
        [
          {
            "node": "Serve Preview Page",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upload To Hostinger": {
      "main": [
        [
          {
            "node": "Mark Deployed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Load Site For Deploy": {
      "main": [
        [
          {
            "node": "Create Subdomain",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Load Previous Version": {
      "main": [
        [
          {
            "node": "Builder Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}