{
  "name": "Brenda - Veille Affiliation & Influence",
  "nodes": [
    {
      "id": "trigger",
      "name": "Cron Lundi 8h",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        0,
        300
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 8 * * 1"
            }
          ]
        }
      }
    },
    {
      "id": "rss_influencia",
      "name": "RSS Influencia",
      "type": "n8n-nodes-base.rssFeedRead",
      "typeVersion": 1.1,
      "position": [
        250,
        0
      ],
      "parameters": {
        "url": "https://www.influencia.net/feed/"
      }
    },
    {
      "id": "rss_strategies",
      "name": "RSS Strategies",
      "type": "n8n-nodes-base.rssFeedRead",
      "typeVersion": 1.1,
      "position": [
        250,
        150
      ],
      "parameters": {
        "url": "https://www.strategies.fr/feed"
      }
    },
    {
      "id": "rss_mntd",
      "name": "RSS MNTD",
      "type": "n8n-nodes-base.rssFeedRead",
      "typeVersion": 1.1,
      "position": [
        250,
        300
      ],
      "parameters": {
        "url": "https://www.mntd.fr/feed/"
      }
    },
    {
      "id": "rss_gensinternet",
      "name": "RSS Gens Internet",
      "type": "n8n-nodes-base.rssFeedRead",
      "typeVersion": 1.1,
      "position": [
        250,
        450
      ],
      "parameters": {
        "url": "https://gensdinternet.fr/feed/"
      }
    },
    {
      "id": "firecrawl_agent",
      "name": "Firecrawl Agent Search",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        250,
        650
      ],
      "parameters": {
        "method": "POST",
        "url": "https://api.firecrawl.dev/v2/agent",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "{\n  \"prompt\": \"Trouve les articles publi\u00e9s cette semaine (7 derniers jours) sur : marketing d'affiliation, affiliate marketing, influence marketing, influence performance, tracking, attribution, cookie-less, retail media, cashback, comparateurs, social commerce, UGC, branding, plateformes affiliation. Focus : France et UK. Retourne titre, URL, date de publication, source, et un r\u00e9sum\u00e9 court pour chaque article.\",\n  \"schema\": {\n    \"type\": \"object\",\n    \"properties\": {\n      \"articles\": {\n        \"type\": \"array\",\n        \"items\": {\n          \"type\": \"object\",\n          \"properties\": {\n            \"title\": { \"type\": \"string\" },\n            \"url\": { \"type\": \"string\" },\n            \"date\": { \"type\": \"string\" },\n            \"source\": { \"type\": \"string\" },\n            \"summary\": { \"type\": \"string\" }\n          }\n        }\n      }\n    }\n  }\n}"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "id": "merge_rss",
      "name": "Merge RSS",
      "type": "n8n-nodes-base.merge",
      "typeVersion": 3,
      "position": [
        500,
        200
      ],
      "parameters": {
        "mode": "append"
      }
    },
    {
      "id": "format_rss",
      "name": "Format RSS Articles",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        700,
        200
      ],
      "parameters": {
        "jsCode": "// Formate les articles RSS\nconst articles = $input.all().map(item => ({\n  title: item.json.title || '',\n  url: item.json.link || '',\n  date: item.json.pubDate || item.json.isoDate || '',\n  source: new URL(item.json.link || 'https://unknown.com').hostname.replace('www.', ''),\n  summary: (item.json.contentSnippet || item.json.description || '').substring(0, 200)\n}));\n\nreturn [{ json: { articles, source: 'rss' } }];"
      }
    },
    {
      "id": "wait_firecrawl",
      "name": "Wait Firecrawl",
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1.1,
      "position": [
        500,
        650
      ],
      "parameters": {
        "amount": 60,
        "unit": "seconds"
      }
    },
    {
      "id": "poll_firecrawl",
      "name": "Poll Firecrawl Status",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        700,
        650
      ],
      "parameters": {
        "method": "GET",
        "url": "=https://api.firecrawl.dev/v2/agent/{{ $('Firecrawl Agent Search').item.json.id }}",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "id": "format_firecrawl",
      "name": "Format Firecrawl Articles",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        900,
        650
      ],
      "parameters": {
        "jsCode": "// Extrait les articles de Firecrawl Agent\nconst response = $input.first().json;\nconst articles = response.data?.articles || [];\n\nreturn [{ json: { articles, source: 'firecrawl' } }];"
      }
    },
    {
      "id": "merge_all",
      "name": "Merge All Articles",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1100,
        400
      ],
      "parameters": {
        "jsCode": "// Fusionne tous les articles des diff\u00e9rentes sources\nconst allArticles = [];\n\nfor (const item of $input.all()) {\n  const articles = item.json.articles || [];\n  allArticles.push(...articles);\n}\n\n// D\u00e9duplique par URL\nconst seen = new Set();\nconst uniqueArticles = allArticles.filter(article => {\n  if (!article.url || seen.has(article.url)) return false;\n  seen.add(article.url);\n  return true;\n});\n\nconsole.log(`Total articles: ${uniqueArticles.length}`);\n\nreturn [{ json: { articles: uniqueArticles, count: uniqueArticles.length } }];"
      }
    },
    {
      "id": "ai_agent",
      "name": "AI Agent Ranking",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 1.7,
      "position": [
        1350,
        400
      ],
      "parameters": {
        "promptType": "define",
        "text": "=Tu es un expert en marketing d'affiliation et d'influence.\n\nVoici {{ $json.count }} articles collect\u00e9s cette semaine. Classe-les en 3 cat\u00e9gories :\n\n**TOP 5** : Les 5 articles les plus importants pour un professionnel de l'affiliation/influence en France.\n\u26a0\ufe0f R\u00c8GLE CRITIQUE : Maximum 2 articles de la m\u00eame source dans le Top 5. Diversifie les sources.\n\n**RADAR** (10-15 articles) : Articles int\u00e9ressants \u00e0 suivre.\n\u26a0\ufe0f M\u00eame r\u00e8gle : \u00e9vite de surrepr\u00e9senter une seule source.\n\n**SIGNAUX FAIBLES** (3 max) : Tendances \u00e9mergentes, nouveaux acteurs, innovations.\n\nCrit\u00e8res de s\u00e9lection :\n- Impact business pour l'affiliation/influence en France/UK\n- Nouveaut\u00e9 de l'information\n- Pertinence strat\u00e9gique\n- DIVERSIT\u00c9 DES SOURCES (obligatoire)\n\nPour chaque article TOP 5, g\u00e9n\u00e8re :\n- title: le titre\n- url: l'URL\n- source: la source\n- summary: R\u00e9sum\u00e9 (2-3 lignes)\n- why_important: \"Pourquoi c'est important\" (1-2 lignes)\n- implication: \"Implication / Next step\" (1 ligne)\n\nPour RADAR et SIGNAUX FAIBLES : title, url, source, summary (1 ligne).\n\nR\u00e9ponds UNIQUEMENT en JSON valide avec cette structure exacte :\n{\n  \"top5\": [...],\n  \"radar\": [...],\n  \"signaux_faibles\": [...]\n}\n\nArticles \u00e0 classer :\n{{ JSON.stringify($json.articles, null, 2) }}"
      }
    },
    {
      "id": "grok_model",
      "name": "xAI Grok",
      "type": "@n8n/n8n-nodes-langchain.lmChatXAiGrok",
      "typeVersion": 1,
      "position": [
        1200,
        600
      ],
      "parameters": {
        "model": "grok-2-1212",
        "options": {
          "temperature": 0.3
        }
      },
      "credentials": {
        "xAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "id": "parse_ranking",
      "name": "Parse Ranking JSON",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1600,
        400
      ],
      "parameters": {
        "jsCode": "// Parse la r\u00e9ponse JSON du LLM\nconst response = $input.first().json.output || $input.first().json.text || $input.first().json;\n\nlet ranking;\ntry {\n  if (typeof response === 'object' && response.top5) {\n    ranking = response;\n  } else if (typeof response === 'string') {\n    // Extrait le JSON de la r\u00e9ponse\n    const jsonMatch = response.match(/\\{[\\s\\S]*\\}/);\n    ranking = JSON.parse(jsonMatch ? jsonMatch[0] : response);\n  } else {\n    ranking = response;\n  }\n} catch (e) {\n  throw new Error('Impossible de parser la r\u00e9ponse JSON: ' + e.message + '\\nResponse: ' + JSON.stringify(response).substring(0, 500));\n}\n\nif (!ranking.top5 || !Array.isArray(ranking.top5)) {\n  throw new Error('Format invalide: top5 manquant');\n}\n\nreturn [{ json: ranking }];"
      }
    },
    {
      "id": "generate_html",
      "name": "Generate Email HTML",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1850,
        400
      ],
      "parameters": {
        "jsCode": "const { top5, radar, signaux_faibles } = $input.first().json;\n\nconst today = new Date();\nconst weekStart = new Date(today);\nweekStart.setDate(today.getDate() - today.getDay() + 1);\nconst dateStr = weekStart.toLocaleDateString('fr-FR', { day: 'numeric', month: 'long', year: 'numeric' });\n\nlet html = `\n<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"utf-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n</head>\n<body style=\"margin: 0; padding: 0; background-color: #f5f5f5;\">\n<div style=\"font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif; max-width: 700px; margin: 0 auto; padding: 20px; background: white;\">\n  \n  <div style=\"text-align: center; padding: 20px 0; border-bottom: 3px solid #e74c3c;\">\n    <h1 style=\"color: #333; margin: 0; font-size: 28px;\">\ud83c\udfaf Veille Affiliation & Influence</h1>\n    <p style=\"color: #888; margin: 10px 0 0 0;\">Semaine du ${dateStr}</p>\n  </div>\n  \n  <div style=\"padding: 30px 0;\">\n    <h2 style=\"color: #e74c3c; border-bottom: 2px solid #e74c3c; padding-bottom: 10px;\">\ud83c\udfc6 TOP 5 - \u00c0 LIRE ABSOLUMENT</h2>\n`;\n\n// Top 5\n(top5 || []).forEach((article, i) => {\n  html += `\n    <div style=\"background: #fafafa; padding: 20px; margin: 20px 0; border-radius: 8px; border-left: 4px solid #e74c3c;\">\n      <h3 style=\"margin: 0 0 10px 0; color: #333; font-size: 18px;\">${i + 1}. ${article.title || 'Sans titre'}</h3>\n      <p style=\"color: #888; font-size: 12px; margin: 0 0 15px 0;\">\ud83d\udcf0 ${article.source || 'Source inconnue'}</p>\n      <p style=\"margin: 0 0 15px 0; color: #444; line-height: 1.6;\">${article.summary || ''}</p>\n      ${article.why_important ? `<p style=\"margin: 0 0 8px 0; color: #555;\"><strong>\ud83d\udca1 Pourquoi c'est important :</strong> ${article.why_important}</p>` : ''}\n      ${article.implication ? `<p style=\"margin: 0 0 15px 0; color: #555;\"><strong>\u27a1\ufe0f Implication :</strong> ${article.implication}</p>` : ''}\n      <a href=\"${article.url || '#'}\" style=\"color: #3498db; text-decoration: none; font-weight: bold;\">\ud83d\udd17 Lire l'article \u2192</a>\n    </div>\n  `;\n});\n\n// Radar\nhtml += `\n    <h2 style=\"color: #3498db; border-bottom: 2px solid #3498db; padding-bottom: 10px; margin-top: 40px;\">\ud83d\udce1 SOUS LE RADAR</h2>\n    <ul style=\"padding-left: 0; list-style: none;\">\n`;\n\n(radar || []).forEach(article => {\n  html += `\n      <li style=\"margin: 15px 0; padding: 15px; background: #f8f9fa; border-radius: 6px;\">\n        <a href=\"${article.url || '#'}\" style=\"color: #333; text-decoration: none; font-weight: 600; font-size: 15px;\">${article.title || 'Sans titre'}</a>\n        <span style=\"color: #888; font-size: 12px;\"> (${article.source || '?'})</span>\n        <p style=\"color: #666; font-size: 13px; margin: 8px 0 0 0;\">${article.summary || ''}</p>\n      </li>`;\n});\n\nhtml += `</ul>`;\n\n// Signaux faibles\nhtml += `\n    <h2 style=\"color: #9b59b6; border-bottom: 2px solid #9b59b6; padding-bottom: 10px; margin-top: 40px;\">\ud83d\udd2e SIGNAUX FAIBLES</h2>\n    <ul style=\"padding-left: 0; list-style: none;\">\n`;\n\n(signaux_faibles || []).forEach(article => {\n  html += `\n      <li style=\"margin: 15px 0; padding: 15px; background: #f5f0f9; border-radius: 6px; border-left: 3px solid #9b59b6;\">\n        <a href=\"${article.url || '#'}\" style=\"color: #333; text-decoration: none; font-weight: 600;\">${article.title || 'Sans titre'}</a>\n        <span style=\"color: #888; font-size: 12px;\"> (${article.source || '?'})</span>\n        <p style=\"color: #666; font-size: 13px; margin: 8px 0 0 0;\">${article.summary || ''}</p>\n      </li>`;\n});\n\nhtml += `\n    </ul>\n  </div>\n  \n  <div style=\"text-align: center; padding: 20px; border-top: 1px solid #eee; margin-top: 30px;\">\n    <p style=\"color: #888; font-size: 12px; margin: 0;\">Brenda, ta veille IA \ud83e\udd16</p>\n    <p style=\"color: #aaa; font-size: 11px; margin: 5px 0 0 0;\">G\u00e9n\u00e9r\u00e9e automatiquement chaque lundi</p>\n  </div>\n  \n</div>\n</body>\n</html>\n`;\n\nreturn [{ \n  json: { \n    html, \n    subject: `\ud83c\udfaf Veille Affiliation & Influence - Semaine du ${dateStr}`,\n    stats: {\n      top5: (top5 || []).length,\n      radar: (radar || []).length,\n      signaux_faibles: (signaux_faibles || []).length\n    }\n  } \n}];"
      }
    },
    {
      "id": "send_gmail",
      "name": "Send Gmail",
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2.1,
      "position": [
        2100,
        400
      ],
      "parameters": {
        "operation": "send",
        "sendTo": "TON_EMAIL@gmail.com",
        "subject": "={{ $json.subject }}",
        "emailType": "html",
        "message": "={{ $json.html }}"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      }
    }
  ],
  "connections": {
    "Cron Lundi 8h": {
      "main": [
        [
          {
            "node": "RSS Influencia",
            "type": "main",
            "index": 0
          },
          {
            "node": "RSS Strategies",
            "type": "main",
            "index": 0
          },
          {
            "node": "RSS MNTD",
            "type": "main",
            "index": 0
          },
          {
            "node": "RSS Gens Internet",
            "type": "main",
            "index": 0
          },
          {
            "node": "Firecrawl Agent Search",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "RSS Influencia": {
      "main": [
        [
          {
            "node": "Merge RSS",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "RSS Strategies": {
      "main": [
        [
          {
            "node": "Merge RSS",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "RSS MNTD": {
      "main": [
        [
          {
            "node": "Merge RSS",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "RSS Gens Internet": {
      "main": [
        [
          {
            "node": "Merge RSS",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge RSS": {
      "main": [
        [
          {
            "node": "Format RSS Articles",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format RSS Articles": {
      "main": [
        [
          {
            "node": "Merge All Articles",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Firecrawl Agent Search": {
      "main": [
        [
          {
            "node": "Wait Firecrawl",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait Firecrawl": {
      "main": [
        [
          {
            "node": "Poll Firecrawl Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Poll Firecrawl Status": {
      "main": [
        [
          {
            "node": "Format Firecrawl Articles",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Firecrawl Articles": {
      "main": [
        [
          {
            "node": "Merge All Articles",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge All Articles": {
      "main": [
        [
          {
            "node": "AI Agent Ranking",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "xAI Grok": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent Ranking",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "AI Agent Ranking": {
      "main": [
        [
          {
            "node": "Parse Ranking JSON",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Ranking JSON": {
      "main": [
        [
          {
            "node": "Generate Email HTML",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Email HTML": {
      "main": [
        [
          {
            "node": "Send Gmail",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "staticData": null,
  "tags": [],
  "triggerCount": 1
}