{
  "schema_version": "1.0",
  "nodes": [
    {
      "id": "hotel_facts",
      "type": "input/text",
      "label": "Hotel facts",
      "parameters": {
        "text": "Villa Aurora, Malcesine (Lago di Garda, sponda veronese). Villa del 1906 restaurata nel 2021.\n14 camere, tutte vista lago; alcune con balcone. Colazione servita in terrazza o in camera.\nPiccola spa con piscina interna riscaldata vista lago, sauna finlandese, bagno turco, due cabine per trattamenti.\nRistorante \"La Limonaia\": cucina del Garda (pesce di lago, olio extravergine DOP del Garda, risotti), carta dei vini\ncon cantine della Valpolicella e del Lugana. Giardino con olivi e limoni. Parcheggio privato gratuito.\nA 5 minuti a piedi dal centro storico e dalla funivia del Monte Baldo. Aeroporto di Verona a 75 minuti.",
        "multiline": true,
        "required": true
      }
    },
    {
      "id": "segment",
      "type": "input/text",
      "label": "Audience",
      "parameters": {
        "text": "Coppie giovani (25–35 anni) che cercano un weekend romantico e rigenerante, lontano dalla folla estiva.",
        "multiline": true,
        "required": true
      }
    },
    {
      "id": "period",
      "type": "input/text",
      "label": "Period",
      "parameters": {
        "text": "Weekend di novembre e dicembre 2026: bassa stagione, lago calmo, colori d'autunno, primi mercatini di Natale nei borghi.",
        "multiline": true,
        "required": true
      }
    },
    {
      "id": "offer",
      "type": "input/json_value",
      "label": "Verified offer (IT/EN)",
      "parameters": {
        "required": true
      }
    },
    {
      "id": "price",
      "type": "input/number",
      "label": "Price per person (EUR)",
      "parameters": {
        "value": 290,
        "required": true
      }
    },
    {
      "id": "booking_code",
      "type": "input/text",
      "label": "Booking code",
      "parameters": {
        "text": "AURORA26",
        "multiline": false,
        "required": true
      }
    },
    {
      "id": "contact",
      "type": "input/text",
      "label": "Contact",
      "parameters": {
        "text": "Via Lungolago 12, Malcesine (VR) · +39 045 555 0199 · stay@villa-aurora.example · villa-aurora.example",
        "multiline": false,
        "required": true
      }
    },
    {
      "id": "exterior_photo",
      "type": "input/image",
      "label": "Photo — exterior",
      "parameters": {
        "image": "__PHOTO_EXTERIOR_ASSET_PATH__",
        "required": true
      }
    },
    {
      "id": "spa_photo",
      "type": "input/image",
      "label": "Photo — spa",
      "parameters": {
        "image": "__PHOTO_SPA_ASSET_PATH__",
        "required": true
      }
    },
    {
      "id": "room_photo",
      "type": "input/image",
      "label": "Photo — room",
      "parameters": {
        "image": "__PHOTO_ROOM_ASSET_PATH__",
        "required": true
      }
    },
    {
      "id": "restaurant_photo",
      "type": "input/image",
      "label": "Photo — restaurant",
      "parameters": {
        "image": "__PHOTO_RESTAURANT_ASSET_PATH__",
        "required": true
      }
    },
    {
      "id": "brief",
      "type": "text/template",
      "label": "Compose the brief",
      "parameters": {
        "template": "HOTEL (fatti verificati)\n[hotel_facts]\n\nPUBBLICO DELLA CAMPAGNA\n[segment]\n\nPERIODO DELLA CAMPAGNA\n[period]",
        "placeholders": [
          {
            "name": "hotel_facts",
            "inputPort": "hotel_facts"
          },
          {
            "name": "segment",
            "inputPort": "segment"
          },
          {
            "name": "period",
            "inputPort": "period"
          }
        ]
      }
    },
    {
      "id": "copywriter",
      "type": "ai/text_generation",
      "label": "Write the copy (IT/EN)",
      "parameters": {
        "system_prompt": "You are the senior copywriter of an Italian boutique-hotel group. From the verified hotel facts, the\ncampaign audience and the campaign period, write the copy of a four-page campaign brochure, in Italian\n(\"it\") and in English (\"en\"). The English version is written for international guests, not translated\nword by word.\n\nRules:\n- Use only facts contained in the hotel facts. Do not invent services, awards, distances or events.\n- Never write prices, discounts, dates, package contents or conditions: they are printed from the\n  verified offer. You may name the season (autumn, November and December) in general terms.\n- Speak to the audience directly and warmly, second person plural in Italian (\"voi\"), no superlatives,\n  no exclamation marks, no clichés such as \"paradiso\" or \"oasi\".\n- Keep strictly within the character limits: they are the space on the printed page.\n\nReturn one JSON object and nothing else: { \"it\": COPY, \"en\": COPY, \"cover_edit_prompt\": \"...\" } where COPY has:\n- \"cover_title\": at most 48 characters; the cover prints it on one or two lines and keeps it at the bottom.\n- \"cover_subtitle\": at most 110 characters.\n- \"experience_title\": at most 36 characters, one line.\n- \"experience_intro\": 200 to 430 characters: what this weekend feels like for this audience in this season.\n- \"highlights\": exactly 3 objects { \"title\" (max 30), \"text\" (60–200) }: three moments of the stay drawn from the facts.\n- \"stay_title\": at most 36 characters, one line.\n- \"day\": exactly 4 objects { \"moment\" (max 16, e.g. \"Mattina\"/\"Morning\"), \"text\" (50–130, a hard limit: the four rows share one fixed area) }: a day at the villa.\n- \"offer_intro\": 80 to 260 characters introducing the package, without listing its contents or price.\n- \"cta\": at most 44 characters, an invitation to book.\n\"cover_edit_prompt\": in English, at most 600 characters, an instruction for an image-editing model that\nreceives the hotel's summer photo of its facade: turn it into the campaign season (late autumn, golden hour\ntowards evening, warm lights in the windows, autumn tones in the garden, calm lake, soft mist on the\nmountains) while keeping the building, its architecture, colours and composition exactly the same.\nNo people, no text, no signs.",
        "response_format": "json_object",
        "temperature": 0.5,
        "max_tokens": 4000
      }
    },
    {
      "id": "copy_contract",
      "type": "utility/json_schema_validate",
      "label": "Copy fits the brochure",
      "parameters": {
        "schema_source": "inline",
        "schema_definition": {
          "$schema": "https://json-schema.org/draft/2020-12/schema",
          "$id": "urn:madoo:demo:f02-hotel-campaign-copy/v1",
          "title": "Bilingual hotel campaign copy",
          "type": "object",
          "additionalProperties": false,
          "required": [
            "it",
            "en",
            "cover_edit_prompt"
          ],
          "properties": {
            "it": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "cover_title",
                "cover_subtitle",
                "experience_title",
                "experience_intro",
                "highlights",
                "stay_title",
                "day",
                "offer_intro",
                "cta"
              ],
              "properties": {
                "cover_title": {
                  "type": "string",
                  "minLength": 12,
                  "maxLength": 48
                },
                "cover_subtitle": {
                  "type": "string",
                  "minLength": 40,
                  "maxLength": 110
                },
                "experience_title": {
                  "type": "string",
                  "minLength": 10,
                  "maxLength": 36
                },
                "experience_intro": {
                  "type": "string",
                  "minLength": 200,
                  "maxLength": 430
                },
                "highlights": {
                  "type": "array",
                  "minItems": 3,
                  "maxItems": 3,
                  "items": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "title",
                      "text"
                    ],
                    "properties": {
                      "title": {
                        "type": "string",
                        "minLength": 4,
                        "maxLength": 30
                      },
                      "text": {
                        "type": "string",
                        "minLength": 60,
                        "maxLength": 200
                      }
                    }
                  }
                },
                "stay_title": {
                  "type": "string",
                  "minLength": 10,
                  "maxLength": 36
                },
                "day": {
                  "type": "array",
                  "minItems": 4,
                  "maxItems": 4,
                  "items": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "moment",
                      "text"
                    ],
                    "properties": {
                      "moment": {
                        "type": "string",
                        "minLength": 3,
                        "maxLength": 16
                      },
                      "text": {
                        "type": "string",
                        "minLength": 50,
                        "maxLength": 130
                      }
                    }
                  }
                },
                "offer_intro": {
                  "type": "string",
                  "minLength": 80,
                  "maxLength": 260
                },
                "cta": {
                  "type": "string",
                  "minLength": 8,
                  "maxLength": 44
                }
              }
            },
            "en": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "cover_title",
                "cover_subtitle",
                "experience_title",
                "experience_intro",
                "highlights",
                "stay_title",
                "day",
                "offer_intro",
                "cta"
              ],
              "properties": {
                "cover_title": {
                  "type": "string",
                  "minLength": 12,
                  "maxLength": 48
                },
                "cover_subtitle": {
                  "type": "string",
                  "minLength": 40,
                  "maxLength": 110
                },
                "experience_title": {
                  "type": "string",
                  "minLength": 10,
                  "maxLength": 36
                },
                "experience_intro": {
                  "type": "string",
                  "minLength": 200,
                  "maxLength": 430
                },
                "highlights": {
                  "type": "array",
                  "minItems": 3,
                  "maxItems": 3,
                  "items": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "title",
                      "text"
                    ],
                    "properties": {
                      "title": {
                        "type": "string",
                        "minLength": 4,
                        "maxLength": 30
                      },
                      "text": {
                        "type": "string",
                        "minLength": 60,
                        "maxLength": 200
                      }
                    }
                  }
                },
                "stay_title": {
                  "type": "string",
                  "minLength": 10,
                  "maxLength": 36
                },
                "day": {
                  "type": "array",
                  "minItems": 4,
                  "maxItems": 4,
                  "items": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "moment",
                      "text"
                    ],
                    "properties": {
                      "moment": {
                        "type": "string",
                        "minLength": 3,
                        "maxLength": 16
                      },
                      "text": {
                        "type": "string",
                        "minLength": 50,
                        "maxLength": 130
                      }
                    }
                  }
                },
                "offer_intro": {
                  "type": "string",
                  "minLength": 80,
                  "maxLength": 260
                },
                "cta": {
                  "type": "string",
                  "minLength": 8,
                  "maxLength": 44
                }
              }
            },
            "cover_edit_prompt": {
              "type": "string",
              "minLength": 80,
              "maxLength": 600
            }
          }
        },
        "mode": "fail"
      }
    },
    {
      "id": "copy_it",
      "type": "utility/extract",
      "label": "Italian copy",
      "parameters": {
        "path": "it",
        "expected_type": "json",
        "on_missing": "fail"
      }
    },
    {
      "id": "copy_en",
      "type": "utility/extract",
      "label": "English copy",
      "parameters": {
        "path": "en",
        "expected_type": "json",
        "on_missing": "fail"
      }
    },
    {
      "id": "edit_prompt",
      "type": "utility/extract",
      "label": "Season edit",
      "parameters": {
        "path": "cover_edit_prompt",
        "expected_type": "text",
        "on_missing": "fail"
      }
    },
    {
      "id": "offer_it",
      "type": "utility/extract",
      "label": "Italian offer",
      "parameters": {
        "path": "it",
        "expected_type": "json",
        "on_missing": "fail"
      }
    },
    {
      "id": "offer_en",
      "type": "utility/extract",
      "label": "English offer",
      "parameters": {
        "path": "en",
        "expected_type": "json",
        "on_missing": "fail"
      }
    },
    {
      "id": "autumn_cover",
      "type": "ai/image_transform",
      "label": "Bring the facade into the season",
      "parameters": {
        "aspect_ratio": "match_input"
      }
    },
    {
      "id": "render_it",
      "type": "design/template_render",
      "label": "Compose the Italian brochure",
      "parameters": {
        "template_id": "__TEMPLATE_ID__",
        "template_revision": "__TEMPLATE_REVISION__",
        "output": "both",
        "page_selection": "all",
        "missing_policy": "fail_required",
        "overflow_policy": "template",
        "max_repeat": 10,
        "pdf_export_mode": "pdfx4",
        "color_profile_guid": "__FOGRA39_PROFILE_GUID__"
      }
    },
    {
      "id": "render_en",
      "type": "design/template_render",
      "label": "Compose the English brochure",
      "parameters": {
        "template_id": "__TEMPLATE_ID__",
        "template_revision": "__TEMPLATE_REVISION__",
        "output": "both",
        "page_selection": "all",
        "missing_policy": "fail_required",
        "overflow_policy": "template",
        "max_repeat": 10,
        "pdf_export_mode": "pdfx4",
        "color_profile_guid": "__FOGRA39_PROFILE_GUID__"
      }
    },
    {
      "id": "brochure_it",
      "type": "output/pdf",
      "label": "Brochure IT — print PDF",
      "parameters": {
        "output_name": "brochure_it"
      }
    },
    {
      "id": "brochure_en",
      "type": "output/pdf",
      "label": "Brochure EN — print PDF",
      "parameters": {
        "output_name": "brochure_en"
      }
    },
    {
      "id": "pages_it",
      "type": "output/json",
      "label": "Pages IT — images",
      "parameters": {
        "output_name": "pages_it"
      }
    },
    {
      "id": "pages_en",
      "type": "output/json",
      "label": "Pages EN — images",
      "parameters": {
        "output_name": "pages_en"
      }
    },
    {
      "id": "cover_out",
      "type": "output/image",
      "label": "Autumn cover photo",
      "parameters": {
        "output_name": "autumn_cover"
      }
    },
    {
      "id": "copy_out",
      "type": "output/json",
      "label": "Approved copy (IT/EN)",
      "parameters": {
        "output_name": "campaign_copy"
      }
    }
  ],
  "connections": [
    {
      "from_node": "hotel_facts",
      "from_output": "text",
      "to_node": "brief",
      "to_input": "hotel_facts"
    },
    {
      "from_node": "segment",
      "from_output": "text",
      "to_node": "brief",
      "to_input": "segment"
    },
    {
      "from_node": "period",
      "from_output": "text",
      "to_node": "brief",
      "to_input": "period"
    },
    {
      "from_node": "brief",
      "from_output": "result",
      "to_node": "copywriter",
      "to_input": "prompt"
    },
    {
      "from_node": "copywriter",
      "from_output": "json",
      "to_node": "copy_contract",
      "to_input": "document"
    },
    {
      "from_node": "copy_contract",
      "from_output": "normalized_json",
      "to_node": "copy_it",
      "to_input": "json"
    },
    {
      "from_node": "copy_contract",
      "from_output": "normalized_json",
      "to_node": "copy_en",
      "to_input": "json"
    },
    {
      "from_node": "copy_contract",
      "from_output": "normalized_json",
      "to_node": "edit_prompt",
      "to_input": "json"
    },
    {
      "from_node": "copy_contract",
      "from_output": "normalized_json",
      "to_node": "copy_out",
      "to_input": "json"
    },
    {
      "from_node": "offer",
      "from_output": "json",
      "to_node": "offer_it",
      "to_input": "json"
    },
    {
      "from_node": "offer",
      "from_output": "json",
      "to_node": "offer_en",
      "to_input": "json"
    },
    {
      "from_node": "exterior_photo",
      "from_output": "image",
      "to_node": "autumn_cover",
      "to_input": "images_0"
    },
    {
      "from_node": "edit_prompt",
      "from_output": "value",
      "to_node": "autumn_cover",
      "to_input": "prompt"
    },
    {
      "from_node": "autumn_cover",
      "from_output": "result",
      "to_node": "cover_out",
      "to_input": "image"
    },
    {
      "from_node": "copy_it",
      "from_output": "value",
      "to_node": "render_it",
      "to_input": "data_0"
    },
    {
      "from_node": "offer_it",
      "from_output": "value",
      "to_node": "render_it",
      "to_input": "data_1"
    },
    {
      "from_node": "autumn_cover",
      "from_output": "result",
      "to_node": "render_it",
      "to_input": "cover_image"
    },
    {
      "from_node": "autumn_cover",
      "from_output": "result",
      "to_node": "render_it",
      "to_input": "strip_image"
    },
    {
      "from_node": "spa_photo",
      "from_output": "image",
      "to_node": "render_it",
      "to_input": "spa_image"
    },
    {
      "from_node": "room_photo",
      "from_output": "image",
      "to_node": "render_it",
      "to_input": "room_image"
    },
    {
      "from_node": "restaurant_photo",
      "from_output": "image",
      "to_node": "render_it",
      "to_input": "restaurant_image"
    },
    {
      "from_node": "price",
      "from_output": "number",
      "to_node": "render_it",
      "to_input": "price"
    },
    {
      "from_node": "booking_code",
      "from_output": "text",
      "to_node": "render_it",
      "to_input": "booking_code"
    },
    {
      "from_node": "contact",
      "from_output": "text",
      "to_node": "render_it",
      "to_input": "contact"
    },
    {
      "from_node": "render_it",
      "from_output": "pdf",
      "to_node": "brochure_it",
      "to_input": "pdf"
    },
    {
      "from_node": "render_it",
      "from_output": "pages_manifest",
      "to_node": "pages_it",
      "to_input": "json"
    },
    {
      "from_node": "copy_en",
      "from_output": "value",
      "to_node": "render_en",
      "to_input": "data_0"
    },
    {
      "from_node": "offer_en",
      "from_output": "value",
      "to_node": "render_en",
      "to_input": "data_1"
    },
    {
      "from_node": "autumn_cover",
      "from_output": "result",
      "to_node": "render_en",
      "to_input": "cover_image"
    },
    {
      "from_node": "autumn_cover",
      "from_output": "result",
      "to_node": "render_en",
      "to_input": "strip_image"
    },
    {
      "from_node": "spa_photo",
      "from_output": "image",
      "to_node": "render_en",
      "to_input": "spa_image"
    },
    {
      "from_node": "room_photo",
      "from_output": "image",
      "to_node": "render_en",
      "to_input": "room_image"
    },
    {
      "from_node": "restaurant_photo",
      "from_output": "image",
      "to_node": "render_en",
      "to_input": "restaurant_image"
    },
    {
      "from_node": "price",
      "from_output": "number",
      "to_node": "render_en",
      "to_input": "price"
    },
    {
      "from_node": "booking_code",
      "from_output": "text",
      "to_node": "render_en",
      "to_input": "booking_code"
    },
    {
      "from_node": "contact",
      "from_output": "text",
      "to_node": "render_en",
      "to_input": "contact"
    },
    {
      "from_node": "render_en",
      "from_output": "pdf",
      "to_node": "brochure_en",
      "to_input": "pdf"
    },
    {
      "from_node": "render_en",
      "from_output": "pages_manifest",
      "to_node": "pages_en",
      "to_input": "json"
    }
  ],
  "layout": {
    "nodes": {
      "hotel_facts": {
        "x": 0,
        "y": 0
      },
      "segment": {
        "x": 0,
        "y": 180
      },
      "period": {
        "x": 0,
        "y": 360
      },
      "exterior_photo": {
        "x": 0,
        "y": 560
      },
      "spa_photo": {
        "x": 0,
        "y": 740
      },
      "room_photo": {
        "x": 0,
        "y": 920
      },
      "restaurant_photo": {
        "x": 0,
        "y": 1100
      },
      "offer": {
        "x": 0,
        "y": 1300
      },
      "price": {
        "x": 0,
        "y": 1480
      },
      "booking_code": {
        "x": 0,
        "y": 1640
      },
      "contact": {
        "x": 0,
        "y": 1800
      },
      "brief": {
        "x": 420,
        "y": 160
      },
      "copywriter": {
        "x": 840,
        "y": 160
      },
      "copy_contract": {
        "x": 1260,
        "y": 160
      },
      "copy_it": {
        "x": 1680,
        "y": 60
      },
      "copy_en": {
        "x": 1680,
        "y": 240
      },
      "edit_prompt": {
        "x": 1680,
        "y": 460
      },
      "offer_it": {
        "x": 1680,
        "y": 1300
      },
      "offer_en": {
        "x": 1680,
        "y": 1480
      },
      "autumn_cover": {
        "x": 2100,
        "y": 560
      },
      "copy_out": {
        "x": 2100,
        "y": 160
      },
      "cover_out": {
        "x": 2580,
        "y": 560
      },
      "render_it": {
        "x": 2580,
        "y": 900
      },
      "render_en": {
        "x": 2580,
        "y": 1300
      },
      "brochure_it": {
        "x": 3060,
        "y": 860
      },
      "pages_it": {
        "x": 3060,
        "y": 1020
      },
      "brochure_en": {
        "x": 3060,
        "y": 1260
      },
      "pages_en": {
        "x": 3060,
        "y": 1420
      }
    }
  }
}
