{
  "name": "Logixb2b — Guardrails límites LinkedIn (v2)",
  "meta": {
    "templateCredsSetupCompleted": false,
    "description": "Webhook actividad diaria → Evalúa límites → IF freno → Slack + CRM pause_linkedin. Europe/Madrid. Placeholders. Sin scrapers."
  },
  "settings": {
    "executionOrder": "v1",
    "timezone": "Europe/Madrid"
  },
  "active": false,
  "pinData": {},
  "tags": [
    {
      "name": "Logixb2b"
    },
    {
      "name": "linkedin"
    },
    {
      "name": "safety"
    }
  ],
  "nodes": [
    {
      "id": "sticky-instrucciones-logix",
      "name": "INSTRUCCIONES (conectar + VPS)",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -480,
        40
      ],
      "parameters": {
        "content": "## INSTRUCCIONES — Guardrails límites LinkedIn (v2)\n\n**Recurso:** `/recursos/guardrails-ia-ventas`\n**Guía:** /riesgos-limitaciones-automatizar-ventas-ia\n**Zona:** Europe/Madrid · `active: false` al importar (tú lo activas).\n\n### 1) Importar\n1. n8n → ⋯ → **Import from File** → este JSON.\n2. El flujo llega **inactive**. No pegues secretos en el lienzo ni en el archivo.\n\n### 2) Credenciales y configuración por nodo\n- **Webhook actividad diaria** (`webhook`): sin credencial. Tras Active, copia **URL de producción** (HTTPS del VPS/Cloud). El emisor (formulario, CRM, bot) debe POST a esa URL.\n- **Evaluar limites** (`Code`): sin credencial. Revisa límites/umbrales en el JS; no hardcodees secretos.\n- **¿Sobre limite?** (`IF`): sin credencial. Comprueba la condición (email, umbral, over_limit, etc.) con datos reales de prueba.\n- **Alerta Slack/Teams** (`HTTP Request` → Slack/Teams): crea Incoming Webhook en Slack (o Adaptive Card URL en Teams). Pega la URL en **Config** o en este nodo. Auth: none (la URL ya es secreta).\n- **CRM pause_linkedin** (`HTTP Request` CRM): Credentials → **Header Auth** / OAuth del CRM. Sustituye `crm*Url` en el nodo **Config**. Prueba con un Lead de sandbox.\n- **Registro OK** (`Set`): sin credencial. Revisa expresiones `={{ }}` y campos de salida.\n\n### 3) Orden recomendado de puesta en marcha\n1. Rellena el nodo **Config** (URLs reales, umbrales, webhooks de Slack).\n2. Crea Credentials en n8n (candado de cada nodo HTTP / Sheets / OpenAI) y **enlázalas**.\n3. Ejecuta **una vez** (Manual / Test URL del Webhook / \"Execute workflow\").\n4. Verifica CRM + Slack/Sheets (y que la IA no escriba en producción sin HITL).\n5. Solo entonces: interruptor **Active**.\n\n### 4) Producción 24/7 en VPS (UE)\nImportar en localhost no basta: webhooks y cron necesitan n8n encendido.\n\n1. VPS en UE (Hetzner/OVH/IONOS…) + Docker Compose + **Postgres** + HTTPS (Caddy/Nginx).\n2. Variables mínimas: `GENERIC_TIMEZONE=Europe/Madrid`, `WEBHOOK_URL=https://n8n.tudominio.com/`, `N8N_ENCRYPTION_KEY`, `N8N_HOST` / `N8N_PROTOCOL=https`.\n3. Firewall: solo 80/443 (+ SSH). Backups del volumen Postgres + export de workflows.\n4. Importa este JSON en la instancia de producción, vuelve a crear Credentials (no se copian solas), actualiza URLs del Config al dominio real.\n5. Pon **Active**. Prueba el Webhook de producción o espera el próximo cron.\n6. Alternativa: **n8n Cloud** (mismo JSON; Credentials en la UI Cloud).\n\n### 5) RGPD + EU AI Act (resumen)\nSi hay nodos IA sois **deployers** (Reglamento UE 2024/1689). Art. 4 alfabetización. **HITL** antes de outreach, scores masivos o pausas de cuenta. Minimiza PII en Slack/logs. Informativo — no es asesoramiento legal. /uso-responsable-de-ia-y-transparencia\n",
        "height": 1500,
        "width": 580,
        "color": 4
      }
    },
    {
      "id": "w1",
      "name": "Webhook actividad diaria",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        0,
        300
      ],
      "webhookId": "w1",
      "parameters": {
        "httpMethod": "POST",
        "path": "logix-linkedin-daily",
        "responseMode": "onReceived",
        "options": {}
      }
    },
    {
      "id": "c1",
      "name": "Evaluar limites",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        300,
        300
      ],
      "parameters": {
        "jsCode": "const i = $input.first().json;\nconst body = i.body || i;\nconst limits = { connections: 20, messages: 40, profile_views: 80 };\nconst usage = {\n  connections: Number(body.connections) || 0,\n  messages: Number(body.messages) || 0,\n  profile_views: Number(body.profile_views) || 0\n};\nconst breaches = [];\nfor (const k of Object.keys(limits)) {\n  if (usage[k] > limits[k]) breaches.push(k + ':' + usage[k] + '>' + limits[k]);\n}\nconst warn = [];\nfor (const k of Object.keys(limits)) {\n  if (usage[k] >= Math.floor(limits[k] * 0.8) && usage[k] <= limits[k]) warn.push(k);\n}\nconst over = breaches.length > 0;\nconst action = over ? 'pause_linkedin' : (warn.length ? 'slow_down' : 'ok');\nconst slackText = '[Logixb2b Guardrails] ' + (body.account || 'cuenta') + ' · ' + (body.date || '') + ' · ' + action + (breaches.length ? ' · ' + breaches.join(', ') : '');\nreturn [{ json: {\n  account: body.account || 'unknown',\n  date: body.date || new Date().toISOString().slice(0, 10),\n  usage, limits, breaches, warn, over_limit: over, action, slackText,\n  market: 'ES/UE',\n  complianceFlag: 'sin_pii_leads_solo_contadores'\n}}];"
      }
    },
    {
      "id": "i1",
      "name": "¿Sobre limite?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        600,
        300
      ],
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "loose",
            "version": 2
          },
          "conditions": [
            {
              "id": "c1",
              "leftValue": "={{ $json.over_limit }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      }
    },
    {
      "id": "h1",
      "name": "Alerta Slack/Teams",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        900,
        40
      ],
      "parameters": {
        "method": "POST",
        "url": "https://hooks.example.com/services/REEMPLAZA_SLACK",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ text: $json.slackText || ('[Logixb2b] freno LinkedIn ' + ($json.account || '')) }) }}",
        "options": {},
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "id": "",
          "name": "Alert Webhook"
        }
      }
    },
    {
      "id": "h2",
      "name": "CRM pause_linkedin",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1200,
        40
      ],
      "parameters": {
        "method": "POST",
        "url": "https://hooks.example.com/crm/pause-linkedin",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ account: $json.account, date: $json.date, action: $json.action, pause_linkedin: true, reasons: $json.breaches || [], market: 'ES/UE' }) }}",
        "options": {},
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "id": "",
          "name": "CRM Staging API"
        }
      }
    },
    {
      "id": "s1",
      "name": "Registro OK",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        900,
        560
      ],
      "parameters": {
        "mode": "manual",
        "duplicateItem": false,
        "assignments": {
          "assignments": [
            {
              "id": "f0",
              "name": "status",
              "value": "within_limits",
              "type": "string"
            },
            {
              "id": "f1",
              "name": "account",
              "value": "={{ $json.account }}",
              "type": "string"
            },
            {
              "id": "f2",
              "name": "action",
              "value": "={{ $json.action }}",
              "type": "string"
            }
          ]
        }
      }
    }
  ],
  "connections": {
    "Webhook actividad diaria": {
      "main": [
        [
          {
            "node": "Evaluar limites",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Evaluar limites": {
      "main": [
        [
          {
            "node": "¿Sobre limite?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "¿Sobre limite?": {
      "main": [
        [
          {
            "node": "Alerta Slack/Teams",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Registro OK",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Alerta Slack/Teams": {
      "main": [
        [
          {
            "node": "CRM pause_linkedin",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
