{
  "name": "WebHS — Diagnostico Worker",
  "nodes": [
    {
      "id": "a1b2c3d4-0001-0000-0000-000000000001",
      "name": "A cada 5 minutos",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [240, 400],
      "parameters": {
        "rule": {
          "interval": [{ "field": "minutes", "minutesInterval": 5 }]
        }
      }
    },
    {
      "id": "a1b2c3d4-0001-0000-0000-000000000002",
      "name": "Fetch Job",
      "type": "n8n-nodes-base.mySql",
      "typeVersion": 2.4,
      "position": [460, 400],
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT * FROM diagnostico_queue WHERE status = 'pending' ORDER BY created_at ASC LIMIT 1"
      },
      "credentials": {
        "mySql": { "id": "CREDENTIAL_MYSQL_ID", "name": "WebHS LP DB" }
      }
    },
    {
      "id": "a1b2c3d4-0001-0000-0000-000000000003",
      "name": "Tem job?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [680, 400],
      "parameters": {
        "conditions": {
          "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict" },
          "conditions": [
            {
              "id": "cond-01",
              "leftValue": "={{ $json.id }}",
              "rightValue": "",
              "operator": { "type": "string", "operation": "exists", "singleValue": true }
            }
          ],
          "combinator": "and"
        }
      }
    },
    {
      "id": "a1b2c3d4-0001-0000-0000-000000000004",
      "name": "Mark Processing",
      "type": "n8n-nodes-base.mySql",
      "typeVersion": 2.4,
      "position": [900, 280],
      "parameters": {
        "operation": "executeQuery",
        "query": "UPDATE diagnostico_queue SET status = 'processing' WHERE id = {{ $json.id }}"
      },
      "credentials": {
        "mySql": { "id": "CREDENTIAL_MYSQL_ID", "name": "WebHS LP DB" }
      }
    },
    {
      "id": "a1b2c3d4-0001-0000-0000-000000000005",
      "name": "PSI Mobile",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [1120, 280],
      "onError": "continueRegularOutput",
      "parameters": {
        "method": "GET",
        "url": "=https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url={{ encodeURIComponent($('Fetch Job').first().json.url) }}&strategy=mobile&key=YOUR_PSI_API_KEY",
        "options": { "timeout": 60000, "response": { "response": { "fullResponse": false } } }
      }
    },
    {
      "id": "a1b2c3d4-0001-0000-0000-000000000006",
      "name": "PSI Desktop",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [1340, 280],
      "onError": "continueRegularOutput",
      "parameters": {
        "method": "GET",
        "url": "=https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url={{ encodeURIComponent($('Fetch Job').first().json.url) }}&strategy=desktop&key=YOUR_PSI_API_KEY",
        "options": { "timeout": 60000, "response": { "response": { "fullResponse": false } } }
      }
    },
    {
      "id": "a1b2c3d4-0001-0000-0000-000000000007",
      "name": "Check Headers",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [1560, 280],
      "onError": "continueRegularOutput",
      "parameters": {
        "method": "GET",
        "url": "={{ $('Fetch Job').first().json.url }}",
        "options": {
          "timeout": 20000,
          "response": {
            "response": {
              "fullResponse": true,
              "responseFormat": "text"
            }
          },
          "redirect": { "redirect": { "followRedirects": true, "maxRedirects": 5 } }
        }
      }
    },
    {
      "id": "a1b2c3d4-0001-0000-0000-000000000008",
      "name": "Build Report",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [1780, 280],
      "parameters": {
        "jsCode": "// ── Helpers ──────────────────────────────────────────────────────────────\nfunction scoreColor(s) {\n  return s >= 90 ? '#0cce6b' : s >= 50 ? '#ffa400' : '#ff4e42';\n}\nfunction scoreLabel(s) {\n  return s >= 90 ? 'Bom' : s >= 50 ? 'A melhorar' : 'Fraco';\n}\nfunction cwvColor(s) {\n  if (s === null || s === undefined) return '#718096';\n  return s >= 0.9 ? '#0cce6b' : s >= 0.5 ? '#ffa400' : '#ff4e42';\n}\nfunction cwvLabel(s) {\n  if (s === null || s === undefined) return 'N/D';\n  return s >= 0.9 ? '✓ Bom' : s >= 0.5 ? '⚠ A melhorar' : '✗ Fraco';\n}\nfunction phpEol(v) {\n  if (!v) return false;\n  const clean = v.split('-')[0];\n  return clean.localeCompare('8.1', undefined, { numeric: true }) < 0;\n}\nfunction scoreRing(score, color) {\n  const C = 201.06;\n  const offset = score != null ? (C - (score / 100) * C).toFixed(2) : C;\n  const label = score != null ? String(score) : '–';\n  return `<svg viewBox=\"0 0 80 80\" width=\"80\" height=\"80\" style=\"display:block;margin:0 auto\">`\n    + `<circle cx=\"40\" cy=\"40\" r=\"32\" fill=\"none\" stroke=\"rgba(255,255,255,.06)\" stroke-width=\"6\"/>`\n    + `<circle cx=\"40\" cy=\"40\" r=\"32\" fill=\"none\" stroke=\"${color}\" stroke-width=\"6\" stroke-linecap=\"round\"`\n    + ` stroke-dasharray=\"${C}\" stroke-dashoffset=\"${offset}\" transform=\"rotate(-90 40 40)\"/>`\n    + `<text x=\"40\" y=\"45\" text-anchor=\"middle\" fill=\"#fff\" font-size=\"18\" font-weight=\"800\"`\n    + ` font-family=\"Helvetica,Arial,sans-serif\">${label}</text>`\n    + `</svg>`;\n}\n\n// ── Input data ────────────────────────────────────────────────────────────\nconst job     = $('Fetch Job').first().json;\nconst psiMRaw = $('PSI Mobile').first().json;\nconst psiDRaw = $('PSI Desktop').first().json;\nconst hdCheck = $('Check Headers').first().json;\n\n// ── Parse PSI ─────────────────────────────────────────────────────────────\nfunction parsePSI(data) {\n  if (!data || data.error || !data.lighthouseResult) return null;\n  const audits = data.lighthouseResult.audits || {};\n  const score  = Math.round((data.lighthouseResult.categories?.performance?.score || 0) * 100);\n  const map = {\n    fcp: 'first-contentful-paint', lcp: 'largest-contentful-paint',\n    tbt: 'total-blocking-time',   cls: 'cumulative-layout-shift',\n    inp: 'interaction-to-next-paint', si: 'speed-index', ttfb: 'server-response-time',\n  };\n  const cwv = {};\n  for (const [k, ak] of Object.entries(map)) {\n    const a = audits[ak];\n    if (a) cwv[k] = { value: a.displayValue || 'N/D', score: a.score ?? null };\n  }\n  const oppKeys = [\n    ['render-blocking-resources',  'Recursos a bloquear renderização'],\n    ['uses-optimized-images',      'Imagens não otimizadas'],\n    ['uses-text-compression',      'Compressão de texto em falta'],\n    ['uses-long-cache-ttl',        'Cache TTL demasiado curto'],\n    ['unused-javascript',          'JavaScript não utilizado'],\n    ['unused-css-rules',           'CSS não utilizado'],\n    ['preload-lcp-image',          'Imagem LCP sem preload'],\n  ];\n  const opps = oppKeys\n    .filter(([k]) => audits[k] && audits[k].score != null && audits[k].score < 0.9)\n    .map(([k, label]) => ({ label, score: audits[k].score }))\n    .sort((a, b) => a.score - b.score)\n    .slice(0, 5);\n  return { score, cwv, opps };\n}\n\nconst psiM   = parsePSI(psiMRaw);\nconst psiD   = parsePSI(psiDRaw);\nconst hasPSI = !!(psiM && psiD);\n\n// ── Parse headers ─────────────────────────────────────────────────────────\nconst rawHeaders = hdCheck.headers || {};\nconst h = Object.fromEntries(Object.entries(rawHeaders).map(([k,v]) => [k.toLowerCase(), v]));\nconst ttfb        = Math.round((hdCheck.$responseTime || 0));\nconst phpMatch    = (h['x-powered-by'] || '').match(/PHP\\/([\\d.]+)/i);\nconst phpVersion  = phpMatch ? phpMatch[1] : null;\nconst compression = h['content-encoding'] || null;\nconst cacheStatus = h['cf-cache-status'] || h['x-cache'] || h['x-litespeed-cache'] || null;\nconst cacheHit    = cacheStatus ? /hit/i.test(cacheStatus) : false;\nconst cdn         = h['cf-ray'] ? 'Cloudflare' : h['x-amz-cf-id'] ? 'CloudFront' : h['x-cdn'] || null;\nconst server      = h['server'] || null;\nconst ssl         = (job.url || '').startsWith('https://');\n\n// ── Build report HTML ─────────────────────────────────────────────────────\nconst hash    = Array.from(crypto.getRandomValues(new Uint8Array(16))).map(b => b.toString(16).padStart(2,'0')).join('');\nconst date    = new Date().toLocaleDateString('pt-PT', { day:'2-digit', month:'2-digit', year:'numeric', hour:'2-digit', minute:'2-digit' });\nconst expiry  = new Date(Date.now() + 30*24*60*60*1000).toLocaleDateString('pt-PT');\nconst nome    = (job.nome || '').replace(/</g,'&lt;').replace(/>/g,'&gt;');\nconst urlEsc  = (job.url  || '').replace(/\"/g,'&quot;');\n\nconst ringMob  = scoreRing(hasPSI ? psiM.score : null, hasPSI ? scoreColor(psiM.score) : '#718096');\nconst ringDesk = scoreRing(hasPSI ? psiD.score : null, hasPSI ? scoreColor(psiD.score) : '#718096');\n\n// CWV rows\nconst cwvKeys = [['fcp','FCP'],['lcp','LCP'],['inp','INP'],['cls','CLS'],['tbt','TBT'],['ttfb','TTFB (PSI)'],['si','Speed Index']];\nlet cwvHtml = '';\nif (hasPSI) {\n  for (const [k, label] of cwvKeys) {\n    const m = psiM.cwv[k], d = psiD.cwv[k];\n    cwvHtml += `<tr>\n      <td style=\"padding:10px 16px;font-weight:600;color:#e2e8f0\">${label}</td>\n      <td style=\"padding:10px 16px;text-align:center;color:${cwvColor(m?.score)}\">${m?.value||'N/D'}<br><small>${cwvLabel(m?.score)}</small></td>\n      <td style=\"padding:10px 16px;text-align:center;color:${cwvColor(d?.score)}\">${d?.value||'N/D'}<br><small>${cwvLabel(d?.score)}</small></td>\n    </tr>`;\n  }\n}\n\n// Opportunities\nconst allOpps = hasPSI ? [...psiM.opps, ...psiD.opps].reduce((acc, o) => {\n  if (!acc.find(x => x.label === o.label)) acc.push(o); return acc;\n}, []).slice(0,6) : [];\nconst oppHtml = allOpps.length\n  ? allOpps.map(o => `<div style=\"display:flex;align-items:center;gap:12px;padding:10px 0;border-bottom:1px solid #1a2640\"><span style=\"width:8px;height:8px;border-radius:50%;background:${o.score<0.5?'#ff4e42':'#ffa400'};flex-shrink:0\"></span><span style=\"font-size:13px;color:#a0aec0\">${o.label}</span></div>`).join('')\n  : '<p style=\"color:#4a5568;font-size:13px\">' + (hasPSI ? 'Nenhuma oportunidade crítica.' : 'PSI indisponível — API key não configurada.') + '</p>';\n\n// Server checks\nconst checks = [\n  ['TTFB', ttfb+'ms', ttfb<800?'#0cce6b':ttfb<1800?'#ffa400':'#ff4e42'],\n  ['PHP', phpVersion?(phpVersion+(phpEol(phpVersion)?' ⚠ EOL':' ✓')):'Não detetado', phpVersion?(phpEol(phpVersion)?'#ff4e42':'#0cce6b'):'#718096'],\n  ['SSL', ssl?'Ativo':'Inativo', ssl?'#0cce6b':'#ff4e42'],\n  ['Cache', cacheStatus||'Não detetado', cacheHit?'#0cce6b':'#ffa400'],\n  ['Compressão', compression?compression.toUpperCase():'Em falta', compression?'#0cce6b':'#ffa400'],\n  ['CDN', cdn||'Não detetado', cdn?'#0cce6b':'#718096'],\n  ['Servidor', server||'Oculto', '#718096'],\n];\nconst checksHtml = checks.map(([l,v,c]) =>\n  `<tr><td style=\"padding:10px 16px;color:#a0aec0;font-size:13px\">${l}</td><td style=\"padding:10px 16px;font-weight:700;font-size:13px;color:${c}\">${v}</td></tr>`\n).join('');\n\nconst psiNotice = !hasPSI\n  ? '<div style=\"background:rgba(212,137,10,.12);border:1px solid rgba(212,137,10,.3);border-radius:8px;padding:14px 18px;margin-bottom:24px;font-size:13px;color:#d4890a\">⚠ Score PageSpeed indisponível. A equipa WebHS incluirá a análise PSI completa.</div>'\n  : '';\n\nconst cwvSection = hasPSI ? `\n  <div style=\"background:#0c1220;border:1px solid rgba(29,113,184,.2);border-radius:12px;overflow:hidden;margin-bottom:24px\">\n    <div style=\"padding:18px 20px;border-bottom:1px solid rgba(29,113,184,.15)\"><p style=\"font-size:13px;font-weight:700;color:#fff\">Core Web Vitals</p></div>\n    <table style=\"width:100%;border-collapse:collapse\">\n      <thead><tr>\n        <th style=\"padding:10px 16px;text-align:left;font-size:11px;color:#5a6a84;font-weight:600;text-transform:uppercase\">Métrica</th>\n        <th style=\"padding:10px 16px;text-align:center;font-size:11px;color:#5a6a84;font-weight:600;text-transform:uppercase\">📱 Mobile</th>\n        <th style=\"padding:10px 16px;text-align:center;font-size:11px;color:#5a6a84;font-weight:600;text-transform:uppercase\">💻 Desktop</th>\n      </tr></thead>\n      <tbody>${cwvHtml}</tbody>\n    </table>\n  </div>` : '';\n\nconst reportHtml = `<!DOCTYPE html>\n<html lang=\"pt\">\n<head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n<meta name=\"robots\" content=\"noindex,nofollow\">\n<title>Relatório de Diagnóstico WordPress — WebHS</title>\n<style>*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif;background:#060912;color:#d8e0ed;line-height:1.6}table{border-collapse:collapse;width:100%}tr:nth-child(even){background:rgba(255,255,255,.03)}</style>\n</head>\n<body><div style=\"max-width:720px;margin:0 auto;padding:20px\">\n  <div style=\"background:#0c1220;border:1px solid rgba(29,113,184,.3);border-radius:12px;overflow:hidden;margin-bottom:24px\">\n    <div style=\"background:#1D71B8;padding:24px 32px;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:12px\">\n      <div style=\"font-size:22px;font-weight:800;color:#fff\">Web<span style=\"color:#a8d4f5\">HS</span></div>\n      <div style=\"font-size:12px;color:rgba(255,255,255,.7);text-align:right\">Diagnóstico WordPress<br><strong style=\"color:#fff\">${date}</strong></div>\n    </div>\n    <div style=\"padding:24px 32px\">\n      <p style=\"font-size:12px;color:#1D71B8;font-weight:700;text-transform:uppercase;letter-spacing:.1em;margin-bottom:6px\">Site analisado</p>\n      <p style=\"font-size:16px;font-weight:700;color:#fff;word-break:break-all\">${urlEsc}</p>\n      <p style=\"font-size:14px;color:#5a6a84;margin-top:4px\">Relatório para <strong style=\"color:#a0aec0\">${nome}</strong></p>\n    </div>\n  </div>\n  ${psiNotice}\n  <div style=\"display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:24px\">\n    <div style=\"background:#0c1220;border:1px solid rgba(29,113,184,.2);border-radius:12px;padding:24px;text-align:center\">\n      <p style=\"font-size:11px;color:#5a6a84;text-transform:uppercase;letter-spacing:.1em;margin-bottom:16px\">📱 Mobile</p>\n      ${ringMob}\n      <p style=\"font-size:12px;font-weight:700;margin-top:8px;color:${hasPSI?scoreColor(psiM.score):'#718096'}\">${hasPSI?scoreLabel(psiM.score):'Pendente'}</p>\n    </div>\n    <div style=\"background:#0c1220;border:1px solid rgba(29,113,184,.2);border-radius:12px;padding:24px;text-align:center\">\n      <p style=\"font-size:11px;color:#5a6a84;text-transform:uppercase;letter-spacing:.1em;margin-bottom:16px\">💻 Desktop</p>\n      ${ringDesk}\n      <p style=\"font-size:12px;font-weight:700;margin-top:8px;color:${hasPSI?scoreColor(psiD.score):'#718096'}\">${hasPSI?scoreLabel(psiD.score):'Pendente'}</p>\n    </div>\n  </div>\n  <div style=\"background:#0c1220;border:1px solid rgba(29,113,184,.2);border-radius:12px;overflow:hidden;margin-bottom:24px\">\n    <div style=\"padding:18px 20px;border-bottom:1px solid rgba(29,113,184,.15)\"><p style=\"font-size:13px;font-weight:700;color:#fff\">Análise de Infraestrutura</p></div>\n    <table><tbody>${checksHtml}</tbody></table>\n  </div>\n  ${cwvSection}\n  <div style=\"background:#0c1220;border:1px solid rgba(29,113,184,.2);border-radius:12px;padding:20px;margin-bottom:24px\">\n    <p style=\"font-size:13px;font-weight:700;color:#fff;margin-bottom:16px\">Principais Problemas</p>\n    ${oppHtml}\n  </div>\n  <div style=\"background:linear-gradient(135deg,#0c1a2e,#0d2040);border:1px solid rgba(29,113,184,.4);border-radius:12px;padding:32px;text-align:center;margin-bottom:24px\">\n    <p style=\"font-size:18px;font-weight:800;color:#fff;margin-bottom:8px\">Resolvemos tudo isto para ti</p>\n    <p style=\"font-size:14px;color:#5a6a84;margin-bottom:24px\">PHP 8.3+, LiteSpeed + LSCache, infraestrutura própria em Portugal. Migração gratuita incluída.</p>\n    <a href=\"https://webhs.pt/contacto?utm_source=report&utm_medium=cta&utm_campaign=diagnostico\" style=\"display:inline-block;background:#1D71B8;color:#fff;font-weight:700;font-size:15px;padding:14px 32px;border-radius:8px;text-decoration:none\">Falar com a nossa equipa →</a>\n  </div>\n  <div style=\"text-align:center;padding:16px;font-size:12px;color:#2e3a4e\">\n    <strong style=\"color:#1D71B8\">WebHS®</strong> · WebSP, Lda · Lisboa · ISO 9001 · Este relatório expira em ${expiry}\n  </div>\n</div></body></html>`;\n\n// ── Email HTML ─────────────────────────────────────────────────────────────\nconst scoreMStr   = hasPSI ? String(psiM.score) : 'N/D';\nconst scoreMColor = hasPSI ? scoreColor(psiM.score) : '#718096';\nconst ttfbColor   = ttfb < 800 ? '#0cce6b' : ttfb < 1800 ? '#ffa400' : '#ff4e42';\nconst reportUrl   = `https://lp.webhs.pt/reports/${hash}.html?utm_source=email&utm_medium=relatorio&utm_campaign=diagnostico-${job.source||'wordpress'}&utm_content=${job.id}`;\n\nconst emailHtml = `<!DOCTYPE html><html lang=\"pt\"><head><meta charset=\"UTF-8\"></head><body style=\"margin:0;padding:0;background:#f0f4f8;font-family:'Helvetica Neue',Helvetica,Arial,sans-serif\">\n<table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" style=\"background:#f0f4f8;padding:40px 20px\"><tr><td align=\"center\">\n<table width=\"100%\" style=\"max-width:560px;background:#ffffff;border-radius:12px;overflow:hidden;box-shadow:0 4px 24px rgba(0,0,0,.08)\">\n  <tr><td style=\"background:#1D71B8;padding:28px 40px\"><div style=\"font-size:22px;font-weight:800;color:#fff\">Web<span style=\"color:#a8d4f5\">HS</span></div></td></tr>\n  <tr><td style=\"padding:36px 40px 28px\">\n    <p style=\"margin:0 0 6px;font-size:12px;color:#1D71B8;font-weight:700;text-transform:uppercase;letter-spacing:.1em\">Diagnóstico WordPress</p>\n    <h1 style=\"margin:0 0 20px;font-size:22px;font-weight:800;color:#0d1a2e\">O teu relatório está pronto, ${nome}!</h1>\n    <p style=\"margin:0 0 24px;font-size:15px;color:#4a5568;line-height:1.7\">Analisámos o teu site e o relatório completo está disponível.</p>\n    <table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" style=\"background:#f7fafc;border:1px solid #e2e8f0;border-radius:8px;margin-bottom:28px\">\n      <tr><td style=\"padding:14px 20px;border-bottom:1px solid #e2e8f0\"><p style=\"margin:0 0 2px;font-size:11px;font-weight:700;color:#718096;text-transform:uppercase\">Site</p><p style=\"margin:0;font-size:13px;color:#1D71B8;font-family:monospace\">${urlEsc}</p></td></tr>\n      <tr><td style=\"padding:0\"><table width=\"100%\"><tr>\n        <td style=\"padding:14px 20px;border-right:1px solid #e2e8f0\"><p style=\"margin:0 0 2px;font-size:11px;font-weight:700;color:#718096;text-transform:uppercase\">Score Mobile</p><p style=\"margin:0;font-size:20px;font-weight:800;color:${scoreMColor}\">${scoreMStr}</p></td>\n        <td style=\"padding:14px 20px\"><p style=\"margin:0 0 2px;font-size:11px;font-weight:700;color:#718096;text-transform:uppercase\">TTFB</p><p style=\"margin:0;font-size:20px;font-weight:800;color:${ttfbColor}\">${ttfb} ms</p></td>\n      </tr></table></td></tr>\n    </table>\n    <table width=\"100%\"><tr><td align=\"center\">\n      <a href=\"${reportUrl}\" style=\"display:inline-block;background:#1D71B8;color:#fff;font-weight:700;font-size:16px;padding:16px 36px;border-radius:8px;text-decoration:none\">Ver Relatório Completo →</a>\n    </td></tr></table>\n    <p style=\"margin:20px 0 0;font-size:12px;color:#a0aec0;text-align:center\">Relatório disponível até ${expiry}</p>\n  </td></tr>\n  <tr><td style=\"background:#f7fafc;border-top:1px solid #e2e8f0;padding:20px 40px\">\n    <p style=\"margin:0;font-size:12px;color:#a0aec0\"><strong style=\"color:#718096\">WebHS®</strong> · WebSP, Lda · ISO 9001 · <a href=\"https://webhs.pt/privacidade\" style=\"color:#1D71B8\">Privacidade</a></p>\n  </td></tr>\n</table></td></tr></table></body></html>`;\n\nreturn [{\n  json: {\n    job_id:       job.id,\n    lead_nome:    job.nome,\n    lead_email:   job.email,\n    report_hash:  hash,\n    report_url:   reportUrl,\n    report_html:  reportHtml,\n    email_html:   emailHtml,\n    email_subject: 'O teu relatório de diagnóstico WordPress está pronto — WebHS',\n    score_mobile:  hasPSI ? psiM.score : null,\n    score_desktop: hasPSI ? psiD.score : null,\n    ttfb,\n  }\n}];"
      }
    },
    {
      "id": "a1b2c3d4-0001-0000-0000-000000000009",
      "name": "Save Report File",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [2000, 280],
      "parameters": {
        "method": "POST",
        "url": "https://lp.webhs.pt/api/save-report.php",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            { "name": "X-Worker-Secret", "value": "ALTERAR_TOKEN_ALEATORIO" }
          ]
        },
        "sendBody": true,
        "contentType": "form-urlencoded",
        "bodyParameters": {
          "parameters": [
            { "name": "hash", "value": "={{ $json.report_hash }}" },
            { "name": "html", "value": "={{ $json.report_html }}" }
          ]
        }
      }
    },
    {
      "id": "a1b2c3d4-0001-0000-0000-000000000010",
      "name": "Send Email Lead",
      "type": "n8n-nodes-base.emailSend",
      "typeVersion": 2.1,
      "position": [2220, 280],
      "parameters": {
        "fromEmail": "lp@webhs.pt",
        "toEmail": "={{ $('Build Report').first().json.lead_email }}",
        "subject":  "={{ $('Build Report').first().json.email_subject }}",
        "emailType": "html",
        "message":  "={{ $('Build Report').first().json.email_html }}"
      },
      "credentials": {
        "smtp": { "id": "CREDENTIAL_SMTP_ID", "name": "WebHS SMTP" }
      }
    },
    {
      "id": "a1b2c3d4-0001-0000-0000-000000000011",
      "name": "Mark Done",
      "type": "n8n-nodes-base.mySql",
      "typeVersion": 2.4,
      "position": [2440, 280],
      "parameters": {
        "operation": "executeQuery",
        "query": "UPDATE diagnostico_queue SET status = 'done', report_hash = '{{ $('Build Report').first().json.report_hash }}', report_expires = DATE_ADD(NOW(), INTERVAL 30 DAY), result = '{}', processed_at = NOW() WHERE id = {{ $('Build Report').first().json.job_id }}"
      },
      "credentials": {
        "mySql": { "id": "CREDENTIAL_MYSQL_ID", "name": "WebHS LP DB" }
      }
    },
    {
      "id": "a1b2c3d4-0001-0000-0000-000000000012",
      "name": "Mark Error",
      "type": "n8n-nodes-base.mySql",
      "typeVersion": 2.4,
      "position": [900, 560],
      "parameters": {
        "operation": "executeQuery",
        "query": "UPDATE diagnostico_queue SET status = 'error', error_msg = 'Erro no workflow n8n', processed_at = NOW() WHERE id = {{ $('Fetch Job').first().json.id }}"
      },
      "credentials": {
        "mySql": { "id": "CREDENTIAL_MYSQL_ID", "name": "WebHS LP DB" }
      }
    }
  ],
  "connections": {
    "A cada 5 minutos": {
      "main": [[{ "node": "Fetch Job", "type": "main", "index": 0 }]]
    },
    "Fetch Job": {
      "main": [[{ "node": "Tem job?", "type": "main", "index": 0 }]]
    },
    "Tem job?": {
      "main": [
        [{ "node": "Mark Processing", "type": "main", "index": 0 }],
        []
      ]
    },
    "Mark Processing": {
      "main": [[{ "node": "PSI Mobile", "type": "main", "index": 0 }]]
    },
    "PSI Mobile": {
      "main": [[{ "node": "PSI Desktop", "type": "main", "index": 0 }]]
    },
    "PSI Desktop": {
      "main": [[{ "node": "Check Headers", "type": "main", "index": 0 }]]
    },
    "Check Headers": {
      "main": [[{ "node": "Build Report", "type": "main", "index": 0 }]]
    },
    "Build Report": {
      "main": [[{ "node": "Save Report File", "type": "main", "index": 0 }]]
    },
    "Save Report File": {
      "main": [[{ "node": "Send Email Lead", "type": "main", "index": 0 }]]
    },
    "Send Email Lead": {
      "main": [[{ "node": "Mark Done", "type": "main", "index": 0 }]]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "saveManualExecutions": true,
    "callerPolicy": "workflowsFromSameOwner",
    "errorWorkflow": ""
  },
  "active": false
}
