{
  "name": "Web Widget Handler",
  "nodes": [
    {
      "parameters": {
        "content": "## \ud83c\udf10 Web Widget Handler\n\n\uc6f9 \ucc44\ud305 \uc704\uc82f \u2194 Main CSBot \uc5f0\uacb0 \uc6cc\ud06c\ud50c\ub85c\uc6b0\n\n---\n\n### \u2705 Import \ud6c4 \ud544\uc218 \uc124\uc815\n\n**1. Main CSBot URL \ubcc0\uacbd**\n`Call CSBot` \ub178\ub4dc > URL\uc744 \uc2e4\uc81c n8n \ud638\uc2a4\ud2b8\ub85c \ubcc0\uacbd\n\uae30\ubcf8\uac12: `http://localhost:5678/webhook/csbot/message`\n\n**2. CORS / OPTIONS \ud504\ub9ac\ud50c\ub77c\uc774\ud2b8 \ucc98\ub9ac [\ud544\uc218]**\n\n\ube0c\ub77c\uc6b0\uc800\ub294 cross-origin POST \uc804\uc5d0 OPTIONS \uc694\uccad\uc744 \uba3c\uc800 \ubcf4\ub0c5\ub2c8\ub2e4.\nn8n Webhook \ub178\ub4dc\ub294 OPTIONS \uba54\uc11c\ub4dc\ub97c \uc9c0\uc6d0\ud558\uc9c0 \uc54a\uc73c\ubbc0\ub85c,\n**\ubc18\ub4dc\uc2dc \uc544\ub798 \uc911 \ud558\ub098**\ub85c \uc778\ud504\ub77c \ub808\ubca8\uc5d0\uc11c \ucc98\ub9ac\ud574\uc57c \ud569\ub2c8\ub2e4.\n\n\ubc29\ubc95 A \u2014 n8n \ud658\uacbd\ubcc0\uc218 (.env \ub610\ub294 docker-compose):\n```\nN8N_CORS_ORIGIN=https://smartstore.naver.com\n# \uac1c\ubc1c/\ud14c\uc2a4\ud2b8: N8N_CORS_ORIGIN=*\n```\nn8n\uc744 \uc7ac\uc2dc\uc791\ud558\uba74 OPTIONS \uc694\uccad\uc5d0 \uc790\ub3d9 \uc751\ub2f5\ud569\ub2c8\ub2e4.\n\n\ubc29\ubc95 B \u2014 Nginx \ub9ac\ubc84\uc2a4 \ud504\ub85d\uc2dc:\n```nginx\nadd_header Access-Control-Allow-Origin *;\nadd_header Access-Control-Allow-Methods 'POST, OPTIONS';\nadd_header Access-Control-Allow-Headers 'Content-Type';\nif ($request_method = OPTIONS) { return 204; }\n```\n\n\u203b POST \uc751\ub2f5\uc758 CORS \ud5e4\ub354\ub294 \uc774 \uc6cc\ud06c\ud50c\ub85c\uc6b0\uc758\n  `Send Widget Response` \ub178\ub4dc\uc5d0 \uc774\ubbf8 \uc124\uc815\ub418\uc5b4 \uc788\uc2b5\ub2c8\ub2e4.\n\n---\n\n### \ud14c\uc2a4\ud2b8 (curl)\n```bash\ncurl -X POST https://YOUR_N8N/webhook/widget \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"message\":\"\ubc30\uc1a1 \uc5b8\uc81c \uc640\uc694?\",\n       \"session_id\":\"test_001\",\n       \"store_id\":\"1\",\n       \"channel\":\"web_widget\"}'\n```",
        "height": 520,
        "width": 400,
        "color": 4
      },
      "id": "ww000001-0000-4000-8000-000000000001",
      "name": "Setup Notes",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -240,
        100
      ]
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "widget",
        "responseMode": "responseNode",
        "options": {}
      },
      "id": "ww000001-0000-4000-8000-000000000002",
      "name": "Receive Widget Request",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        200,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "// \uc704\uc82f \uc694\uccad\uc5d0\uc11c \ud544\ub4dc \ucd94\ucd9c \ubc0f \uac80\uc99d\nconst body = $input.item.json.body || $input.item.json;\n\nconst message    = (body.message    || '').trim();\nconst session_id = (body.session_id || '').trim();\nconst store_id   = (body.store_id   || '1').toString().trim();\nconst channel    = 'web_widget';\n\n// \ud544\uc218 \ud544\ub4dc \uac80\uc99d\nif (!message) {\n  throw new Error('message \ud544\ub4dc\uac00 \ube44\uc5b4 \uc788\uc2b5\ub2c8\ub2e4.');\n}\nif (!session_id) {\n  throw new Error('session_id \ud544\ub4dc\uac00 \ube44\uc5b4 \uc788\uc2b5\ub2c8\ub2e4.');\n}\n\nreturn {\n  message,\n  session_id,\n  store_id,\n  channel,\n  received_at: new Date().toISOString()\n};"
      },
      "id": "ww000001-0000-4000-8000-000000000003",
      "name": "Validate & Extract",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        440,
        300
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "http://localhost:5678/webhook/csbot/message",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"store_id\":   \"{{ $json.store_id }}\",\n  \"session_id\": \"{{ $json.session_id }}\",\n  \"channel\":    \"{{ $json.channel }}\",\n  \"message\":    \"{{ $json.message }}\"\n}",
        "options": {
          "timeout": 30000,
          "response": {
            "response": {
              "fullResponse": false
            }
          }
        }
      },
      "id": "ww000001-0000-4000-8000-000000000004",
      "name": "Call CSBot",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        680,
        300
      ],
      "notes": "\u26a0\ufe0f URL\uc744 \uc2e4\uc81c n8n \ud638\uc2a4\ud2b8\ub85c \ubcc0\uacbd\ud558\uc138\uc694.\n\uc608: https://your-n8n.example.com/webhook/csbot/message",
      "notesInFlow": false,
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "jsCode": "// Main CSBot \uc751\ub2f5 \u2192 \uc704\uc82f \uc751\ub2f5 \ud3ec\ub9f7\uc73c\ub85c \ubcc0\ud658\nconst csbot = $input.item.json;\n\n// Main CSBot\uc740 { response: \"...\" } \ub610\ub294 { message: \"...\" } \ud615\ud0dc\ub85c \ubc18\ud658\nconst botText = csbot.response || csbot.message || '\uc7a0\uc2dc \ud6c4 \ub2e4\uc2dc \uc2dc\ub3c4\ud574 \uc8fc\uc138\uc694.';\n\nreturn {\n  message:    botText,\n  session_id: $('Validate & Extract').first().json.session_id,\n  timestamp:  new Date().toISOString()\n};"
      },
      "id": "ww000001-0000-4000-8000-000000000005",
      "name": "Format Widget Response",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        920,
        220
      ]
    },
    {
      "parameters": {
        "jsCode": "// CSBot \ud638\ucd9c \uc2e4\ud328 \uc2dc \ud3f4\ubc31 \uc751\ub2f5\nreturn {\n  message:    '\uc77c\uc2dc\uc801\uc778 \uc624\ub958\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4. \uc7a0\uc2dc \ud6c4 \ub2e4\uc2dc \ubb38\uc758\ud574 \uc8fc\uc138\uc694.',\n  session_id: $('Validate & Extract').first().json.session_id,\n  timestamp:  new Date().toISOString(),\n  error:      true\n};"
      },
      "id": "ww000001-0000-4000-8000-000000000006",
      "name": "Format Error Response",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        920,
        420
      ]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ $json }}",
        "options": {
          "responseHeaders": {
            "entries": [
              {
                "name": "Access-Control-Allow-Origin",
                "value": "*"
              },
              {
                "name": "Access-Control-Allow-Methods",
                "value": "POST, OPTIONS"
              },
              {
                "name": "Access-Control-Allow-Headers",
                "value": "Content-Type"
              }
            ]
          }
        }
      },
      "id": "ww000001-0000-4000-8000-000000000007",
      "name": "Send Widget Response",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        1160,
        300
      ]
    }
  ],
  "connections": {
    "Receive Widget Request": {
      "main": [
        [
          {
            "node": "Validate & Extract",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate & Extract": {
      "main": [
        [
          {
            "node": "Call CSBot",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Call CSBot": {
      "main": [
        [
          {
            "node": "Format Widget Response",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Format Error Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Widget Response": {
      "main": [
        [
          {
            "node": "Send Widget Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Error Response": {
      "main": [
        [
          {
            "node": "Send Widget Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "binaryMode": "separate",
    "availableInMCP": false
  }
}