{
  "schema_version": "1.0",
  "nodes": [
    {
      "id": "price_list",
      "type": "input/data",
      "label": "Price list",
      "parameters": {
        "dataConfig": {
          "assetPath": "__PRICE_LIST__",
          "format": "auto",
          "headerRow": 1,
          "locale": "invariant",
          "formulaPolicy": "cached_value",
          "emptyBehavior": "fail",
          "maxRows": 500
        }
      }
    },
    {
      "id": "vat_rate",
      "type": "input/number",
      "label": "VAT rate",
      "parameters": {
        "value": 0.22,
        "required": true
      }
    },
    {
      "id": "vendor",
      "type": "input/text",
      "label": "Vendor",
      "parameters": {
        "text": "Terra & Glaze",
        "multiline": false,
        "required": true
      }
    },
    {
      "id": "products",
      "type": "enumerate/data_rows",
      "label": "One product per row",
      "parameters": {
        "rowMapping": {
          "columns": [
            {
              "sourceColumn": "SKU",
              "outputPort": "sku",
              "outputType": "text",
              "selected": true,
              "label": "SKU",
              "conversion": "strict"
            },
            {
              "sourceColumn": "Product",
              "outputPort": "name",
              "outputType": "text",
              "selected": true,
              "label": "Product",
              "conversion": "strict"
            },
            {
              "sourceColumn": "Collection",
              "outputPort": "collection",
              "outputType": "text",
              "selected": true,
              "label": "Collection",
              "conversion": "strict"
            },
            {
              "sourceColumn": "Glaze",
              "outputPort": "glaze",
              "outputType": "text",
              "selected": true,
              "label": "Glaze",
              "conversion": "strict"
            },
            {
              "sourceColumn": "Size",
              "outputPort": "size",
              "outputType": "text",
              "selected": true,
              "label": "Size",
              "conversion": "strict"
            },
            {
              "sourceColumn": "Price",
              "outputPort": "price",
              "outputType": "number",
              "selected": true,
              "label": "Price",
              "conversion": "strict"
            },
            {
              "sourceColumn": "Stock",
              "outputPort": "stock",
              "outputType": "number",
              "selected": true,
              "label": "Stock",
              "conversion": "strict"
            },
            {
              "sourceColumn": "Maker notes",
              "outputPort": "notes",
              "outputType": "text",
              "selected": true,
              "label": "Maker notes",
              "conversion": "strict"
            }
          ]
        }
      }
    },
    {
      "id": "in_stock",
      "type": "utility/predicate",
      "label": "In stock",
      "parameters": {
        "operation": "greater_than",
        "compare_number": 0
      }
    },
    {
      "id": "only_in_stock",
      "type": "utility/filter",
      "label": "Only pieces in stock",
      "parameters": {
        "invert": false
      }
    },
    {
      "id": "out_of_stock",
      "type": "utility/filter",
      "label": "Out of stock",
      "parameters": {
        "invert": true
      }
    },
    {
      "id": "brief",
      "type": "text/template",
      "label": "Product brief",
      "parameters": {
        "template": "Product: [name]\nCollection: [collection]\nGlaze: [glaze]\nSize: [size]\nMaker notes: [notes]",
        "placeholders": [
          {
            "name": "name",
            "inputPort": "name"
          },
          {
            "name": "collection",
            "inputPort": "collection"
          },
          {
            "name": "glaze",
            "inputPort": "glaze"
          },
          {
            "name": "size",
            "inputPort": "size"
          },
          {
            "name": "notes",
            "inputPort": "notes"
          }
        ]
      }
    },
    {
      "id": "copy",
      "type": "ai/text_generation",
      "label": "Write the product copy",
      "parameters": {
        "system_prompt": "You write product copy for Terra & Glaze, a small studio that makes handmade stoneware in Faenza, Italy. Voice: warm, precise, unhurried; concrete details over adjectives; no exclamation marks, no clichés such as \"elevate\" or \"perfect for\". Use only the facts you are given. Never invent materials, sizes, certifications or care instructions. Answer with one JSON object with exactly these keys: handle: a URL slug in lowercase letters, digits and hyphens, from the product name and collection; title: the product name as a shopper reads it, at most 70 characters; body_html: two or three short paragraphs of HTML, each in <p>…</p>, 60 to 120 words in total, the last one about use and care; tags: 3 to 8 tags separated by a comma and a space (letters, digits, spaces, & and hyphens only); seo_title: at most 60 characters; seo_description: 70 to 155 characters; image_prompt: one English sentence describing the object for a product photograph: its shape, glaze, colour and size, and nothing about the background or lighting.",
        "response_format": "json_object",
        "temperature": 0.6,
        "max_tokens": 1200
      }
    },
    {
      "id": "check",
      "type": "utility/json_schema_validate",
      "label": "Check the copy",
      "parameters": {
        "schema_source": "inline",
        "schema_definition": "{\n  \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n  \"title\": \"Product copy for the online shop\",\n  \"type\": \"object\",\n  \"required\": [\n    \"handle\",\n    \"title\",\n    \"body_html\",\n    \"tags\",\n    \"seo_title\",\n    \"seo_description\",\n    \"image_prompt\"\n  ],\n  \"properties\": {\n    \"handle\": {\n      \"type\": \"string\",\n      \"pattern\": \"^[a-z0-9]+(-[a-z0-9]+)*$\",\n      \"maxLength\": 60\n    },\n    \"title\": {\n      \"type\": \"string\",\n      \"minLength\": 3,\n      \"maxLength\": 70\n    },\n    \"body_html\": {\n      \"type\": \"string\",\n      \"pattern\": \"^<p>\",\n      \"minLength\": 200,\n      \"maxLength\": 1400\n    },\n    \"tags\": {\n      \"type\": \"string\",\n      \"pattern\": \"^[A-Za-z0-9 &-]+(, [A-Za-z0-9 &-]+){2,7}$\"\n    },\n    \"seo_title\": {\n      \"type\": \"string\",\n      \"minLength\": 20,\n      \"maxLength\": 60\n    },\n    \"seo_description\": {\n      \"type\": \"string\",\n      \"minLength\": 70,\n      \"maxLength\": 155\n    },\n    \"image_prompt\": {\n      \"type\": \"string\",\n      \"minLength\": 40,\n      \"maxLength\": 600\n    }\n  },\n  \"additionalProperties\": false\n}",
        "mode": "route",
        "max_errors": 20
      }
    },
    {
      "id": "handle",
      "type": "utility/extract",
      "label": "Handle",
      "parameters": {
        "path": "handle",
        "expected_type": "text",
        "on_missing": "fail"
      }
    },
    {
      "id": "title",
      "type": "utility/extract",
      "label": "Title",
      "parameters": {
        "path": "title",
        "expected_type": "text",
        "on_missing": "fail"
      }
    },
    {
      "id": "body",
      "type": "utility/extract",
      "label": "Body",
      "parameters": {
        "path": "body_html",
        "expected_type": "text",
        "on_missing": "fail"
      }
    },
    {
      "id": "tags",
      "type": "utility/extract",
      "label": "Tags",
      "parameters": {
        "path": "tags",
        "expected_type": "text",
        "on_missing": "fail"
      }
    },
    {
      "id": "seo_title",
      "type": "utility/extract",
      "label": "SEO title",
      "parameters": {
        "path": "seo_title",
        "expected_type": "text",
        "on_missing": "fail"
      }
    },
    {
      "id": "seo_description",
      "type": "utility/extract",
      "label": "SEO description",
      "parameters": {
        "path": "seo_description",
        "expected_type": "text",
        "on_missing": "fail"
      }
    },
    {
      "id": "image_idea",
      "type": "utility/extract",
      "label": "Image idea",
      "parameters": {
        "path": "image_prompt",
        "expected_type": "text",
        "on_missing": "fail"
      }
    },
    {
      "id": "photo_prompt",
      "type": "text/template",
      "label": "Photo direction",
      "parameters": {
        "template": "[idea] Studio product photograph for an online shop: the object alone, centred, on undyed natural linen, soft north-window daylight from the left, gentle shadow, shallow depth of field, true-to-life colours, no text, no props, no hands.",
        "placeholders": [
          {
            "name": "idea",
            "inputPort": "idea"
          }
        ]
      }
    },
    {
      "id": "photo",
      "type": "ai/text_to_image",
      "label": "Product photo",
      "parameters": {
        "aspect_ratio": "1_1"
      }
    },
    {
      "id": "price_gross",
      "type": "utility/calculate",
      "label": "Price with VAT",
      "parameters": {
        "expression": "round(price * (1 + vat_rate), 2)",
        "decimals": 2
      }
    },
    {
      "id": "needs_review",
      "type": "utility/filter",
      "label": "Needs review",
      "parameters": {
        "invert": true
      }
    },
    {
      "id": "published",
      "type": "utility/constant",
      "label": "Published",
      "parameters": {
        "type": "text",
        "value": "TRUE"
      }
    },
    {
      "id": "status",
      "type": "utility/constant",
      "label": "Status",
      "parameters": {
        "type": "text",
        "value": "active"
      }
    },
    {
      "id": "tracker",
      "type": "utility/constant",
      "label": "Inventory tracker",
      "parameters": {
        "type": "text",
        "value": "shopify"
      }
    },
    {
      "id": "shopify",
      "type": "aggregate/csv",
      "label": "Shopify product CSV",
      "parameters": {
        "csvAggregateConfig": {
          "delimiter": ",",
          "quoteValues": true,
          "includeHeader": true,
          "encoding": "utf-8",
          "outputName": "shopify-products",
          "columns": [
            {
              "name": "Handle",
              "inputPort": "handle",
              "type": "text",
              "whenAbsent": "skip_row"
            },
            {
              "name": "Title",
              "inputPort": "title",
              "type": "text"
            },
            {
              "name": "Body (HTML)",
              "inputPort": "body",
              "type": "text"
            },
            {
              "name": "Vendor",
              "inputPort": "vendor",
              "type": "text"
            },
            {
              "name": "Type",
              "inputPort": "type",
              "type": "text"
            },
            {
              "name": "Tags",
              "inputPort": "tags",
              "type": "text"
            },
            {
              "name": "Published",
              "inputPort": "published",
              "type": "text"
            },
            {
              "name": "Variant SKU",
              "inputPort": "sku",
              "type": "text"
            },
            {
              "name": "Variant Price",
              "inputPort": "price",
              "type": "number"
            },
            {
              "name": "Variant Inventory Tracker",
              "inputPort": "tracker",
              "type": "text"
            },
            {
              "name": "Variant Inventory Qty",
              "inputPort": "qty",
              "type": "number"
            },
            {
              "name": "Image Src",
              "inputPort": "image",
              "type": "image"
            },
            {
              "name": "Image Alt Text",
              "inputPort": "alt",
              "type": "text"
            },
            {
              "name": "SEO Title",
              "inputPort": "seo_title",
              "type": "text"
            },
            {
              "name": "SEO Description",
              "inputPort": "seo_description",
              "type": "text"
            },
            {
              "name": "Status",
              "inputPort": "status",
              "type": "text"
            }
          ]
        }
      }
    },
    {
      "id": "review",
      "type": "aggregate/json",
      "label": "Copy to review",
      "parameters": {
        "emptyBehavior": "empty",
        "jsonAggregateConfig": {
          "prettyPrint": true,
          "outputName": "review",
          "columns": [
            {
              "name": "sku",
              "inputPort": "sku",
              "type": "text",
              "whenAbsent": "skip_row"
            },
            {
              "name": "errors",
              "inputPort": "errors",
              "type": "json",
              "whenAbsent": "null"
            }
          ]
        }
      }
    },
    {
      "id": "not_listed",
      "type": "aggregate/json",
      "label": "Not listed",
      "parameters": {
        "emptyBehavior": "empty",
        "jsonAggregateConfig": {
          "prettyPrint": true,
          "outputName": "not-listed",
          "columns": [
            {
              "name": "sku",
              "inputPort": "sku",
              "type": "text",
              "whenAbsent": "skip_row"
            },
            {
              "name": "product",
              "inputPort": "product",
              "type": "text",
              "whenAbsent": "null"
            }
          ]
        }
      }
    },
    {
      "id": "out_csv",
      "type": "output/csv",
      "label": "Shopify CSV",
      "parameters": {
        "output_name": "shopify_products"
      }
    },
    {
      "id": "out_review",
      "type": "output/json",
      "label": "Review",
      "parameters": {
        "output_name": "copy_to_review"
      }
    },
    {
      "id": "out_not_listed",
      "type": "output/json",
      "label": "Not listed",
      "parameters": {
        "output_name": "not_listed"
      }
    },
    {
      "id": "out_photos",
      "type": "output/image",
      "label": "Photos",
      "parameters": {
        "output_name": "product_photos"
      }
    },
    {
      "id": "out_rows",
      "type": "output/json",
      "label": "Rows read",
      "parameters": {
        "output_name": "rows_read"
      }
    }
  ],
  "connections": [
    {
      "from_node": "price_list",
      "from_output": "dataset",
      "to_node": "products",
      "to_input": "dataset"
    },
    {
      "from_node": "price_list",
      "from_output": "row_count",
      "to_node": "out_rows",
      "to_input": "json"
    },
    {
      "from_node": "products",
      "from_output": "stock",
      "to_node": "in_stock",
      "to_input": "a"
    },
    {
      "from_node": "in_stock",
      "from_output": "result",
      "to_node": "only_in_stock",
      "to_input": "condition"
    },
    {
      "from_node": "products",
      "from_output": "name",
      "to_node": "only_in_stock",
      "to_input": "value"
    },
    {
      "from_node": "in_stock",
      "from_output": "result",
      "to_node": "out_of_stock",
      "to_input": "condition"
    },
    {
      "from_node": "products",
      "from_output": "sku",
      "to_node": "out_of_stock",
      "to_input": "value"
    },
    {
      "from_node": "only_in_stock",
      "from_output": "value",
      "to_node": "brief",
      "to_input": "name"
    },
    {
      "from_node": "products",
      "from_output": "collection",
      "to_node": "brief",
      "to_input": "collection"
    },
    {
      "from_node": "products",
      "from_output": "glaze",
      "to_node": "brief",
      "to_input": "glaze"
    },
    {
      "from_node": "products",
      "from_output": "size",
      "to_node": "brief",
      "to_input": "size"
    },
    {
      "from_node": "products",
      "from_output": "notes",
      "to_node": "brief",
      "to_input": "notes"
    },
    {
      "from_node": "brief",
      "from_output": "result",
      "to_node": "copy",
      "to_input": "prompt"
    },
    {
      "from_node": "copy",
      "from_output": "json",
      "to_node": "check",
      "to_input": "document"
    },
    {
      "from_node": "check",
      "from_output": "normalized_json",
      "to_node": "handle",
      "to_input": "json"
    },
    {
      "from_node": "check",
      "from_output": "normalized_json",
      "to_node": "title",
      "to_input": "json"
    },
    {
      "from_node": "check",
      "from_output": "normalized_json",
      "to_node": "body",
      "to_input": "json"
    },
    {
      "from_node": "check",
      "from_output": "normalized_json",
      "to_node": "tags",
      "to_input": "json"
    },
    {
      "from_node": "check",
      "from_output": "normalized_json",
      "to_node": "seo_title",
      "to_input": "json"
    },
    {
      "from_node": "check",
      "from_output": "normalized_json",
      "to_node": "seo_description",
      "to_input": "json"
    },
    {
      "from_node": "check",
      "from_output": "normalized_json",
      "to_node": "image_idea",
      "to_input": "json"
    },
    {
      "from_node": "image_idea",
      "from_output": "value",
      "to_node": "photo_prompt",
      "to_input": "idea"
    },
    {
      "from_node": "photo_prompt",
      "from_output": "result",
      "to_node": "photo",
      "to_input": "prompt"
    },
    {
      "from_node": "products",
      "from_output": "price",
      "to_node": "price_gross",
      "to_input": "price"
    },
    {
      "from_node": "vat_rate",
      "from_output": "number",
      "to_node": "price_gross",
      "to_input": "vat_rate"
    },
    {
      "from_node": "check",
      "from_output": "valid",
      "to_node": "needs_review",
      "to_input": "condition"
    },
    {
      "from_node": "products",
      "from_output": "sku",
      "to_node": "needs_review",
      "to_input": "value"
    },
    {
      "from_node": "handle",
      "from_output": "value",
      "to_node": "shopify",
      "to_input": "handle"
    },
    {
      "from_node": "title",
      "from_output": "value",
      "to_node": "shopify",
      "to_input": "title"
    },
    {
      "from_node": "body",
      "from_output": "value",
      "to_node": "shopify",
      "to_input": "body"
    },
    {
      "from_node": "vendor",
      "from_output": "text",
      "to_node": "shopify",
      "to_input": "vendor"
    },
    {
      "from_node": "products",
      "from_output": "collection",
      "to_node": "shopify",
      "to_input": "type"
    },
    {
      "from_node": "tags",
      "from_output": "value",
      "to_node": "shopify",
      "to_input": "tags"
    },
    {
      "from_node": "published",
      "from_output": "value",
      "to_node": "shopify",
      "to_input": "published"
    },
    {
      "from_node": "products",
      "from_output": "sku",
      "to_node": "shopify",
      "to_input": "sku"
    },
    {
      "from_node": "price_gross",
      "from_output": "result",
      "to_node": "shopify",
      "to_input": "price"
    },
    {
      "from_node": "tracker",
      "from_output": "value",
      "to_node": "shopify",
      "to_input": "tracker"
    },
    {
      "from_node": "products",
      "from_output": "stock",
      "to_node": "shopify",
      "to_input": "qty"
    },
    {
      "from_node": "photo",
      "from_output": "result",
      "to_node": "shopify",
      "to_input": "image"
    },
    {
      "from_node": "title",
      "from_output": "value",
      "to_node": "shopify",
      "to_input": "alt"
    },
    {
      "from_node": "seo_title",
      "from_output": "value",
      "to_node": "shopify",
      "to_input": "seo_title"
    },
    {
      "from_node": "seo_description",
      "from_output": "value",
      "to_node": "shopify",
      "to_input": "seo_description"
    },
    {
      "from_node": "status",
      "from_output": "value",
      "to_node": "shopify",
      "to_input": "status"
    },
    {
      "from_node": "needs_review",
      "from_output": "value",
      "to_node": "review",
      "to_input": "sku"
    },
    {
      "from_node": "check",
      "from_output": "errors",
      "to_node": "review",
      "to_input": "errors"
    },
    {
      "from_node": "out_of_stock",
      "from_output": "value",
      "to_node": "not_listed",
      "to_input": "sku"
    },
    {
      "from_node": "products",
      "from_output": "name",
      "to_node": "not_listed",
      "to_input": "product"
    },
    {
      "from_node": "shopify",
      "from_output": "result",
      "to_node": "out_csv",
      "to_input": "csv"
    },
    {
      "from_node": "review",
      "from_output": "result",
      "to_node": "out_review",
      "to_input": "json"
    },
    {
      "from_node": "not_listed",
      "from_output": "result",
      "to_node": "out_not_listed",
      "to_input": "json"
    },
    {
      "from_node": "photo",
      "from_output": "result",
      "to_node": "out_photos",
      "to_input": "image"
    }
  ]
}
