{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://keepthisday.com/ai/wedding-draft.schema.json",
  "title": "Keep This Day wedding draft",
  "description": "Everything needed to set up a free Keep This Day wedding website. Paste the JSON at keepthisday.com/host, or hand it to a connector. Guests can be listed under `guests` or in a separate CSV. Unknown keys are ignored.",
  "type": "object",
  "properties": {
    "format": {
      "const": "keepthisday.wedding-draft",
      "description": "Always \"keepthisday.wedding-draft\"."
    },
    "version": {
      "const": 1,
      "description": "Format version. Always 1."
    },
    "couple": {
      "type": "object",
      "description": "The two people getting married.",
      "properties": {
        "partner1": {
          "type": "string",
          "maxLength": 60,
          "description": "First partner's name as it should appear, e.g. \"Maya\"."
        },
        "partner2": {
          "type": "string",
          "maxLength": 60,
          "description": "Second partner's name, e.g. \"Daniel\"."
        }
      },
      "required": [
        "partner1",
        "partner2"
      ],
      "additionalProperties": true
    },
    "date": {
      "type": "string",
      "maxLength": 10,
      "description": "Wedding date as YYYY-MM-DD. Leave out if it is not decided.",
      "format": "date",
      "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
    },
    "time": {
      "type": "string",
      "maxLength": 5,
      "description": "Start time, 24-hour HH:MM, e.g. \"16:30\". Leave out if unknown.",
      "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$"
    },
    "venue": {
      "type": "object",
      "description": "Where it happens.",
      "properties": {
        "name": {
          "type": "string",
          "maxLength": 120,
          "description": "Venue name."
        },
        "address": {
          "type": "string",
          "maxLength": 240,
          "description": "Street address."
        },
        "map_url": {
          "type": "string",
          "maxLength": 2000,
          "description": "Google Maps or Apple Maps link (https).",
          "format": "uri"
        }
      },
      "additionalProperties": true
    },
    "theme": {
      "type": "string",
      "enum": [
        "editorial",
        "botanical",
        "rose",
        "midnight",
        "azure",
        "coral"
      ],
      "description": "Look of the website. One of: editorial (Cloud), botanical (Something blue), rose (Blush), midnight (Afterglow), azure (Coast), coral (Terracotta)."
    },
    "appearance": {
      "type": "object",
      "description": "Optional fine-tuning on top of the theme. Leave out to keep the theme's own look.",
      "properties": {
        "font": {
          "type": "string",
          "enum": [
            "serif",
            "sans",
            "script"
          ],
          "description": "Heading font: serif (editorial), sans (modern), script (romantic)."
        },
        "layout": {
          "type": "string",
          "enum": [
            "immersive",
            "framed",
            "split"
          ],
          "description": "Cover layout: immersive (full photo), framed, or split."
        },
        "colors": {
          "type": "object",
          "description": "Only set colours the couple actually asked for.",
          "properties": {
            "background": {
              "type": "string",
              "maxLength": 7,
              "description": "Page background, hex like #fff9f8.",
              "pattern": "^#[0-9a-fA-F]{6}$"
            },
            "text": {
              "type": "string",
              "maxLength": 7,
              "description": "Text colour, hex.",
              "pattern": "^#[0-9a-fA-F]{6}$"
            },
            "accent": {
              "type": "string",
              "maxLength": 7,
              "description": "Buttons and highlights, hex.",
              "pattern": "^#[0-9a-fA-F]{6}$"
            }
          },
          "additionalProperties": true
        }
      },
      "additionalProperties": true
    },
    "headline": {
      "type": "string",
      "maxLength": 300,
      "description": "A short welcome shown on the cover, in the couple's own words. Plain, no slogans."
    },
    "dress_code": {
      "type": "string",
      "maxLength": 600,
      "description": "Dress code, e.g. \"Garden party, light colours\"."
    },
    "hashtag": {
      "type": "string",
      "maxLength": 60,
      "description": "Wedding hashtag, if they have one."
    },
    "schedule": {
      "type": "array",
      "maxItems": 40,
      "description": "The day's schedule, in order.",
      "items": {
        "type": "object",
        "description": "One row of the day's schedule.",
        "properties": {
          "time": {
            "type": "string",
            "maxLength": 20,
            "description": "Display time, e.g. \"4:00 PM\"."
          },
          "title": {
            "type": "string",
            "maxLength": 120,
            "description": "What happens, e.g. \"Ceremony\"."
          },
          "note": {
            "type": "string",
            "maxLength": 240,
            "description": "Optional detail, e.g. \"Doors open at 3:30 PM\"."
          }
        },
        "additionalProperties": true
      }
    },
    "pages": {
      "type": "object",
      "description": "The website's info pages. A page with content is switched on automatically.",
      "properties": {
        "story": {
          "type": "object",
          "description": "Our story.",
          "properties": {
            "on": {
              "type": "boolean",
              "description": "Show this page. Defaults to true when the page has content."
            },
            "title": {
              "type": "string",
              "maxLength": 80,
              "description": "Page title, e.g. \"How we met\"."
            },
            "body": {
              "type": "string",
              "maxLength": 6000,
              "description": "The story. Separate paragraphs with a blank line."
            }
          },
          "additionalProperties": true
        },
        "travel": {
          "type": "object",
          "description": "Travel and stay.",
          "properties": {
            "on": {
              "type": "boolean",
              "description": "Show this page. Defaults to true when the page has content."
            },
            "intro": {
              "type": "string",
              "maxLength": 2000,
              "description": "Intro text."
            },
            "items": {
              "type": "array",
              "maxItems": 20,
              "description": "Places to stay or ways to get there.",
              "items": {
                "type": "object",
                "description": "A hotel, parking tip or transport option.",
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 120,
                    "description": "Name."
                  },
                  "detail": {
                    "type": "string",
                    "maxLength": 1200,
                    "description": "A line or two of detail."
                  },
                  "url": {
                    "type": "string",
                    "maxLength": 2000,
                    "description": "Link (https).",
                    "format": "uri"
                  }
                },
                "additionalProperties": true
              }
            }
          },
          "additionalProperties": true
        },
        "party": {
          "type": "object",
          "description": "The wedding party.",
          "properties": {
            "on": {
              "type": "boolean",
              "description": "Show this page. Defaults to true when the page has content."
            },
            "intro": {
              "type": "string",
              "maxLength": 1000,
              "description": "Intro text."
            },
            "people": {
              "type": "array",
              "maxItems": 40,
              "description": "The people in the wedding party.",
              "items": {
                "type": "object",
                "description": "One person.",
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 80,
                    "description": "Name."
                  },
                  "role": {
                    "type": "string",
                    "maxLength": 60,
                    "description": "Role, e.g. \"Best man\"."
                  },
                  "note": {
                    "type": "string",
                    "maxLength": 400,
                    "description": "A line about them."
                  }
                },
                "additionalProperties": true
              }
            }
          },
          "additionalProperties": true
        },
        "todo": {
          "type": "object",
          "description": "Things to do nearby.",
          "properties": {
            "on": {
              "type": "boolean",
              "description": "Show this page. Defaults to true when the page has content."
            },
            "intro": {
              "type": "string",
              "maxLength": 2000,
              "description": "Intro text."
            },
            "items": {
              "type": "array",
              "maxItems": 30,
              "description": "Things to see and do.",
              "items": {
                "type": "object",
                "description": "A place or activity.",
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 120,
                    "description": "Name."
                  },
                  "detail": {
                    "type": "string",
                    "maxLength": 1200,
                    "description": "A line or two of detail."
                  },
                  "url": {
                    "type": "string",
                    "maxLength": 2000,
                    "description": "Link (https).",
                    "format": "uri"
                  }
                },
                "additionalProperties": true
              }
            }
          },
          "additionalProperties": true
        },
        "gifts": {
          "type": "object",
          "description": "A note about gifts.",
          "properties": {
            "on": {
              "type": "boolean",
              "description": "Show this page. Defaults to true when the page has content."
            },
            "intro": {
              "type": "string",
              "maxLength": 2000,
              "description": "What the couple would like to say about gifts."
            },
            "items": {
              "type": "array",
              "maxItems": 12,
              "description": "Registry or gift links.",
              "items": {
                "type": "object",
                "description": "A registry or gift link.",
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 120,
                    "description": "Name."
                  },
                  "detail": {
                    "type": "string",
                    "maxLength": 1200,
                    "description": "A line or two of detail."
                  },
                  "url": {
                    "type": "string",
                    "maxLength": 2000,
                    "description": "Link (https).",
                    "format": "uri"
                  }
                },
                "additionalProperties": true
              }
            }
          },
          "additionalProperties": true
        },
        "faq": {
          "type": "object",
          "description": "Questions and answers.",
          "properties": {
            "on": {
              "type": "boolean",
              "description": "Show this page. Defaults to true when the page has content."
            },
            "items": {
              "type": "array",
              "maxItems": 40,
              "description": "Questions guests ask.",
              "items": {
                "type": "object",
                "description": "One question.",
                "properties": {
                  "q": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "Question."
                  },
                  "a": {
                    "type": "string",
                    "maxLength": 2000,
                    "description": "Answer."
                  }
                },
                "additionalProperties": true
              }
            }
          },
          "additionalProperties": true
        }
      },
      "additionalProperties": true
    },
    "rsvp": {
      "type": "object",
      "description": "What the RSVP form asks.",
      "properties": {
        "enabled": {
          "type": "boolean",
          "description": "Turn online RSVP on. Defaults to true."
        },
        "deadline": {
          "type": "string",
          "maxLength": 10,
          "description": "Reply-by date, YYYY-MM-DD.",
          "format": "date",
          "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
        },
        "meals": {
          "type": "array",
          "maxItems": 8,
          "description": "Meal choices, if guests pick one.",
          "items": {
            "type": "string",
            "maxLength": 80,
            "description": "A meal choice, e.g. \"Beef\"."
          }
        },
        "dietary": {
          "type": "boolean",
          "description": "Ask about dietary needs. Defaults to true."
        },
        "song": {
          "type": "boolean",
          "description": "Ask for a song request. Defaults to false."
        },
        "questions": {
          "type": "array",
          "maxItems": 10,
          "description": "Your own extra questions.",
          "items": {
            "type": "object",
            "description": "A custom question asked once per reply.",
            "properties": {
              "question": {
                "type": "string",
                "maxLength": 200,
                "description": "The question text."
              },
              "kind": {
                "type": "string",
                "enum": [
                  "text",
                  "choice"
                ],
                "description": "text for a free answer, choice for a list of options."
              },
              "options": {
                "type": "array",
                "maxItems": 8,
                "description": "Options. Needed (2 or more) when kind is choice.",
                "items": {
                  "type": "string",
                  "maxLength": 80,
                  "description": "One option."
                }
              },
              "required": {
                "type": "boolean",
                "description": "Guests must answer."
              }
            },
            "additionalProperties": true
          }
        }
      },
      "additionalProperties": true
    },
    "seating": {
      "type": "object",
      "description": "Find-your-seat. Guests search their name and see their table. Table numbers come from the guest list.",
      "properties": {
        "enabled": {
          "type": "boolean",
          "description": "Turn find-your-seat on."
        },
        "note": {
          "type": "string",
          "maxLength": 300,
          "description": "A note shown above the seating search."
        }
      },
      "additionalProperties": true
    },
    "guests": {
      "type": "array",
      "maxItems": 1000,
      "description": "Optional. Guests contain personal details: they are only saved after the couple signs in, through the guest list importer.",
      "items": {
        "type": "object",
        "description": "One invited guest. Same fields as the guest CSV template.",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 120,
            "description": "Full name."
          },
          "side": {
            "type": "string",
            "enum": [
              "bride",
              "groom",
              "both",
              "neither"
            ],
            "description": "Whose side. Leave out if unsure."
          },
          "group": {
            "type": "string",
            "maxLength": 80,
            "description": "Group, e.g. \"College friends\"."
          },
          "table": {
            "type": "string",
            "maxLength": 60,
            "description": "Table name or number."
          },
          "seat": {
            "type": "string",
            "maxLength": 30,
            "description": "Seat."
          },
          "email": {
            "type": "string",
            "maxLength": 200,
            "description": "Email.",
            "format": "email"
          },
          "phone": {
            "type": "string",
            "maxLength": 40,
            "description": "Phone."
          }
        },
        "additionalProperties": true
      }
    }
  },
  "required": [
    "couple"
  ],
  "additionalProperties": true
}