{
  "name": "Car Scanner - מגרש AI",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "GET",
        "path": "car-scanner",
        "responseMode": "responseNode",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        0,
        0
      ],
      "id": "wh-app",
      "name": "Webhook - אפליקציה"
    },
    {
      "parameters": {
        "jsCode": "\nconst html = `<!doctype html><html dir=\"rtl\" lang=\"he\"><head><meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1\">\n<title>מגרש AI · סריקת רכב</title>\n<link href=\"https://fonts.googleapis.com/css2?family=Heebo:wght@400;500;700;900&display=swap\" rel=\"stylesheet\">\n<style>\n* { box-sizing: border-box; margin: 0; }\nbody { font-family: 'Heebo', sans-serif; background: #0b0e14; color: #e8eaf0; min-height: 100vh; padding: 28px 18px 60px; max-width: 560px; margin: 0 auto; }\nh1 { font-size: 26px; font-weight: 900; background: linear-gradient(90deg, #7dd3fc, #c084fc); -webkit-background-clip: text; background-clip: text; color: transparent; }\n.sub { color: #8b93a7; font-size: 14px; margin: 6px 0 26px; }\n.snap { width: 100%; border: 0; border-radius: 16px; padding: 22px; font-family: inherit; font-size: 18px; font-weight: 900; cursor: pointer; background: linear-gradient(90deg, #7dd3fc, #c084fc); color: #08111f; }\n.snap:disabled { opacity: .5; }\n.hint { text-align: center; color: #58607a; font-size: 12px; margin-top: 10px; }\n#prev { width: 100%; border-radius: 14px; margin-top: 18px; display: none; border: 1px solid #262d3a; }\n.spin { display: none; text-align: center; color: #8b93a7; margin-top: 20px; font-size: 14px; }\n.spin i { display: inline-block; width: 14px; height: 14px; border: 2px solid #7dd3fc; border-top-color: transparent; border-radius: 50%; animation: r 0.8s linear infinite; vertical-align: -2px; margin-inline-end: 8px; }\n@keyframes r { to { transform: rotate(360deg) } }\n.card { background: #131826; border: 1px solid #262d3a; border-radius: 16px; padding: 18px; margin-top: 18px; display: none; }\n.card h2 { font-size: 20px; font-weight: 900; }\n.conf { display: inline-block; font-size: 12px; font-weight: 700; border-radius: 99px; padding: 2px 10px; margin-inline-start: 8px; vertical-align: 3px; }\n.meta { color: #8b93a7; font-size: 13px; margin-top: 4px; }\n.match { background: #10141d; border: 1px solid #1f2739; border-radius: 12px; padding: 12px 14px; margin-top: 10px; display: flex; justify-content: space-between; align-items: center; gap: 10px; }\n.match .l b { font-size: 15px; } .match .l div { font-size: 12px; color: #8b93a7; margin-top: 2px; }\n.match .p { font-size: 17px; font-weight: 900; color: #7dd3fc; white-space: nowrap; }\n.match .st { font-size: 10px; border-radius: 99px; padding: 2px 8px; margin-inline-start: 6px; vertical-align: 2px; }\n.est { border: 1px dashed #262d3a; border-radius: 12px; padding: 12px 14px; margin-top: 12px; color: #c6cbd8; font-size: 14px; }\n.err { color: #ff5c5c; }\n.again { width: 100%; margin-top: 16px; background: none; border: 1px solid #262d3a; color: #e8eaf0; border-radius: 12px; padding: 12px; font-family: inherit; cursor: pointer; display: none; }\n.foot { text-align: center; color: #58607a; font-size: 11px; margin-top: 34px; font-family: monospace; direction: ltr; }\n</style></head><body>\n<h1>מגרש AI 🚗</h1>\n<div class=\"sub\">צלמו רכב - הסוכן יזהה את הדגם ויבדוק מה יש לנו במלאי</div>\n<input type=\"file\" accept=\"image/*\" capture=\"environment\" id=\"cam\" hidden>\n<button class=\"snap\" id=\"snapBtn\" onclick=\"document.getElementById('cam').click()\">📷 צלמו רכב</button>\n<div class=\"hint\">אפשר גם לבחור תמונה קיימת מהגלריה</div>\n<img id=\"prev\">\n<div class=\"spin\" id=\"spin\"><i></i>הסוכן מזהה את הרכב ובודק מלאי...</div>\n<div class=\"card\" id=\"result\"></div>\n<button class=\"again\" id=\"again\" onclick=\"location.reload()\">↻ סריקה נוספת</button>\n<div class=\"foot\">n8n + Claude Vision + Data Table · self-hosted by Ilan</div>\n<script>\nconst cam = document.getElementById('cam');\ncam.onchange = async () => {\n  const f = cam.files[0]; if (!f) return;\n  const img = new Image();\n  img.src = URL.createObjectURL(f);\n  await img.decode();\n  const scale = Math.min(1, 1280 / Math.max(img.width, img.height));\n  const c = document.createElement('canvas');\n  c.width = Math.round(img.width * scale); c.height = Math.round(img.height * scale);\n  c.getContext('2d').drawImage(img, 0, 0, c.width, c.height);\n  const dataUrl = c.toDataURL('image/jpeg', 0.82);\n  const prev = document.getElementById('prev'); prev.src = dataUrl; prev.style.display = 'block';\n  document.getElementById('snapBtn').disabled = true;\n  document.getElementById('spin').style.display = 'block';\n  document.getElementById('result').style.display = 'none';\n  try {\n    const res = await fetch('/webhook/car-scan', { method: 'POST', headers: { 'Content-Type': 'application/json' },\n      body: JSON.stringify({ image: dataUrl.split(',')[1] }) });\n    const d = await res.json();\n    render(d);\n  } catch (e) {\n    render({ ok: false, error: String(e) });\n  }\n  document.getElementById('spin').style.display = 'none';\n  document.getElementById('again').style.display = 'block';\n};\nconst fmt = n => new Intl.NumberFormat('he-IL').format(n);\nconst stMap = { available: ['זמין', '#34d399'], reserved: ['שמור', '#ffb020'], sold: ['נמכר', '#ff5c5c'] };\nfunction render(d) {\n  const el = document.getElementById('result');\n  el.style.display = 'block';\n  if (!d.ok) { el.innerHTML = '<div class=\"err\">לא הצלחתי לזהות: ' + (d.error || 'שגיאה') + '</div>'; return; }\n  const id = d.identification;\n  const cc = id.confidence >= 75 ? '#34d399' : id.confidence >= 45 ? '#ffb020' : '#ff5c5c';\n  let h = '<h2>' + id.make + ' ' + id.model + ' <span class=\"conf\" style=\"color:' + cc + ';background:' + cc + '22\">' + id.confidence + '%</span></h2>';\n  h += '<div class=\"meta\">שנתון משוער: ' + id.year_est + (id.color ? ' · ' + id.color : '') + (id.body_type ? ' · ' + id.body_type : '') + '</div>';\n  if (d.matches.length) {\n    h += '<div class=\"meta\" style=\"margin-top:14px;font-weight:700;color:#e8eaf0\">🎯 נמצאו ' + d.matches.length + ' במלאי:</div>';\n    for (const m of d.matches) {\n      const [sl, sc] = stMap[m.status] || [m.status, '#888'];\n      h += '<div class=\"match\"><div class=\"l\"><b>' + m.make + ' ' + m.model + ' ' + m.year + '</b><span class=\"st\" style=\"color:' + sc + ';background:' + sc + '22\">' + sl + '</span><div>' + m.trim + ' · ' + m.color + ' · ' + fmt(m.km) + ' ק\"מ</div></div><div class=\"p\">₪' + fmt(m.price) + '</div></div>';\n    }\n  } else {\n    h += '<div class=\"est\">אין כרגע התאמה במלאי.' + (id.market_price_ils ? ' הערכת מחיר שוק: <b>₪' + fmt(id.market_price_ils) + '</b>' : '') + '</div>';\n  }\n  if (id.notes) h += '<div class=\"meta\" style=\"margin-top:10px\">' + id.notes + '</div>';\n  el.innerHTML = h;\n}\n</script></body></html>`;\nreturn [{ json: { html } }];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        220,
        0
      ],
      "id": "code-page",
      "name": "דף הסריקה"
    },
    {
      "parameters": {
        "respondWith": "text",
        "responseBody": "={{ $json.html }}",
        "options": {
          "responseHeaders": {
            "entries": [
              {
                "name": "Content-Type",
                "value": "text/html; charset=utf-8"
              }
            ]
          }
        }
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        440,
        0
      ],
      "id": "resp-page",
      "name": "החזרת הדף"
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "car-scan",
        "responseMode": "responseNode",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        0,
        260
      ],
      "id": "wh-scan",
      "name": "Webhook - סריקה"
    },
    {
      "parameters": {
        "operation": "get",
        "dataTableId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_DATA_TABLE_ID",
          "cachedResultName": "Car Inventory"
        },
        "returnAll": true,
        "filters": {},
        "options": {}
      },
      "type": "n8n-nodes-base.dataTable",
      "typeVersion": 1,
      "position": [
        200,
        260
      ],
      "id": "dt-inv",
      "name": "שליפת מלאי"
    },
    {
      "parameters": {
        "jsCode": "\nconst body = $('Webhook - סריקה').item.json.body || {};\nif (!body.image) { return [{ json: { skip: true, error: 'no image' } }]; }\nconst rows = $input.all().map(i => i.json);\nconst catalog = [...new Set(rows.map(r => r.make + ' | ' + r.model))].join('\\n');\nconst prompt = `אתה מומחה זיהוי רכבים. זהה את הרכב בתמונה בשני שלבים נפרדים:\n\nשלב 1 - זיהוי אמיתי, חופשי לחלוטין: מהו הרכב באמת? התבסס על סמל היצרן, צורת הסורג, הפנסים והמרכב. אל תתאים לשום רשימה - תגיד את האמת גם אם זה מותג נדיר. שים לב במיוחד למותגים סיניים הנפוצים בישראל: צ'רי (Chery - סמל אליפסה עם A, סורג יהלומים), אומודה (Omoda), ג'איקו (Jaecoo), ג'ילי (Geely), האוול (Haval), BYD, MG (סמל מתומן MG), סקייוול (Skywell), ליפמוטור, זיקר. אם אתה לא בטוח בין שני דגמים - תגיד את שניהם ב-notes והורד confidence.\n\nשלב 2 - התאמה לקטלוג המגרש: רק אחרי שזיהית באמת, בדוק אם הרכב שזיהית קיים בקטלוג הבא. אם כן - מלא catalog_match עם הכתיב המדויק מהקטלוג. אם הרכב שזיהית לא נמצא בקטלוג - catalog_match חייב להיות null. אסור \"לעגל\" לדגם דומה מהקטלוג.\n\nקטלוג (יצרן | דגם):\n${catalog}\n\nהחזר JSON בלבד:\n{\"identified\": true/false, \"make\": \"היצרן האמיתי בעברית\", \"make_en\": \"היצרן באנגלית\", \"model\": \"הדגם האמיתי\", \"year_est\": \"טווח שנתונים\", \"color\": \"צבע בעברית\", \"body_type\": \"סוג מרכב בעברית\", \"confidence\": 0-100, \"market_price_ils\": מחיר שוק משוער בשקלים או null, \"catalog_match\": {\"make\": \"...\", \"model\": \"...\"} או null, \"notes\": \"הערה קצרה בעברית\"}`;\nreturn [{ json: { req: {\n  model: 'claude-sonnet-4-5',\n  max_tokens: 800,\n  temperature: 0,\n  messages: [{ role: 'user', content: [\n    { type: 'image', source: { type: 'base64', media_type: 'image/jpeg', data: body.image } },\n    { type: 'text', text: prompt }\n  ]}]\n}}}];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        400,
        260
      ],
      "id": "code-req",
      "name": "בניית בקשת Vision"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.anthropic.com/v1/messages",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "anthropic-version",
              "value": "2023-06-01"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify($json.req) }}",
        "options": {
          "timeout": 60000
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        600,
        260
      ],
      "id": "http-claude",
      "name": "Claude Vision"
    },
    {
      "parameters": {
        "jsCode": "\nlet out = { ok: false, error: 'parse failed' };\ntry {\n  const txt = $json.content[0].text.replace(/^```json?\\s*/i, '').replace(/```\\s*$/, '').trim();\n  const id = JSON.parse(txt);\n  if (!id.identified) {\n    out = { ok: false, error: id.notes || 'לא זוהה רכב בתמונה' };\n  } else {\n    const rows = $('שליפת מלאי').all().map(i => i.json);\n    const norm = s => String(s || '').replace(/[\\s'’׳\"-]/g, '').toLowerCase();\n    let matches = [];\n    if (id.catalog_match && id.catalog_match.make) {\n      matches = rows.filter(r => norm(r.make) === norm(id.catalog_match.make) && norm(r.model) === norm(id.catalog_match.model));\n      if (!matches.length) matches = rows.filter(r => norm(r.make) === norm(id.catalog_match.make) && (norm(r.model).includes(norm(id.catalog_match.model)) || norm(id.catalog_match.model).includes(norm(r.model))));\n    }\n    matches.sort((a, b) => b.year - a.year || a.price - b.price);\n    out = { ok: true, identification: id, matches: matches.slice(0, 8) };\n  }\n} catch (e) { out = { ok: false, error: String(e).slice(0, 120) }; }\nreturn [{ json: out }];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        800,
        260
      ],
      "id": "code-parse",
      "name": "פענוח והצלבת מלאי"
    },
    {
      "parameters": {
        "respondWith": "text",
        "responseBody": "={{ JSON.stringify($json) }}",
        "options": {
          "responseHeaders": {
            "entries": [
              {
                "name": "Content-Type",
                "value": "application/json; charset=utf-8"
              }
            ]
          }
        }
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        1000,
        260
      ],
      "id": "resp-json",
      "name": "תשובת JSON"
    },
    {
      "parameters": {
        "httpMethod": "GET",
        "path": "cars-dashboard",
        "responseMode": "responseNode",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        0,
        520
      ],
      "id": "wh-carsdash",
      "name": "Webhook - מלאי"
    },
    {
      "parameters": {
        "operation": "get",
        "dataTableId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_DATA_TABLE_ID",
          "cachedResultName": "Car Inventory"
        },
        "returnAll": true,
        "filters": {},
        "options": {}
      },
      "type": "n8n-nodes-base.dataTable",
      "typeVersion": 1,
      "position": [
        200,
        520
      ],
      "id": "dt-carsdash",
      "name": "שליפת מלאי לדשבורד"
    },
    {
      "parameters": {
        "jsCode": "\nconst KEYX = '';\nconst esc = t => String(t ?? '').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\"/g,'&quot;');\nconst rows = $input.all().map(i => i.json).sort((a,b) => (a.make+a.model).localeCompare(b.make+b.model, 'he') || b.year - a.year);\nconst avail = rows.filter(r => r.status === 'available');\nconst avg = rows.length ? Math.round(rows.reduce((s,r) => s + (r.price||0), 0) / rows.length) : 0;\nconst makes = new Set(rows.map(r => r.make)).size;\nconst fmt = n => new Intl.NumberFormat('he-IL').format(n);\nconst stMap = { available: ['זמין','#34d399'], reserved: ['שמור','#ffb020'], sold: ['נמכר','#ff5c5c'] };\nconst trs = rows.map(r => {\n  const [sl, sc] = stMap[r.status] || [r.status,'#888'];\n  return `<tr><td><b>${esc(r.make)} ${esc(r.model)}</b><div class=\"sub\">${esc(r.trim)}</div></td>\n  <td>${r.year}</td><td>${esc(r.color)}</td><td>${fmt(r.km)}</td>\n  <td class=\"pr\">₪${fmt(r.price)}</td>\n  <td><span class=\"badge\" style=\"--c:${sc}\">${sl}</span></td>${''}</tr>`;\n}).join('');\nconst html = `<!doctype html><html dir=\"rtl\" lang=\"he\"><head><meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><title>מלאי המגרש · מגרש AI</title>\n<link href=\"https://fonts.googleapis.com/css2?family=Heebo:wght@400;500;700;900&display=swap\" rel=\"stylesheet\">\n<style>\n* { box-sizing: border-box; margin: 0; }\nbody { font-family: 'Heebo', sans-serif; background: #0b0e14; color: #e8eaf0; min-height: 100vh; padding: 32px clamp(16px, 4vw, 48px); }\n.top { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 22px; }\nh1 { font-size: 25px; font-weight: 900; background: linear-gradient(90deg, #7dd3fc, #c084fc); -webkit-background-clip: text; background-clip: text; color: transparent; }\n.adm { font-size: 11px; border: 1px solid #ffb020; color: #ffb020; border-radius: 99px; padding: 2px 10px; font-weight: 700; }\n.grid { display: grid; grid-template-columns: 1fr 300px; gap: 18px; align-items: start; }\n@media(max-width: 900px) { .grid { grid-template-columns: 1fr; } }\n.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 12px; margin-bottom: 18px; }\n.card { background: #131826; border: 1px solid #1f2739; border-radius: 14px; padding: 14px 18px; }\n.card b { font-size: 26px; font-weight: 900; display: block; }\n.card span { font-size: 12px; color: #8b93a7; }\n.card.g b { color: #34d399; } .card.b b { color: #7dd3fc; } .card.p b { color: #c084fc; }\n.qrbox { background: #131826; border: 1px solid #1f2739; border-radius: 16px; padding: 20px; text-align: center; }\n.qrbox img { width: 170px; border-radius: 10px; background: #fff; padding: 8px; }\n.qrbox h3 { font-size: 15px; margin: 12px 0 4px; }\n.qrbox p { font-size: 12px; color: #8b93a7; }\n.qrbox a { color: #7dd3fc; font-size: 12px; }\n#q { width: 100%; background: #131826; border: 1px solid #1f2739; color: #e8eaf0; border-radius: 10px; padding: 10px 14px; font-family: inherit; margin-bottom: 12px; }\ntable { width: 100%; border-collapse: collapse; background: #131826; border: 1px solid #1f2739; border-radius: 14px; overflow: hidden; font-size: 14px; }\nth { text-align: right; padding: 11px 13px; font-size: 12px; color: #8b93a7; border-bottom: 1px solid #1f2739; background: #10141f; }\ntd { padding: 10px 13px; border-bottom: 1px solid #1a2030; vertical-align: middle; }\ntr:last-child td { border-bottom: 0; } tr:hover td { background: #161c2c; }\n.sub { font-size: 11px; color: #8b93a7; }\n.pr { font-weight: 900; color: #7dd3fc; white-space: nowrap; }\n.badge { font-size: 11px; font-weight: 700; border-radius: 99px; padding: 2px 9px; color: var(--c); background: color-mix(in srgb, var(--c) 14%, transparent); border: 1px solid color-mix(in srgb, var(--c) 40%, transparent); }\n.del { background: rgba(255,92,92,.12); color: #ff5c5c; border: 1px solid rgba(255,92,92,.4); border-radius: 7px; padding: 5px 9px; cursor: pointer; }\n.addbar { background: #131826; border: 1px solid #1f2739; border-radius: 14px; padding: 14px 16px; margin-bottom: 14px; }\n.addbar b { font-size: 14px; }\n.addgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(110px, 1fr)); gap: 8px; margin-top: 10px; }\n.addgrid input, .addgrid select { background: #0e1220; border: 1px solid #1f2739; color: #e8eaf0; border-radius: 8px; padding: 8px 10px; font-family: inherit; font-size: 13px; }\n.addgrid button { background: linear-gradient(90deg, #7dd3fc, #c084fc); color: #08111f; border: 0; border-radius: 8px; font-weight: 900; cursor: pointer; font-family: inherit; }\n.foot { margin-top: 16px; font-size: 11px; color: #58607a; text-align: center; font-family: monospace; direction: ltr; }\n</style></head><body>\n<div class=\"top\"><h1>🚗 מלאי המגרש</h1></div>\n<div class=\"stats\">\n  <div class=\"card\"><b>${rows.length}</b><span>רכבים במלאי</span></div>\n  <div class=\"card g\"><b>${avail.length}</b><span>זמינים למכירה</span></div>\n  <div class=\"card b\"><b>₪${fmt(avg)}</b><span>מחיר ממוצע</span></div>\n  <div class=\"card p\"><b>${makes}</b><span>מותגים</span></div>\n</div>\n<div class=\"grid\">\n<div>\n\n<input id=\"q\" placeholder=\"🔎 חיפוש חופשי: יצרן, דגם, צבע, שנה...\" oninput=\"filt()\">\n<table><thead><tr><th>רכב</th><th>שנה</th><th>צבע</th><th>ק\"מ</th><th>מחיר</th><th>סטטוס</th></tr></thead>\n<tbody>${trs}</tbody></table>\n</div>\n<div class=\"qrbox\">\n  <img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAUoAAAFKAQMAAABB54RGAAAABlBMVEUAAAD///+l2Z/dAAAAAnRSTlP//8i138cAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAGwSURBVGiB7ZnLbcQwDEQFqACX5NZTkgpYgJE5/MjZJPCexMPwYDjW02lCcsht8jgaUaJEP0JHszjlNZ/H6/rWRb6OeWzRiVZBuwl34m3l5/UrBtFCqEqnwuJSm5pC2POS/SRaEJ2fkZW4NDrRwqionE61f/8HiG5Ds2ji7FF9JboFDUMC9Pb4y7sQ3YTeA43NdV6DaAV0mHRtiZmG6HNaQ6/rRGugKmczn+8tLq9fB6MTLYLCLwqE1T/nTX97T0OiW1GlDtMUphGaHnlAtBBq6oamkYuiW5BTiFZBR1set5Xiq70XTaKbUR+kUTQlALFCughLtABqjU1rY45mmoGQmGgZVJNP1q2UShyW8lY0iW5HcwLDpl5czmab4U60CupWEfrpfJalcsRekWgVFLXRJ2dTMgrpWl+JbkfFzH68wZVoxO6DaAU0I81HeBE0QKJlUHcg8CLnBaLjISH9G9EaaIesnnw5qXXxJO1E66AtGlvWy8xAs5RE66HLfPajfBIthjZ4kfxxxeIXYYluQ61oIg1Fsrv59p5oGdTl02yzs/gBTGLCJloBfRpEiRL9AP0GtPaQm0pfgTMAAAAASUVORK5CYII=\" alt=\"QR לסורק הרכבים\">\n  <h3>📱 סרקו לפתיחת הסורק</h3>\n  <p>מצלמים רכב מהטלפון - הסוכן מזהה את הדגם ובודק מה יש במלאי</p>\n  <a href=\"/webhook/car-scanner\" target=\"_blank\">או פתחו בדפדפן ←</a>\n</div>\n</div>\n<div class=\"foot\">Car Inventory · n8n Data Table · served by a webhook workflow</div>\n\n<script>\nconst KEY = '';\nfunction filt() {\n  const t = document.getElementById('q').value.trim().toLowerCase();\n  document.querySelectorAll('tbody tr').forEach(tr => {\n    tr.style.display = !t || tr.textContent.toLowerCase().includes(t) ? '' : 'none';\n  });\n}\nasync function post(body) {\n  body.key = KEY;\n  const res = await fetch('/webhook/car-action', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) });\n  if (res.ok) location.reload(); else alert('נכשל: ' + res.status);\n}\nfunction delCar(id) { if (confirm('למחוק את הרכב מהמלאי?')) post({ action: 'delete', id }); }\nfunction addCar() {\n  const v = k => document.getElementById('a_' + k).value;\n  if (!v('make') || !v('model') || !v('price')) { alert('יצרן, דגם ומחיר הם חובה'); return; }\n  post({ action: 'add', car: { make: v('make'), model: v('model'), year: Number(v('year')) || 2024,\n    trim: v('trim') || '-', color: v('color') || '-', km: Number(v('km')) || 0,\n    price: Number(v('price')), status: v('status') } });\n}\n</script>\n</body></html>`;\nreturn [{ json: { html } }];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        400,
        520
      ],
      "id": "code-carsdash",
      "name": "דף מלאי ציבורי"
    },
    {
      "parameters": {
        "respondWith": "text",
        "responseBody": "={{ $json.html }}",
        "options": {
          "responseHeaders": {
            "entries": [
              {
                "name": "Content-Type",
                "value": "text/html; charset=utf-8"
              }
            ]
          }
        }
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        600,
        520
      ],
      "id": "resp-carsdash",
      "name": "החזרת דף מלאי"
    },
    {
      "parameters": {
        "httpMethod": "GET",
        "path": "cars-admin",
        "responseMode": "responseNode",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        0,
        700
      ],
      "id": "wh-carsadmin",
      "name": "Webhook - מלאי אדמין"
    },
    {
      "parameters": {
        "operation": "get",
        "dataTableId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_DATA_TABLE_ID",
          "cachedResultName": "Car Inventory"
        },
        "returnAll": true,
        "filters": {},
        "options": {}
      },
      "type": "n8n-nodes-base.dataTable",
      "typeVersion": 1,
      "position": [
        200,
        700
      ],
      "id": "dt-carsadmin",
      "name": "שליפת מלאי לאדמין"
    },
    {
      "parameters": {
        "jsCode": "\n\nconst KEYX = 'YOUR_ADMIN_KEY';\nconst q = $('Webhook - מלאי אדמין').item.json.query || {};\nif (q.key !== KEYX) {\n  return [{ json: { html: `<!doctype html><html dir=\"rtl\"><head><meta charset=\"utf-8\"><title>403</title></head><body style=\"background:#0b0e14;color:#8b93a7;font-family:sans-serif;display:grid;place-items:center;height:100vh;margin:0\"><div>403 · אין גישה</div></body></html>` } }];\n}\nconst esc = t => String(t ?? '').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\"/g,'&quot;');\nconst rows = $input.all().map(i => i.json).sort((a,b) => (a.make+a.model).localeCompare(b.make+b.model, 'he') || b.year - a.year);\nconst avail = rows.filter(r => r.status === 'available');\nconst avg = rows.length ? Math.round(rows.reduce((s,r) => s + (r.price||0), 0) / rows.length) : 0;\nconst makes = new Set(rows.map(r => r.make)).size;\nconst fmt = n => new Intl.NumberFormat('he-IL').format(n);\nconst stMap = { available: ['זמין','#34d399'], reserved: ['שמור','#ffb020'], sold: ['נמכר','#ff5c5c'] };\nconst trs = rows.map(r => {\n  const [sl, sc] = stMap[r.status] || [r.status,'#888'];\n  return `<tr><td><b>${esc(r.make)} ${esc(r.model)}</b><div class=\"sub\">${esc(r.trim)}</div></td>\n  <td>${r.year}</td><td>${esc(r.color)}</td><td>${fmt(r.km)}</td>\n  <td class=\"pr\">₪${fmt(r.price)}</td>\n  <td><span class=\"badge\" style=\"--c:${sc}\">${sl}</span></td>${'<td><button class=\"del\" onclick=\"delCar(' + r.id + ')\">🗑</button></td>'}</tr>`;\n}).join('');\nconst html = `<!doctype html><html dir=\"rtl\" lang=\"he\"><head><meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><title>מלאי המגרש · מגרש AI</title>\n<link href=\"https://fonts.googleapis.com/css2?family=Heebo:wght@400;500;700;900&display=swap\" rel=\"stylesheet\">\n<style>\n* { box-sizing: border-box; margin: 0; }\nbody { font-family: 'Heebo', sans-serif; background: #0b0e14; color: #e8eaf0; min-height: 100vh; padding: 32px clamp(16px, 4vw, 48px); }\n.top { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 22px; }\nh1 { font-size: 25px; font-weight: 900; background: linear-gradient(90deg, #7dd3fc, #c084fc); -webkit-background-clip: text; background-clip: text; color: transparent; }\n.adm { font-size: 11px; border: 1px solid #ffb020; color: #ffb020; border-radius: 99px; padding: 2px 10px; font-weight: 700; }\n.grid { display: grid; grid-template-columns: 1fr 300px; gap: 18px; align-items: start; }\n@media(max-width: 900px) { .grid { grid-template-columns: 1fr; } }\n.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 12px; margin-bottom: 18px; }\n.card { background: #131826; border: 1px solid #1f2739; border-radius: 14px; padding: 14px 18px; }\n.card b { font-size: 26px; font-weight: 900; display: block; }\n.card span { font-size: 12px; color: #8b93a7; }\n.card.g b { color: #34d399; } .card.b b { color: #7dd3fc; } .card.p b { color: #c084fc; }\n.qrbox { background: #131826; border: 1px solid #1f2739; border-radius: 16px; padding: 20px; text-align: center; }\n.qrbox img { width: 170px; border-radius: 10px; background: #fff; padding: 8px; }\n.qrbox h3 { font-size: 15px; margin: 12px 0 4px; }\n.qrbox p { font-size: 12px; color: #8b93a7; }\n.qrbox a { color: #7dd3fc; font-size: 12px; }\n#q { width: 100%; background: #131826; border: 1px solid #1f2739; color: #e8eaf0; border-radius: 10px; padding: 10px 14px; font-family: inherit; margin-bottom: 12px; }\ntable { width: 100%; border-collapse: collapse; background: #131826; border: 1px solid #1f2739; border-radius: 14px; overflow: hidden; font-size: 14px; }\nth { text-align: right; padding: 11px 13px; font-size: 12px; color: #8b93a7; border-bottom: 1px solid #1f2739; background: #10141f; }\ntd { padding: 10px 13px; border-bottom: 1px solid #1a2030; vertical-align: middle; }\ntr:last-child td { border-bottom: 0; } tr:hover td { background: #161c2c; }\n.sub { font-size: 11px; color: #8b93a7; }\n.pr { font-weight: 900; color: #7dd3fc; white-space: nowrap; }\n.badge { font-size: 11px; font-weight: 700; border-radius: 99px; padding: 2px 9px; color: var(--c); background: color-mix(in srgb, var(--c) 14%, transparent); border: 1px solid color-mix(in srgb, var(--c) 40%, transparent); }\n.del { background: rgba(255,92,92,.12); color: #ff5c5c; border: 1px solid rgba(255,92,92,.4); border-radius: 7px; padding: 5px 9px; cursor: pointer; }\n.addbar { background: #131826; border: 1px solid #1f2739; border-radius: 14px; padding: 14px 16px; margin-bottom: 14px; }\n.addbar b { font-size: 14px; }\n.addgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(110px, 1fr)); gap: 8px; margin-top: 10px; }\n.addgrid input, .addgrid select { background: #0e1220; border: 1px solid #1f2739; color: #e8eaf0; border-radius: 8px; padding: 8px 10px; font-family: inherit; font-size: 13px; }\n.addgrid button { background: linear-gradient(90deg, #7dd3fc, #c084fc); color: #08111f; border: 0; border-radius: 8px; font-weight: 900; cursor: pointer; font-family: inherit; }\n.foot { margin-top: 16px; font-size: 11px; color: #58607a; text-align: center; font-family: monospace; direction: ltr; }\n</style></head><body>\n<div class=\"top\"><h1>🚗 מלאי המגרש</h1><span class=\"adm\">ADMIN</span></div>\n<div class=\"stats\">\n  <div class=\"card\"><b>${rows.length}</b><span>רכבים במלאי</span></div>\n  <div class=\"card g\"><b>${avail.length}</b><span>זמינים למכירה</span></div>\n  <div class=\"card b\"><b>₪${fmt(avg)}</b><span>מחיר ממוצע</span></div>\n  <div class=\"card p\"><b>${makes}</b><span>מותגים</span></div>\n</div>\n<div class=\"grid\">\n<div>\n\n  <div class=\"addbar\">\n    <b>+ הוספת רכב</b>\n    <div class=\"addgrid\">\n      <input id=\"a_make\" placeholder=\"יצרן\">\n      <input id=\"a_model\" placeholder=\"דגם\">\n      <input id=\"a_year\" type=\"number\" placeholder=\"שנה\">\n      <input id=\"a_trim\" placeholder=\"גימור\">\n      <input id=\"a_color\" placeholder=\"צבע\">\n      <input id=\"a_km\" type=\"number\" placeholder='ק\"מ'>\n      <input id=\"a_price\" type=\"number\" placeholder=\"מחיר ₪\">\n      <select id=\"a_status\"><option value=\"available\">זמין</option><option value=\"reserved\">שמור</option><option value=\"sold\">נמכר</option></select>\n      <button onclick=\"addCar()\">הוסף</button>\n    </div>\n  </div>\n<input id=\"q\" placeholder=\"🔎 חיפוש חופשי: יצרן, דגם, צבע, שנה...\" oninput=\"filt()\">\n<table><thead><tr><th>רכב</th><th>שנה</th><th>צבע</th><th>ק\"מ</th><th>מחיר</th><th>סטטוס</th><th></th></tr></thead>\n<tbody>${trs}</tbody></table>\n</div>\n<div class=\"qrbox\">\n  <img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAUoAAAFKAQMAAABB54RGAAAABlBMVEUAAAD///+l2Z/dAAAAAnRSTlP//8i138cAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAGwSURBVGiB7ZnLbcQwDEQFqACX5NZTkgpYgJE5/MjZJPCexMPwYDjW02lCcsht8jgaUaJEP0JHszjlNZ/H6/rWRb6OeWzRiVZBuwl34m3l5/UrBtFCqEqnwuJSm5pC2POS/SRaEJ2fkZW4NDrRwqionE61f/8HiG5Ds2ji7FF9JboFDUMC9Pb4y7sQ3YTeA43NdV6DaAV0mHRtiZmG6HNaQ6/rRGugKmczn+8tLq9fB6MTLYLCLwqE1T/nTX97T0OiW1GlDtMUphGaHnlAtBBq6oamkYuiW5BTiFZBR1set5Xiq70XTaKbUR+kUTQlALFCughLtABqjU1rY45mmoGQmGgZVJNP1q2UShyW8lY0iW5HcwLDpl5czmab4U60CupWEfrpfJalcsRekWgVFLXRJ2dTMgrpWl+JbkfFzH68wZVoxO6DaAU0I81HeBE0QKJlUHcg8CLnBaLjISH9G9EaaIesnnw5qXXxJO1E66AtGlvWy8xAs5RE66HLfPajfBIthjZ4kfxxxeIXYYluQ61oIg1Fsrv59p5oGdTl02yzs/gBTGLCJloBfRpEiRL9AP0GtPaQm0pfgTMAAAAASUVORK5CYII=\" alt=\"QR לסורק הרכבים\">\n  <h3>📱 סרקו לפתיחת הסורק</h3>\n  <p>מצלמים רכב מהטלפון - הסוכן מזהה את הדגם ובודק מה יש במלאי</p>\n  <a href=\"/webhook/car-scanner\" target=\"_blank\">או פתחו בדפדפן ←</a>\n</div>\n</div>\n<div class=\"foot\">Car Inventory · n8n Data Table · served by a webhook workflow</div>\n\n<script>\nconst KEY = 'YOUR_ADMIN_KEY';\nfunction filt() {\n  const t = document.getElementById('q').value.trim().toLowerCase();\n  document.querySelectorAll('tbody tr').forEach(tr => {\n    tr.style.display = !t || tr.textContent.toLowerCase().includes(t) ? '' : 'none';\n  });\n}\nasync function post(body) {\n  body.key = KEY;\n  const res = await fetch('/webhook/car-action', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) });\n  if (res.ok) location.reload(); else alert('נכשל: ' + res.status);\n}\nfunction delCar(id) { if (confirm('למחוק את הרכב מהמלאי?')) post({ action: 'delete', id }); }\nfunction addCar() {\n  const v = k => document.getElementById('a_' + k).value;\n  if (!v('make') || !v('model') || !v('price')) { alert('יצרן, דגם ומחיר הם חובה'); return; }\n  post({ action: 'add', car: { make: v('make'), model: v('model'), year: Number(v('year')) || 2024,\n    trim: v('trim') || '-', color: v('color') || '-', km: Number(v('km')) || 0,\n    price: Number(v('price')), status: v('status') } });\n}\n</script>\n</body></html>`;\nreturn [{ json: { html } }];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        400,
        700
      ],
      "id": "code-carsadmin",
      "name": "דף מלאי אדמין"
    },
    {
      "parameters": {
        "respondWith": "text",
        "responseBody": "={{ $json.html }}",
        "options": {
          "responseHeaders": {
            "entries": [
              {
                "name": "Content-Type",
                "value": "text/html; charset=utf-8"
              }
            ]
          }
        }
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        600,
        700
      ],
      "id": "resp-carsadmin",
      "name": "החזרת דף אדמין"
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "car-action",
        "responseMode": "responseNode",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        0,
        880
      ],
      "id": "wh-caraction",
      "name": "Webhook - פעולות מלאי"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "loose",
            "version": 2
          },
          "conditions": [
            {
              "id": "k",
              "leftValue": "={{ $('Webhook - פעולות מלאי').item.json.body.key }}",
              "rightValue": "YOUR_ADMIN_KEY",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        200,
        880
      ],
      "id": "if-carkey",
      "name": "מפתח מלאי תקין?"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "loose",
            "version": 2
          },
          "conditions": [
            {
              "id": "a",
              "leftValue": "={{ $('Webhook - פעולות מלאי').item.json.body.action }}",
              "rightValue": "delete",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        400,
        840
      ],
      "id": "if-cardel",
      "name": "מחיקת רכב?"
    },
    {
      "parameters": {
        "operation": "deleteRows",
        "dataTableId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_DATA_TABLE_ID",
          "cachedResultName": "Car Inventory"
        },
        "matchType": "allConditions",
        "filters": {
          "conditions": [
            {
              "keyName": "id",
              "condition": "eq",
              "keyValue": "={{ $('Webhook - פעולות מלאי').item.json.body.id }}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.dataTable",
      "typeVersion": 1,
      "position": [
        620,
        780
      ],
      "id": "dt-cardel",
      "name": "מחיקת רכב מהמלאי"
    },
    {
      "parameters": {
        "operation": "insert",
        "dataTableId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_DATA_TABLE_ID",
          "cachedResultName": "Car Inventory"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "make": "={{ $('Webhook - פעולות מלאי').item.json.body.car.make }}",
            "model": "={{ $('Webhook - פעולות מלאי').item.json.body.car.model }}",
            "year": "={{ Number($('Webhook - פעולות מלאי').item.json.body.car.year) }}",
            "trim": "={{ $('Webhook - פעולות מלאי').item.json.body.car.trim }}",
            "color": "={{ $('Webhook - פעולות מלאי').item.json.body.car.color }}",
            "km": "={{ Number($('Webhook - פעולות מלאי').item.json.body.car.km) }}",
            "price": "={{ Number($('Webhook - פעולות מלאי').item.json.body.car.price) }}",
            "status": "={{ $('Webhook - פעולות מלאי').item.json.body.car.status }}"
          },
          "matchingColumns": [],
          "schema": []
        },
        "options": {}
      },
      "type": "n8n-nodes-base.dataTable",
      "typeVersion": 1,
      "position": [
        620,
        940
      ],
      "id": "dt-caradd",
      "name": "הוספת רכב למלאי"
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={\"ok\": true}",
        "options": {}
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        840,
        860
      ],
      "id": "resp-carok",
      "name": "אישור פעולת מלאי"
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={\"ok\": false}",
        "options": {
          "responseCode": 403
        }
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        400,
        1000
      ],
      "id": "resp-car403",
      "name": "סירוב פעולת מלאי"
    }
  ],
  "connections": {
    "Webhook - אפליקציה": {
      "main": [
        [
          {
            "node": "דף הסריקה",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "דף הסריקה": {
      "main": [
        [
          {
            "node": "החזרת הדף",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook - סריקה": {
      "main": [
        [
          {
            "node": "שליפת מלאי",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "שליפת מלאי": {
      "main": [
        [
          {
            "node": "בניית בקשת Vision",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "בניית בקשת Vision": {
      "main": [
        [
          {
            "node": "Claude Vision",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Claude Vision": {
      "main": [
        [
          {
            "node": "פענוח והצלבת מלאי",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "פענוח והצלבת מלאי": {
      "main": [
        [
          {
            "node": "תשובת JSON",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook - מלאי": {
      "main": [
        [
          {
            "node": "שליפת מלאי לדשבורד",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "שליפת מלאי לדשבורד": {
      "main": [
        [
          {
            "node": "דף מלאי ציבורי",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "דף מלאי ציבורי": {
      "main": [
        [
          {
            "node": "החזרת דף מלאי",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook - מלאי אדמין": {
      "main": [
        [
          {
            "node": "שליפת מלאי לאדמין",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "שליפת מלאי לאדמין": {
      "main": [
        [
          {
            "node": "דף מלאי אדמין",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "דף מלאי אדמין": {
      "main": [
        [
          {
            "node": "החזרת דף אדמין",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook - פעולות מלאי": {
      "main": [
        [
          {
            "node": "מפתח מלאי תקין?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "מפתח מלאי תקין?": {
      "main": [
        [
          {
            "node": "מחיקת רכב?",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "סירוב פעולת מלאי",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "מחיקת רכב?": {
      "main": [
        [
          {
            "node": "מחיקת רכב מהמלאי",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "הוספת רכב למלאי",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "מחיקת רכב מהמלאי": {
      "main": [
        [
          {
            "node": "אישור פעולת מלאי",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "הוספת רכב למלאי": {
      "main": [
        [
          {
            "node": "אישור פעולת מלאי",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "meta": {
    "note": "Car Scanner - exported from a live self-hosted n8n 2.31.6. Credentials, admin key and table IDs replaced with placeholders. Wire your own: Anthropic API key (httpHeaderAuth, x-api-key), a Data Table with columns make/model/year/trim/color/km/price/status."
  }
}