{
  "name": "Messaging Burst Debounce & Context Guard",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "whatsapp-inbound",
        "responseMode": "responseNode",
        "options": {}
      },
      "id": "burst-webhook",
      "name": "Webhook - Inbound WhatsApp Message",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [180, 300],
      "webhookId": "wa-inbound-burst"
    },
    {
      "parameters": {
        "jsCode": "const headers = $input.first().json.headers || {};\nconst secret = headers['x-codeven-secret'] || headers['x-hub-signature-256'];\n\n// Basic webhook validation\nif (!secret && process.env.NODE_ENV === 'production') {\n  throw new Error('Unauthorized webhook caller: missing secret header.');\n}\n\nreturn $input.all();"
      },
      "id": "burst-verify-secret",
      "name": "VerifySecret",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [400, 300]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "INSERT INTO \"WhatsAppMessage\" (\"id\", \"conversationId\", \"sender\", \"body\", \"direction\", \"sentAt\")\nVALUES (\n  '{{ $('Webhook - Inbound WhatsApp Message').item.json.body?.messageId || $('Webhook - Inbound WhatsApp Message').item.json.messageId }}',\n  '{{ $('Webhook - Inbound WhatsApp Message').item.json.body?.conversationId || $('Webhook - Inbound WhatsApp Message').item.json.conversationId }}',\n  '{{ $('Webhook - Inbound WhatsApp Message').item.json.body?.from || $('Webhook - Inbound WhatsApp Message').item.json.from }}',\n  '{{ $('Webhook - Inbound WhatsApp Message').item.json.body?.text || $('Webhook - Inbound WhatsApp Message').item.json.text }}',\n  'inbound',\n  NOW()\n)\nON CONFLICT (\"id\") DO NOTHING\nRETURNING *;"
      },
      "id": "burst-save-message",
      "name": "SaveInboundMessage",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [620, 300],
      "credentials": {
        "postgres": {
          "id": "postgres-cred-placeholder",
          "name": "Production Database"
        }
      }
    },
    {
      "parameters": {
        "amount": 4,
        "unit": "seconds"
      },
      "id": "burst-debounce-wait",
      "name": "DebounceWait",
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1.1,
      "position": [840, 300],
      "webhookId": "burst-debounce-timer"
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT COUNT(*)::text AS newer FROM \"WhatsAppMessage\"\nWHERE \"conversationId\" = '{{ $('Webhook - Inbound WhatsApp Message').item.json.body?.conversationId || $('Webhook - Inbound WhatsApp Message').item.json.conversationId }}'\n  AND direction = 'inbound'\n  AND (\"sentAt\", id) > (SELECT \"sentAt\", id FROM \"WhatsAppMessage\" WHERE id = '{{ $('Webhook - Inbound WhatsApp Message').item.json.body?.messageId || $('Webhook - Inbound WhatsApp Message').item.json.messageId }}');"
      },
      "id": "burst-check-newer",
      "name": "CheckNewer",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [1060, 300],
      "credentials": {
        "postgres": {
          "id": "postgres-cred-placeholder",
          "name": "Production Database"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 1
          },
          "conditions": [
            {
              "id": "cond-is-newest-burst",
              "leftValue": "={{ String($json.newer ?? '0') }}",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "rightValue": "0"
            }
          ],
          "combinator": "and"
        }
      },
      "id": "burst-is-newest",
      "name": "IsNewest",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [1280, 300]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT id, \"sender\", \"body\", \"direction\", \"sentAt\"\nFROM \"WhatsAppMessage\"\nWHERE \"conversationId\" = '{{ $('Webhook - Inbound WhatsApp Message').item.json.body?.conversationId || $('Webhook - Inbound WhatsApp Message').item.json.conversationId }}'\nORDER BY \"sentAt\" ASC\nLIMIT 20;"
      },
      "id": "burst-fetch-history",
      "name": "FetchHistory",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [1520, 200],
      "credentials": {
        "postgres": {
          "id": "postgres-cred-placeholder",
          "name": "Production Database"
        }
      }
    },
    {
      "parameters": {
        "resource": "chat",
        "operation": "complete",
        "model": "gpt-4o",
        "messages": {
          "values": [
            {
              "role": "system",
              "content": "You are a customer assistant on WhatsApp. Formulate a single, unified response that comprehensively answers all recent messages in the conversation thread. Do not send fragmented answers."
            },
            {
              "role": "user",
              "content": "=Conversation history:\n{{ JSON.stringify($('FetchHistory').all().map(item => ({ sender: item.json.sender, body: item.json.body }))) }}"
            }
          ]
        },
        "options": {}
      },
      "id": "burst-generate-reply",
      "name": "OpenAI - Formulate Unified Reply",
      "type": "n8n-nodes-base.openAi",
      "typeVersion": 1.4,
      "position": [1740, 200],
      "credentials": {
        "openAiApi": {
          "id": "openai-cred-placeholder",
          "name": "OpenAI API Account"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://graph.facebook.com/v25.0/{{$env.WHATSAPP_PHONE_NUMBER_ID}}/messages",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"messaging_product\": \"whatsapp\",\n  \"to\": \"{{ $('Webhook - Inbound WhatsApp Message').item.json.body?.from || $('Webhook - Inbound WhatsApp Message').item.json.from }}\",\n  \"type\": \"text\",\n  \"text\": {\n    \"body\": \"{{ $json.message?.content || $json.replyText }}\"\n  }\n}"
      },
      "id": "burst-send-reply",
      "name": "WhatsApp - Send Unified Reply",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [1960, 200],
      "credentials": {
        "httpHeaderAuth": {
          "id": "meta-whatsapp-token-cred",
          "name": "WhatsApp Cloud API Token"
        }
      }
    },
    {
      "parameters": {},
      "id": "burst-drop-superceded",
      "name": "DropSupercededExecution",
      "type": "n8n-nodes-base.noOp",
      "typeVersion": 1,
      "position": [1520, 420]
    }
  ],
  "connections": {
    "Webhook - Inbound WhatsApp Message": {
      "main": [
        [
          {
            "node": "VerifySecret",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "VerifySecret": {
      "main": [
        [
          {
            "node": "SaveInboundMessage",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "SaveInboundMessage": {
      "main": [
        [
          {
            "node": "DebounceWait",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "DebounceWait": {
      "main": [
        [
          {
            "node": "CheckNewer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "CheckNewer": {
      "main": [
        [
          {
            "node": "IsNewest",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IsNewest": {
      "main": [
        [
          {
            "node": "FetchHistory",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "DropSupercededExecution",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "FetchHistory": {
      "main": [
        [
          {
            "node": "OpenAI - Formulate Unified Reply",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI - Formulate Unified Reply": {
      "main": [
        [
          {
            "node": "WhatsApp - Send Unified Reply",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  }
}
