{
  "name": "apizt ecommerce drafts - manual review required",
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "nodes": [
    {
      "id": "manual",
      "name": "Manual Trigger",
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        0,
        0
      ],
      "parameters": {}
    },
    {
      "id": "facts",
      "name": "Product facts",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        240,
        0
      ],
      "parameters": {
        "jsCode": "const rows = [{\"sku\": \"DEMO-CUP-01\", \"name\": \"示例随行杯\", \"material\": \"不锈钢\", \"dimensions\": \"容量 350 ml\", \"approved_claims\": \"可拆卸杯盖\", \"forbidden_claims\": \"不得推断食品安全认证、产地或保温时长\"}, {\"sku\": \"DEMO-BAG-02\", \"name\": \"示例帆布袋\", \"material\": \"棉帆布\", \"dimensions\": \"宽 30 cm，高 35 cm\", \"approved_claims\": \"单个内袋\", \"forbidden_claims\": \"不得推断防水、负重、环保认证或优惠\"}];\nconst ids=new Set();\nfor (const row of rows) { if (!row.sku || ids.has(row.sku) || !row.name || !row.approved_claims) throw new Error(\"Invalid or duplicate SKU\"); ids.add(row.sku); }\nreturn rows.map(json=>({json}));"
      }
    },
    {
      "id": "http",
      "name": "apizt draft",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        480,
        0
      ],
      "retryOnFail": false,
      "onError": "continueRegularOutput",
      "parameters": {
        "method": "POST",
        "url": "https://api.apizt.com/v1/chat/completions",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({model:\"glm-5.3\",messages:[{role:\"system\",content:\"Prepare ecommerce drafts in Chinese. Return ONLY JSON: sku, title, bullets (exactly 3 strings), image_prompt. Preserve sku. Use only provided facts. Missing facts must not be invented. No certifications, discounts, origin, health or performance claims beyond approved_claims. No tools.\"},{role:\"user\",content:JSON.stringify($json)}],max_tokens:800}) }}",
        "options": {
          "timeout": 60000,
          "batching": {
            "batch": {
              "batchSize": 1,
              "batchInterval": 1000
            }
          }
        }
      }
    },
    {
      "id": "validate",
      "name": "Validate drafts",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        720,
        0
      ],
      "parameters": {
        "jsCode": "const sources = $('Product facts').all();\nconst responses = $input.all();\nreturn sources.map((item,index) => {\n const source=item.json; const body=responses[index]?.json??{};\n const choice=body.choices?.[0]; let parsed=null;\n try { parsed=JSON.parse(choice?.message?.content??''); } catch {}\n const code=Number(body.error?.statusCode??body.error?.httpCode??body.statusCode??0);\n const uncertain=!responses[index] || (Boolean(body.error) && (!code || code>=500 || code===408));\n const valid=responses.length===sources.length && !body.error && choice?.finish_reason==='stop' && parsed?.sku===source.sku && typeof parsed?.title==='string' && parsed.title.trim().length>0 && parsed.title.length<=160 && Array.isArray(parsed.bullets) && parsed.bullets.length===3 && parsed.bullets.every(v=>typeof v==='string' && v.trim().length>0 && v.length<=300) && typeof parsed?.image_prompt==='string' && parsed.image_prompt.trim().length>0 && parsed.image_prompt.length<=2000;\n return {json:{sku:source.sku,status:valid?'draft':uncertain?'unknown':'failed',draft:valid?parsed:null,facts:source,manual_review_required:true,usage:body.usage??null,response_id:body.id??null,error_type:valid?null:uncertain?'outcome_unknown':'response_or_schema_failed'}};\n});"
      }
    }
  ],
  "connections": {
    "Manual Trigger": {
      "main": [
        [
          {
            "node": "Product facts",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Product facts": {
      "main": [
        [
          {
            "node": "apizt draft",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "apizt draft": {
      "main": [
        [
          {
            "node": "Validate drafts",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
