{
  "name": "FANZA Review Auto-Generator (Phase 1)",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 3 * * 0"
            }
          ]
        }
      },
      "id": "schedule-trigger",
      "name": "Schedule Trigger (Weekly Sun 03:00 JST)",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        100,
        300
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "c1",
              "name": "dmmApiId",
              "value": "={{ $env.DMM_API_ID }}",
              "type": "string"
            },
            {
              "id": "c2",
              "name": "affiliateId",
              "value": "ikuoji-990",
              "type": "string"
            },
            {
              "id": "c3",
              "name": "hits",
              "value": 10,
              "type": "number"
            },
            {
              "id": "c4",
              "name": "wpBaseUrl",
              "value": "https://princess-kira-adult.com",
              "type": "string"
            },
            {
              "id": "c5",
              "name": "anthropicModel",
              "value": "claude-haiku-4-5",
              "type": "string"
            },
            {
              "id": "c7",
              "name": "notifyEmail",
              "value": "manatsusuki@gmail.com",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "config",
      "name": "Config",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        320,
        300
      ]
    },
    {
      "parameters": {
        "method": "GET",
        "url": "https://api.dmm.com/affiliate/v3/ItemList",
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "api_id",
              "value": "={{ $json.dmmApiId }}"
            },
            {
              "name": "affiliate_id",
              "value": "={{ $json.affiliateId }}"
            },
            {
              "name": "site",
              "value": "FANZA"
            },
            {
              "name": "service",
              "value": "digital"
            },
            {
              "name": "floor",
              "value": "videoa"
            },
            {
              "name": "hits",
              "value": "={{ $json.hits }}"
            },
            {
              "name": "sort",
              "value": "date"
            },
            {
              "name": "output",
              "value": "json"
            }
          ]
        },
        "options": {
          "timeout": 30000,
          "response": {
            "response": {
              "responseFormat": "json"
            }
          }
        }
      },
      "id": "dmm-item-list",
      "name": "DMM API ItemList",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        540,
        300
      ],
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 5000
    },
    {
      "parameters": {
        "jsCode": "// Extract items from DMM API response + build affiliate URL per item\nconst resp = $input.first().json;\nconst items = (resp.result && resp.result.items) || [];\nconst join = (arr, f) => (arr || []).map(x => x[f]).filter(Boolean).join(', ');\nconst out = [];\nfor (const it of items) {\n  const info = it.iteminfo || {};\n  const productUrl = it.URL || '';\n  const affiliateUrl =\n    'https://al.dmm.co.jp/?lurl=' + encodeURIComponent(productUrl) +\n    '&af_id=ikuoji-002-001&ch=link_tool&ch_id=text';\n  out.push({ json: {\n    product_id: it.content_id || '',\n    product_title: it.title || '',\n    actress: join(info.actress, 'name'),\n    genre: join(info.genre, 'name'),\n    release_date: it.date || '',\n    duration: it.volume || '',\n    label: ((info.label || [])[0] || {}).name || '',\n    series: ((info.series || [])[0] || {}).name || '',\n    description: it.comment || it.title || '',\n    thumbnail_url: (it.imageURL || {}).large || (it.imageURL || {}).list || '',\n    product_url: productUrl,\n    affiliate_url: affiliateUrl\n  }});\n}\nif (out.length === 0) {\n  return [{ json: { _empty: true, message: 'No items returned from DMM API' } }];\n}\nreturn out;"
      },
      "id": "extract-items",
      "name": "Extract Items",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        760,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "// Build Claude API request body with prompt-caching on system prompt.\n// System prompt is kept verbatim here so n8n needs no external file read.\nconst SYSTEM_PROMPT = [\n  '\u3042\u306a\u305f\u306f\u30a2\u30c0\u30eb\u30c8\u52d5\u753b\u30ec\u30d3\u30e5\u30fc\u30d6\u30ed\u30b0\u300cprincess-kira-adult.com\u300d\u306e\u30e9\u30a4\u30bf\u30fc\u3067\u3059\u3002DMM Web Service API \u304b\u3089\u6e21\u3055\u308c\u308b\u4f5c\u54c1\u60c5\u5831\u3092\u3082\u3068\u306b\u3001SEO \u3068\u30b3\u30f3\u30d0\u30fc\u30b8\u30e7\u30f3\u3092\u4e21\u7acb\u3059\u308b\u65e5\u672c\u8a9e\u30ec\u30d3\u30e5\u30fc\u8a18\u4e8b\u30921\u672c\u751f\u6210\u3057\u307e\u3059\u3002',\n  '',\n  '## \u51fa\u529b\u5f62\u5f0f',\n  'JSON \u306e\u307f\u8fd4\u5374\u3002\u524d\u5f8c\u306b\u5730\u306e\u6587\u3084 ``` \u3092\u4ed8\u3051\u306a\u3044\u3002',\n  '{',\n  '  \"title\": \"h1 \u30bf\u30a4\u30c8\u30eb\uff0860\u6587\u5b57\u4ee5\u5185\u3001\u5973\u512a\u540d\u3068\u4f5c\u54c1\u30bf\u30a4\u30c8\u30eb\u306e\u8981\u7d20\u3092\u542b\u3080\uff09\",',\n  '  \"excerpt\": \"\u30ea\u30fc\u30c9\u6587\u306e\u5192\u982d150\u6587\u5b57\",',\n  '  \"content_html\": \"<p>\u301c</p>... HTML \u672c\u6587\uff082000\u301c3000\u6587\u5b57\uff09\",',\n  '  \"categories\": [\"FANZA\u30ec\u30d3\u30e5\u30fc\", \"\u5973\u512a\u540d1\"],',\n  '  \"tags\": [\"\u30b8\u30e3\u30f3\u30eb1\"],',\n  '  \"compliance_check\": {\"has_pr\": true, \"has_18_plus\": true, \"no_forbidden_words\": true, \"affiliate_link_count\": 1, \"char_count_in_range\": true}',\n  '}',\n  '',\n  '## \u8a18\u4e8b\u69cb\u6210\uff08content_html\uff09',\n  '1. \u30ea\u30fc\u30c9\u6587\uff08200\u5b57\u7a0b\u5ea6\uff09',\n  '2. <h2>\u4f5c\u54c1\u60c5\u5831</h2> \u3068 HTML table\uff08\u5973\u512a/\u30b8\u30e3\u30f3\u30eb/\u767a\u58f2\u65e5/\u53ce\u9332\u6642\u9593/\u30ec\u30fc\u30d9\u30eb/\u30b7\u30ea\u30fc\u30ba\uff09',\n  '3. <img src=\"{{THUMBNAIL_URL}}\" alt=\"{{PRODUCT_TITLE}}\">\uff08table\u76f4\u5f8c\u30011\u679a\u306e\u307f\uff09',\n  '4. <h2>\u898b\u3069\u3053\u308d</h2> 3\u9805\u76ee',\n  '5. <h2>\u5973\u512a\u7d39\u4ecb</h2>\uff08API\u3067\u5f97\u3089\u308c\u308b\u7bc4\u56f2\u306e\u307f\u3001\u79c1\u751f\u6d3b\u306b\u8e0f\u307f\u8fbc\u307e\u306a\u3044\uff09',\n  '6. <h2>\u8996\u8074\u8005\u306e\u58f0\uff08\u4e88\u60f3\uff09</h2> 3\u8996\u70b9\u3001\u300c\u301c\u3068\u3044\u3046\u611f\u60f3\u3082\u51fa\u305d\u3046\u3067\u3059\u300d\u5f62\u5f0f',\n  '7. <h2>\u4f5c\u54c1\u3092\u8996\u8074\u3059\u308b</h2> \u2192 <p><a href=\"{{AFFILIATE_URL}}\" class=\"btn-affiliate\" target=\"_blank\" rel=\"noopener noreferrer\">FANZA\u3067\u8996\u8074\u3059\u308b</a></p>',\n  '8. \u672b\u5c3e\u514d\u8cac: <hr><p class=\"disclosure\">#PR / \u672c\u8a18\u4e8b\u306f\u30d7\u30ed\u30e2\u30fc\u30b7\u30e7\u30f3\u3092\u542b\u307f\u307e\u3059\u300218\u6b73\u672a\u6e80\u306e\u65b9\u306f\u8996\u8074\u3067\u304d\u307e\u305b\u3093\u3002\u4f5c\u54c1\u60c5\u5831\u306f\u63b2\u8f09\u6642\u70b9\u306e\u3082\u306e\u3067\u3059\u3002\u500b\u4eba\u306e\u611f\u60f3\u3092\u542b\u307f\u307e\u3059\u3002</p>',\n  '',\n  '## \u5fc5\u9808\u8981\u7d20',\n  '- \u672c\u65872000\u301c3000\u6587\u5b57\uff08HTML\u30bf\u30b0\u9664\u5916\u3067\u8a08\u7b97\uff09',\n  '- \u672b\u5c3edisclosure\u306b #PR \u3068 18\u6b73\u672a\u6e80 \u3092\u5fc5\u305a\u542b\u3081\u308b',\n  '- \u30a2\u30d5\u30a3\u30ea\u30a8\u30a4\u30c8\u30ea\u30f3\u30af\u306f CTA \u306e1\u7b87\u6240\u306e\u307f\u3001rel=\"noopener noreferrer\"',\n  '- \u30b5\u30e0\u30cd\u30a4\u30eb img \u306f1\u679a\u3001alt \u306b\u30bf\u30a4\u30c8\u30eb',\n  '',\n  '## \u7981\u6b62\u8868\u73fe',\n  '- \u65ad\u5b9a: \u7d76\u5bfe/\u5fc5\u305a/100%/\u9593\u9055\u3044\u306a\u304f/\u78ba\u5b9f\u306b',\n  '- \u8a87\u5927: \u6700\u9ad8\u5091\u4f5c/\u53f2\u4e0a\u6700\u9ad8/\u795e\u4f5c/\u81f3\u9ad8/\u552f\u4e00\u7121\u4e8c',\n  '- \u9732\u9aa8\u306a\u6027\u884c\u70ba\u306e\u5177\u4f53\u63cf\u5199\u3001\u672a\u6210\u5e74\u3078\u306e\u8a00\u53ca\u3001\u5973\u512a\u4ee5\u5916\u306e\u5b9f\u5728\u500b\u4eba\u540d',\n  '',\n  '## \u30c8\u30fc\u30f3',\n  '- \u5ba2\u89b3\u7684\u3067\u843d\u3061\u7740\u3044\u305f\u8a9e\u308a\u53e3',\n  '- \u300c\u301c\u304b\u3082\u3057\u308c\u307e\u305b\u3093\u300d\u300c\u301c\u3068\u3044\u3046\u5370\u8c61\u300d\u300c\u301c\u3068\u611f\u3058\u308b\u65b9\u3082\u3044\u305d\u3046\u3067\u3059\u300d'\n].join('\\n');\n\nconst model = $('Config').item.json.anthropicModel;\nconst results = [];\nfor (const it of $input.all()) {\n  const d = it.json;\n  const USER_PROMPT = [\n    '## \u4f5c\u54c1\u60c5\u5831',\n    '- \u5546\u54c1ID: ' + d.product_id,\n    '- \u30bf\u30a4\u30c8\u30eb: ' + d.product_title,\n    '- \u5973\u512a: ' + d.actress,\n    '- \u30b8\u30e3\u30f3\u30eb: ' + d.genre,\n    '- \u767a\u58f2\u65e5: ' + d.release_date,\n    '- \u53ce\u9332\u6642\u9593: ' + d.duration,\n    '- \u30ec\u30fc\u30d9\u30eb: ' + d.label,\n    '- \u30b7\u30ea\u30fc\u30ba: ' + d.series,\n    '- \u5546\u54c1\u8aac\u660e: ' + d.description,\n    '- \u30b5\u30e0\u30cd\u30a4\u30eb: ' + d.thumbnail_url,\n    '- \u30a2\u30d5\u30a3\u30ea\u30a8\u30a4\u30c8URL: ' + d.affiliate_url,\n    '',\n    '\u4e0a\u8a18\u3092\u3082\u3068\u306b\u3001\u30b7\u30b9\u30c6\u30e0\u6307\u793a\u306b\u5f93\u3044 JSON \u3092\u8fd4\u3057\u3066\u304f\u3060\u3055\u3044\u3002'\n  ].join('\\n');\n  const anthropicBody = {\n    model: model,\n    max_tokens: 4500,\n    temperature: 0.7,\n    system: [ { type: 'text', text: SYSTEM_PROMPT, cache_control: { type: 'ephemeral' } } ],\n    messages: [ { role: 'user', content: USER_PROMPT } ]\n  };\n  results.push({ json: { ...d, anthropicBody } });\n}\nreturn results;"
      },
      "id": "build-prompt",
      "name": "Build Claude Prompt",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        980,
        300
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.anthropic.com/v1/messages",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "x-api-key",
              "value": "={{ $env.ANTHROPIC_API_KEY }}"
            },
            {
              "name": "anthropic-version",
              "value": "2023-06-01"
            },
            {
              "name": "anthropic-beta",
              "value": "prompt-caching-2024-07-31"
            },
            {
              "name": "content-type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify($json.anthropicBody) }}",
        "options": {
          "timeout": 120000,
          "response": {
            "response": {
              "responseFormat": "json",
              "neverError": true
            }
          },
          "batching": {
            "batch": {
              "batchSize": 1,
              "batchInterval": 25000
            }
          }
        }
      },
      "id": "claude-call",
      "name": "Claude Haiku API",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1200,
        300
      ],
      "retryOnFail": true,
      "maxTries": 2,
      "waitBetweenTries": 10000
    },
    {
      "parameters": {
        "jsCode": "function validateCompliance(gen) {\n  const html = (gen && gen.content_html) || '';\n  const textOnly = html.replace(/<[^>]+>/g, '');\n  const forbidden = /(\u7d76\u5bfe|\u5fc5\u305a|100%|\u9593\u9055\u3044\u306a\u304f|\u6700\u9ad8\u5091\u4f5c|\u795e\u4f5c|\u81f3\u9ad8)/;\n  const affiliateMatches = html.match(/al\\.dmm\\.co\\.jp/g) || [];\n  return {\n    has_pr: /#PR/.test(html),\n    has_18_plus: /18\u6b73\u672a\u6e80|18\u7981/.test(html),\n    no_forbidden_words: !forbidden.test(textOnly),\n    affiliate_link_count: affiliateMatches.length,\n    char_count_in_range: textOnly.length >= 1200 && textOnly.length <= 4000,\n    char_count: textOnly.length\n  };\n}\n\nfunction extractJson(text) {\n  let s = text.trim();\n  const fence = s.match(/^```(?:json)?\\s*([\\s\\S]*?)\\s*```\\s*$/);\n  if (fence) s = fence[1].trim();\n  const first = s.indexOf('{');\n  const last = s.lastIndexOf('}');\n  if (first >= 0 && last > first) s = s.slice(first, last+1);\n  return JSON.parse(s);\n}\n\nconst out = [];\nfor (const item of $input.all()) {\n  const ctx = item.json;\n  const resp = ctx;\n  let generated = null;\n  let parseError = null;\n  let rawText = '';\n  try {\n    if (resp.error) {\n      parseError = \"api:\" + (resp.error.type || \"unknown\") + \":\" + (resp.error.message || \"\").slice(0,120);\n    } else {\n      rawText = ((resp.content || [])[0] || {}).text || \"\";\n      generated = extractJson(rawText);\n    }\n  } catch (e) {\n    parseError = e.message;\n  }\n  const compliance = generated ? validateCompliance(generated) : {\n    has_pr: false, has_18_plus: false, no_forbidden_words: false,\n    affiliate_link_count: 0, char_count_in_range: false, char_count: 0\n  };\n  const pass = compliance.has_pr && compliance.has_18_plus && compliance.no_forbidden_words\n    && compliance.affiliate_link_count === 1 && compliance.char_count_in_range;\n  out.push({ json: {\n    product_id: ctx.product_id,\n    product_title: ctx.product_title,\n    affiliate_url: ctx.affiliate_url,\n    generated,\n    parseError,\n    rawTextPreview: rawText.slice(0, 120),\n    compliance,\n    pass\n  }});\n}\nreturn out;"
      },
      "id": "validate",
      "name": "Parse & Validate",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1420,
        300
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "i1",
              "leftValue": "={{ $json.pass }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "true"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "if-pass",
      "name": "IF compliance pass",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        1640,
        300
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "={{ $('Config').item.json.wpBaseUrl }}/wp-json/wp/v2/posts",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBasicAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({\n  title: $json.generated.title,\n  content: $json.generated.content_html,\n  excerpt: $json.generated.excerpt,\n  status: 'draft'\n}) }}",
        "options": {
          "timeout": 30000,
          "response": {
            "response": {
              "responseFormat": "json"
            }
          }
        }
      },
      "id": "wp-post",
      "name": "WordPress Draft Post",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1860,
        220
      ],
      "retryOnFail": true,
      "maxTries": 2,
      "waitBetweenTries": 5000,
      "credentials": {
        "httpBasicAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const out = [];\nfor (const it of $input.all()) {\n  const r = it.json;\n  out.push({ json: {\n    product_id: r.product_id,\n    product_title: r.product_title,\n    wp_post_id: (r.id !== undefined) ? r.id : null,\n    wp_link: r.link || null,\n    status: 'draft_created'\n  }});\n}\nreturn out;"
      },
      "id": "success-record",
      "name": "Success Record",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2080,
        220
      ]
    },
    {
      "parameters": {
        "jsCode": "const out = [];\nfor (const it of $input.all()) {\n  const r = it.json;\n  const c = r.compliance || {};\n  const reasons = [];\n  if (r.parseError) reasons.push('parse:' + r.parseError);\n  if (c.has_pr === false) reasons.push('no #PR');\n  if (c.has_18_plus === false) reasons.push('no 18+');\n  if (c.no_forbidden_words === false) reasons.push('forbidden_word');\n  if (c.affiliate_link_count !== undefined && c.affiliate_link_count !== 1) reasons.push('aff_count=' + c.affiliate_link_count);\n  if (c.char_count_in_range === false) reasons.push('char_range_ng');\n  out.push({ json: {\n    product_id: r.product_id || '',\n    product_title: r.product_title || '',\n    wp_post_id: null,\n    wp_link: null,\n    status: 'compliance_failed',\n    failure_reason: reasons.join(' | ') || 'unknown',\n    compliance: c\n  }});\n}\nreturn out;"
      },
      "id": "failure-record",
      "name": "Failure Record",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1860,
        380
      ]
    },
    {
      "parameters": {
        "aggregate": "aggregateAllItemData",
        "options": {
          "mergeLists": false
        }
      },
      "id": "aggregate-success",
      "name": "Aggregate Success",
      "type": "n8n-nodes-base.aggregate",
      "typeVersion": 1,
      "position": [
        2300,
        220
      ]
    },
    {
      "parameters": {
        "jsCode": "const items = ($input.first().json.data) || [];\nconst success = items.filter(i => i.status === 'draft_created');\nconst failed = items.filter(i => i.status !== 'draft_created');\nconst esc = s => String(s||'').replace(/</g,'&lt;');\nconst rowsS = success.map((it, i) => `<tr><td>${i+1}</td><td>${esc(it.product_title)}</td><td>${esc(it.product_id)}</td><td><a href=\"${it.wp_link||'#'}\">\u4e0b\u66f8\u304d\u3092\u958b\u304f</a></td></tr>`).join('');\nconst rowsF = failed.map((it, i) => `<tr><td>${i+1}</td><td>${esc(it.product_title)}</td><td>${esc(it.product_id)}</td><td>${esc(it.failure_reason)}</td></tr>`).join('');\nconst html = `\n<h2>FANZA\u30ec\u30d3\u30e5\u30fc\u81ea\u52d5\u5316 \u5b9f\u884c\u30b5\u30de\u30ea</h2>\n<p>\u5b9f\u884c: ${new Date().toLocaleString('ja-JP')}</p>\n<p>\u4e0b\u66f8\u304d\u6295\u5165: ${success.length}\u4ef6 / \u4e0d\u63a1\u7528: ${failed.length}\u4ef6</p>\n<h3>\u4e0b\u66f8\u304d\u6295\u5165</h3>\n<table border=\"1\" cellpadding=\"6\" style=\"border-collapse:collapse;font-family:sans-serif\">\n  <thead><tr style=\"background:#f0f0f0\"><th>#</th><th>\u4f5c\u54c1\u30bf\u30a4\u30c8\u30eb</th><th>\u5546\u54c1ID</th><th>WP</th></tr></thead>\n  <tbody>${rowsS||'<tr><td colspan=4>\u306a\u3057</td></tr>'}</tbody>\n</table>\n${failed.length ? `<h3>\u30b3\u30f3\u30d7\u30e9\u30a4\u30a2\u30f3\u30b9\u4e0d\u901a\u904e\uff08\u4e0d\u63a1\u7528\uff09</h3>\n<table border=\"1\" cellpadding=\"6\" style=\"border-collapse:collapse;font-family:sans-serif\">\n  <thead><tr style=\"background:#fee\"><th>#</th><th>\u4f5c\u54c1\u30bf\u30a4\u30c8\u30eb</th><th>\u5546\u54c1ID</th><th>\u4e0d\u63a1\u7528\u7406\u7531</th></tr></thead>\n  <tbody>${rowsF}</tbody>\n</table>` : ''}\n<p>\u8a73\u7d30\u306f n8n \u5b9f\u884c\u5c65\u6b74\u3092\u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044\u3002</p>`;\nreturn [{ json: { html, count: success.length, failed: failed.length } }];"
      },
      "id": "build-summary",
      "name": "Build Summary HTML",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2520,
        220
      ]
    },
    {
      "parameters": {
        "fromEmail": "manatsusuki@gmail.com",
        "toEmail": "={{ $('Config').item.json.notifyEmail }}",
        "subject": "=\u3010FANZA\u30ec\u30d3\u30e5\u30fc\u81ea\u52d5\u5316\u3011{{ $now.format('yyyy-MM-dd') }} \u4e0b\u66f8\u304d{{ $json.count }}\u4ef6",
        "html": "={{ $json.html }}",
        "options": {}
      },
      "id": "smtp-send",
      "name": "SMTP Send Summary",
      "type": "n8n-nodes-base.emailSend",
      "typeVersion": 2.1,
      "position": [
        2740,
        220
      ],
      "credentials": {
        "smtp": {
          "name": "<your credential>"
        }
      }
    }
  ],
  "connections": {
    "Schedule Trigger (Weekly Sun 03:00 JST)": {
      "main": [
        [
          {
            "node": "Config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Config": {
      "main": [
        [
          {
            "node": "DMM API ItemList",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "DMM API ItemList": {
      "main": [
        [
          {
            "node": "Extract Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Items": {
      "main": [
        [
          {
            "node": "Build Claude Prompt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Claude Prompt": {
      "main": [
        [
          {
            "node": "Claude Haiku API",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Claude Haiku API": {
      "main": [
        [
          {
            "node": "Parse & Validate",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse & Validate": {
      "main": [
        [
          {
            "node": "IF compliance pass",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF compliance pass": {
      "main": [
        [
          {
            "node": "WordPress Draft Post",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Failure Record",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "WordPress Draft Post": {
      "main": [
        [
          {
            "node": "Success Record",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Success Record": {
      "main": [
        [
          {
            "node": "Aggregate Success",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Failure Record": {
      "main": [
        [
          {
            "node": "Aggregate Success",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Aggregate Success": {
      "main": [
        [
          {
            "node": "Build Summary HTML",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Summary HTML": {
      "main": [
        [
          {
            "node": "SMTP Send Summary",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "saveExecutionProgress": true,
    "saveManualExecutions": true,
    "timezone": "Asia/Tokyo"
  },
  "tags": [
    {
      "name": "fanza-auto-review"
    },
    {
      "name": "track-c"
    }
  ]
}