<?xml version="1.0" encoding="UTF-8"?>
<!--
  brotxml 1.0 – Austauschformat für Brotrezepte, Zutaten, Sauerteige, Backprotokolle,
  Backpläne und Vorräte.

  Namensraum:  https://laibhaftig.familie-steinberg.org/ns/brotxml/1
  Versionierung:
    * Die HAUPTversion steckt im Namensraum (…/1). Eine neue Hauptversion (…/2) darf
      Inkompatibles ändern und bekommt einen neuen Namensraum.
    * Die NEBENversion steht im Attribut brot/@version ("1.0", "1.1", …). Neue Nebenversionen
      fügen nur OPTIONALE Elemente, Attribute und Aufzählungswerte hinzu. Ein Dokument der
      Version 1.0 ist damit immer auch ein gültiges 1.1-Dokument.
    * Leser validieren gegen das Schema ihrer Nebenversion. Ist ein Dokument neuer als der
      Leser, liest er es tolerant: Unbekannte Elemente und Attribute werden ignoriert,
      unbekannte Aufzählungswerte als "other" behandelt.
  Erweiterungen:
    * Elemente und Attribute aus FREMDEN Namensräumen sind an den mit "ext" markierten Stellen
      erlaubt (xs:any / xs:anyAttribute, processContents="lax"). So können Programme eigene
      Daten mitschicken, ohne das Format zu brechen.
    * Eigene Aufzählungswerte beginnen mit "x-" (z. B. category="x-stollen").
  Einheiten:  Massen in Gramm, Temperaturen in °C, Dauern als xs:duration (PT12H, PT45M),
              Zeitpunkte als xs:dateTime mit Zeitzone, Datumsangaben als xs:date.
  Identität:  Jede eigenständige Einheit (Rezept, Zutat, Sauerteig, Backprotokoll, Backplan,
              Vorratsposten) trägt eine dauerhafte uid. Dieselbe uid in zwei Dateien bedeutet
              "dasselbe Objekt" – Grundlage der Duplikaterkennung beim Import.
-->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns:b="https://laibhaftig.familie-steinberg.org/ns/brotxml/1"
           targetNamespace="https://laibhaftig.familie-steinberg.org/ns/brotxml/1"
           elementFormDefault="qualified"
           attributeFormDefault="unqualified"
           version="1.0">

  <!-- =====================================================================================
       Wurzel
       ===================================================================================== -->

  <xs:element name="brot" type="b:Document">
    <xs:annotation><xs:documentation>
      Wurzelelement. Enthält beliebig viele Abschnitte in beliebiger Reihenfolge; jeder
      Abschnitt ist optional. Eine Datei kann also ein einzelnes Rezept, eine ganze Sammlung
      oder den kompletten Datenbestand eines Kontos enthalten.
    </xs:documentation></xs:annotation>
    <xs:unique name="uniqueRecipeUid"><xs:selector xpath="b:recipes/b:recipe"/><xs:field xpath="@uid"/></xs:unique>
    <xs:unique name="uniqueIngredientUid"><xs:selector xpath="b:ingredients/b:ingredient"/><xs:field xpath="@uid"/></xs:unique>
    <xs:unique name="uniqueStarterUid"><xs:selector xpath="b:starters/b:starter"/><xs:field xpath="@uid"/></xs:unique>
    <xs:unique name="uniqueBakeUid"><xs:selector xpath="b:bakes/b:bake"/><xs:field xpath="@uid"/></xs:unique>
    <xs:unique name="uniquePlanUid"><xs:selector xpath="b:plans/b:plan"/><xs:field xpath="@uid"/></xs:unique>
  </xs:element>

  <xs:complexType name="Document">
    <xs:sequence>
      <xs:element name="meta" type="b:Meta" minOccurs="0"/>
      <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:element name="ingredients" type="b:IngredientList"/>
        <xs:element name="recipes" type="b:RecipeList"/>
        <xs:element name="starters" type="b:StarterList"/>
        <xs:element name="bakes" type="b:BakeList"/>
        <xs:element name="plans" type="b:PlanList"/>
        <xs:element name="pantry" type="b:Pantry"/>
        <xs:any namespace="##other" processContents="lax"/>
      </xs:choice>
    </xs:sequence>
    <xs:attribute name="version" type="b:FormatVersion" use="required">
      <xs:annotation><xs:documentation>Formatversion HAUPT.NEBEN, hier immer "1.x".</xs:documentation></xs:annotation>
    </xs:attribute>
    <xs:attribute name="created" type="xs:dateTime">
      <xs:annotation><xs:documentation>Zeitpunkt, zu dem die Datei erzeugt wurde.</xs:documentation></xs:annotation>
    </xs:attribute>
    <xs:attribute name="generator" type="xs:string">
      <xs:annotation><xs:documentation>Programm und Version, z. B. "Laibhaftig 1.0.17".</xs:documentation></xs:annotation>
    </xs:attribute>
    <xs:attribute name="lang" type="xs:language">
      <xs:annotation><xs:documentation>Sprache der Texte, z. B. "de".</xs:documentation></xs:annotation>
    </xs:attribute>
    <xs:anyAttribute namespace="##other" processContents="lax"/>
  </xs:complexType>

  <xs:simpleType name="FormatVersion">
    <xs:restriction base="xs:token"><xs:pattern value="1\.[0-9]+"/></xs:restriction>
  </xs:simpleType>

  <xs:complexType name="Meta">
    <xs:annotation><xs:documentation>Angaben zur Datei als Ganzes (alle optional).</xs:documentation></xs:annotation>
    <xs:sequence>
      <xs:element name="title" type="xs:string" minOccurs="0"/>
      <xs:element name="description" type="b:Text" minOccurs="0"/>
      <xs:element name="author" type="b:Person" minOccurs="0"/>
      <xs:element name="license" type="xs:string" minOccurs="0">
        <xs:annotation><xs:documentation>Nutzungsbedingungen, z. B. "CC BY 4.0" oder "nur privat".</xs:documentation></xs:annotation>
      </xs:element>
      <xs:element name="source" type="b:Source" minOccurs="0"/>
      <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
  </xs:complexType>

  <!-- =====================================================================================
       Gemeinsame Bausteine
       ===================================================================================== -->

  <xs:simpleType name="Uid">
    <xs:annotation><xs:documentation>
      Dauerhafte Kennung. Empfohlen: UUID (z. B. "3f2a…"). Erlaubt sind auch sprechende,
      weltweit eindeutige Kennungen wie "seed:ploetzblog:61542da61b35936d60f8cb60".
    </xs:documentation></xs:annotation>
    <xs:restriction base="xs:token"><xs:pattern value="[A-Za-z0-9][A-Za-z0-9:._\-]{0,127}"/></xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="ExtensionToken">
    <xs:annotation><xs:documentation>Eigener Aufzählungswert eines Programms, beginnt mit "x-".</xs:documentation></xs:annotation>
    <xs:restriction base="xs:token"><xs:pattern value="x-[a-z0-9][a-z0-9\-]*"/></xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="Grams"><xs:restriction base="xs:decimal"><xs:minInclusive value="0"/></xs:restriction></xs:simpleType>
  <xs:simpleType name="Celsius">
    <xs:restriction base="xs:decimal"><xs:minInclusive value="-40"/><xs:maxInclusive value="400"/></xs:restriction>
  </xs:simpleType>
  <xs:simpleType name="Factor"><xs:restriction base="xs:decimal"><xs:minExclusive value="0"/></xs:restriction></xs:simpleType>
  <xs:simpleType name="Percent"><xs:restriction base="xs:decimal"><xs:minInclusive value="0"/></xs:restriction></xs:simpleType>
  <xs:simpleType name="Rating">
    <xs:restriction base="xs:integer"><xs:minInclusive value="1"/><xs:maxInclusive value="5"/></xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="Visibility">
    <xs:annotation><xs:documentation>
      private = nur Besitzer, internal = angemeldete Benutzer, public = alle. Beim Import
      entscheidet der Empfänger, ob er die Angabe übernimmt.
    </xs:documentation></xs:annotation>
    <xs:union memberTypes="b:ExtensionToken">
      <xs:simpleType><xs:restriction base="xs:token">
        <xs:enumeration value="private"/><xs:enumeration value="internal"/><xs:enumeration value="public"/>
      </xs:restriction></xs:simpleType>
    </xs:union>
  </xs:simpleType>

  <xs:attributeGroup name="EntityAttributes">
    <xs:attribute name="uid" type="b:Uid" use="required"/>
    <xs:attribute name="created" type="xs:dateTime">
      <xs:annotation><xs:documentation>Angelegt (beim Ersteller).</xs:documentation></xs:annotation>
    </xs:attribute>
    <xs:attribute name="modified" type="xs:dateTime">
      <xs:annotation><xs:documentation>Zuletzt geändert – entscheidet bei Duplikaten über „jüngere Version“.</xs:documentation></xs:annotation>
    </xs:attribute>
    <xs:attribute name="visibility" type="b:Visibility"/>
    <xs:anyAttribute namespace="##other" processContents="lax"/>
  </xs:attributeGroup>

  <xs:complexType name="Text">
    <xs:annotation><xs:documentation>Freitext. format="markdown" erlaubt einfache Auszeichnung.</xs:documentation></xs:annotation>
    <xs:simpleContent>
      <xs:extension base="xs:string">
        <xs:attribute name="format" default="plain">
          <xs:simpleType><xs:restriction base="xs:token">
            <xs:enumeration value="plain"/><xs:enumeration value="markdown"/>
          </xs:restriction></xs:simpleType>
        </xs:attribute>
      </xs:extension>
    </xs:simpleContent>
  </xs:complexType>

  <xs:complexType name="Person">
    <xs:simpleContent>
      <xs:extension base="xs:string">
        <xs:attribute name="url" type="xs:anyURI"/>
        <xs:attribute name="email" type="xs:string"/>
      </xs:extension>
    </xs:simpleContent>
  </xs:complexType>

  <xs:complexType name="Source">
    <xs:annotation><xs:documentation>Woher ein Inhalt stammt (Webseite, Buch, Person).</xs:documentation></xs:annotation>
    <xs:simpleContent>
      <xs:extension base="xs:string">
        <xs:attribute name="url" type="xs:anyURI"/>
        <xs:attribute name="retrieved" type="xs:dateTime"/>
      </xs:extension>
    </xs:simpleContent>
  </xs:complexType>

  <xs:complexType name="Provenance">
    <xs:annotation><xs:documentation>
      Herkunftskette: wann und wie ein Objekt in einen Bestand gelangt ist. Bei jeder
      Weitergabe kommt ein acquired-Eintrag hinzu; der erste beschreibt den Ursprung.
    </xs:documentation></xs:annotation>
    <xs:sequence>
      <xs:element name="acquired" minOccurs="0" maxOccurs="unbounded">
        <xs:complexType>
          <xs:simpleContent>
            <xs:extension base="xs:string">
              <xs:attribute name="via" type="b:AcquiredVia" use="required"/>
              <xs:attribute name="at" type="xs:dateTime"/>
              <xs:attribute name="from" type="xs:string">
                <xs:annotation><xs:documentation>URL, Dateiname oder Rezept, aus dem abgeleitet wurde.</xs:documentation></xs:annotation>
              </xs:attribute>
              <xs:attribute name="by" type="xs:string"/>
            </xs:extension>
          </xs:simpleContent>
        </xs:complexType>
      </xs:element>
      <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
  </xs:complexType>

  <xs:simpleType name="AcquiredVia">
    <xs:annotation><xs:documentation>
      manual = von Hand angelegt, seed = Startsammlung, url-import = von einer Webseite
      importiert, file-import = aus einer Datei (z. B. brotxml), fork = aus einem anderen
      Rezept abgeleitet, api = über die Programmierschnittstelle, copy = beim Löschen eines
      anderen Kontos übernommen.
    </xs:documentation></xs:annotation>
    <xs:union memberTypes="b:ExtensionToken">
      <xs:simpleType><xs:restriction base="xs:token">
        <xs:enumeration value="manual"/><xs:enumeration value="seed"/><xs:enumeration value="url-import"/>
        <xs:enumeration value="file-import"/><xs:enumeration value="fork"/><xs:enumeration value="api"/>
        <xs:enumeration value="copy"/>
      </xs:restriction></xs:simpleType>
    </xs:union>
  </xs:simpleType>

  <xs:complexType name="Tags">
    <xs:sequence><xs:element name="tag" type="xs:string" minOccurs="0" maxOccurs="unbounded"/></xs:sequence>
  </xs:complexType>

  <xs:complexType name="Photo">
    <xs:annotation><xs:documentation>
      Foto: entweder eingebettet (data, Base64) oder als Verweis (href). Eingebettete Fotos
      machen die Datei groß, sind aber vollständig übertragbar.
    </xs:documentation></xs:annotation>
    <xs:sequence>
      <xs:element name="caption" type="xs:string" minOccurs="0"/>
      <xs:element name="data" minOccurs="0">
        <xs:complexType>
          <xs:simpleContent>
            <xs:extension base="xs:base64Binary">
              <xs:attribute name="media-type" use="required">
                <xs:simpleType><xs:restriction base="xs:token">
                  <xs:enumeration value="image/jpeg"/><xs:enumeration value="image/png"/><xs:enumeration value="image/webp"/>
                </xs:restriction></xs:simpleType>
              </xs:attribute>
            </xs:extension>
          </xs:simpleContent>
        </xs:complexType>
      </xs:element>
    </xs:sequence>
    <xs:attribute name="href" type="xs:anyURI"/>
    <xs:attribute name="taken" type="xs:dateTime"/>
  </xs:complexType>

  <xs:complexType name="Photos">
    <xs:sequence><xs:element name="photo" type="b:Photo" minOccurs="0" maxOccurs="unbounded"/></xs:sequence>
  </xs:complexType>

  <xs:simpleType name="Gluten">
    <xs:annotation><xs:documentation>
      contains = enthält Gluten (Weizen, Dinkel, Roggen, Gerste, Urgetreide …),
      traces = von Natur aus glutenfrei, aber oft verunreinigt (z. B. Hafer ohne Zertifikat),
      free = glutenfrei, unknown = nicht bekannt. Keine medizinische Zusicherung.
    </xs:documentation></xs:annotation>
    <xs:union memberTypes="b:ExtensionToken">
      <xs:simpleType><xs:restriction base="xs:token">
        <xs:enumeration value="contains"/><xs:enumeration value="traces"/>
        <xs:enumeration value="free"/><xs:enumeration value="unknown"/>
      </xs:restriction></xs:simpleType>
    </xs:union>
  </xs:simpleType>

  <xs:complexType name="IngredientRef">
    <xs:annotation><xs:documentation>
      Verweis auf eine Zutat: ref = uid einer Zutat in dieser Datei (ingredients) oder eine
      bekannte Kennung; der Text ist der Name, wie er im Rezept steht. Fehlt ref, ordnet der
      Empfänger über den Namen zu.
    </xs:documentation></xs:annotation>
    <xs:simpleContent>
      <xs:extension base="xs:string">
        <xs:attribute name="ref" type="b:Uid"/>
      </xs:extension>
    </xs:simpleContent>
  </xs:complexType>

  <xs:complexType name="Extensions">
    <xs:annotation><xs:documentation>Container für Daten aus fremden Namensräumen.</xs:documentation></xs:annotation>
    <xs:sequence><xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/></xs:sequence>
  </xs:complexType>

  <!-- =====================================================================================
       Zutaten
       ===================================================================================== -->

  <xs:complexType name="IngredientList">
    <xs:sequence><xs:element name="ingredient" type="b:Ingredient" minOccurs="0" maxOccurs="unbounded"/></xs:sequence>
  </xs:complexType>

  <xs:complexType name="Ingredient">
    <xs:sequence>
      <xs:element name="name" type="xs:string"/>
      <xs:element name="alias" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
      <xs:element name="category" type="b:IngredientCategory"/>
      <xs:element name="grain" type="b:Grain" minOccurs="0"/>
      <xs:element name="type-number" type="xs:token" minOccurs="0">
        <xs:annotation><xs:documentation>Mehltype, z. B. 550, 1150, 997 (bei Vollkorn leer).</xs:documentation></xs:annotation>
      </xs:element>
      <xs:element name="whole-grain" type="xs:boolean" minOccurs="0"/>
      <xs:element name="composition" minOccurs="0">
        <xs:annotation><xs:documentation>Anteile in Prozent der Masse.</xs:documentation></xs:annotation>
        <xs:complexType>
          <xs:attribute name="water" type="b:Percent"/>
          <xs:attribute name="fat" type="b:Percent"/>
          <xs:attribute name="sugar" type="b:Percent"/>
          <xs:attribute name="protein" type="b:Percent"/>
          <xs:attribute name="flour" type="xs:boolean">
            <xs:annotation><xs:documentation>Zählt als Mehl für Bäckerprozente und TA.</xs:documentation></xs:annotation>
          </xs:attribute>
        </xs:complexType>
      </xs:element>
      <xs:element name="gluten" type="b:Gluten" minOccurs="0"/>
      <xs:element name="price" minOccurs="0">
        <xs:complexType>
          <xs:simpleContent>
            <xs:extension base="xs:decimal">
              <xs:attribute name="currency" type="xs:token" default="EUR"/>
              <xs:attribute name="per" type="xs:token" fixed="kg"/>
            </xs:extension>
          </xs:simpleContent>
        </xs:complexType>
      </xs:element>
      <xs:element name="notes" type="b:Text" minOccurs="0"/>
      <xs:element name="provenance" type="b:Provenance" minOccurs="0"/>
      <xs:element name="ext" type="b:Extensions" minOccurs="0"/>
    </xs:sequence>
    <xs:attributeGroup ref="b:EntityAttributes"/>
  </xs:complexType>

  <xs:simpleType name="IngredientCategory">
    <xs:union memberTypes="b:ExtensionToken">
      <xs:simpleType><xs:restriction base="xs:token">
        <xs:enumeration value="flour"/><xs:enumeration value="meal"/><xs:enumeration value="flakes"/>
        <xs:enumeration value="seeds"/><xs:enumeration value="liquid"/><xs:enumeration value="dairy"/>
        <xs:enumeration value="egg"/><xs:enumeration value="fat"/><xs:enumeration value="sweetener"/>
        <xs:enumeration value="salt"/><xs:enumeration value="yeast"/><xs:enumeration value="starter"/>
        <xs:enumeration value="malt"/><xs:enumeration value="spice"/><xs:enumeration value="vegetable"/>
        <xs:enumeration value="old_bread"/><xs:enumeration value="other"/>
      </xs:restriction></xs:simpleType>
    </xs:union>
  </xs:simpleType>

  <xs:simpleType name="Grain">
    <xs:union memberTypes="b:ExtensionToken">
      <xs:simpleType><xs:restriction base="xs:token">
        <xs:enumeration value="wheat"/><xs:enumeration value="spelt"/><xs:enumeration value="rye"/>
        <xs:enumeration value="emmer"/><xs:enumeration value="einkorn"/><xs:enumeration value="khorasan"/>
        <xs:enumeration value="durum"/><xs:enumeration value="oat"/><xs:enumeration value="barley"/>
        <xs:enumeration value="buckwheat"/><xs:enumeration value="millet"/><xs:enumeration value="corn"/>
        <xs:enumeration value="rice"/><xs:enumeration value="other"/>
      </xs:restriction></xs:simpleType>
    </xs:union>
  </xs:simpleType>

  <!-- =====================================================================================
       Rezepte
       ===================================================================================== -->

  <xs:complexType name="RecipeList">
    <xs:sequence><xs:element name="recipe" type="b:Recipe" minOccurs="0" maxOccurs="unbounded"/></xs:sequence>
  </xs:complexType>

  <xs:complexType name="Recipe">
    <xs:annotation><xs:documentation>
      Ein Rezept mit seiner vollständigen Versionsgeschichte. versions/@current nennt die
      gültige Version; ältere Versionen bleiben erhalten (z. B. für Backprotokolle).
    </xs:documentation></xs:annotation>
    <xs:sequence>
      <xs:element name="title" type="xs:string"/>
      <xs:element name="subtitle" type="xs:string" minOccurs="0"/>
      <xs:element name="classification" type="b:Classification" minOccurs="0"/>
      <xs:element name="author" type="b:Person" minOccurs="0">
        <xs:annotation><xs:documentation>Urheber des Rezepts (bei Fremdrezepten, z. B. "Lutz Geißler").</xs:documentation></xs:annotation>
      </xs:element>
      <xs:element name="source" type="b:Source" minOccurs="0"/>
      <xs:element name="tags" type="b:Tags" minOccurs="0"/>
      <xs:element name="provenance" type="b:Provenance" minOccurs="0"/>
      <xs:element name="versions">
        <xs:complexType>
          <xs:sequence><xs:element name="version" type="b:RecipeVersion" maxOccurs="unbounded"/></xs:sequence>
          <xs:attribute name="current" type="xs:positiveInteger"/>
        </xs:complexType>
        <xs:unique name="uniqueVersionNumber"><xs:selector xpath="b:version"/><xs:field xpath="@number"/></xs:unique>
      </xs:element>
      <xs:element name="ext" type="b:Extensions" minOccurs="0"/>
    </xs:sequence>
    <xs:attributeGroup ref="b:EntityAttributes"/>
  </xs:complexType>

  <xs:complexType name="Classification">
    <xs:attribute name="category" type="b:RecipeCategory"/>
    <xs:attribute name="leavening" type="b:Leavening"/>
    <xs:attribute name="origin">
      <xs:annotation><xs:documentation>own = eigenes Rezept, external = Rezept einer anderen Person.</xs:documentation></xs:annotation>
      <xs:simpleType><xs:union memberTypes="b:ExtensionToken"><xs:simpleType><xs:restriction base="xs:token">
        <xs:enumeration value="own"/><xs:enumeration value="external"/>
      </xs:restriction></xs:simpleType></xs:union></xs:simpleType>
    </xs:attribute>
    <xs:attribute name="gluten" type="b:Gluten">
      <xs:annotation><xs:documentation>Abgeleitet aus den Zutaten (informativ).</xs:documentation></xs:annotation>
    </xs:attribute>
  </xs:complexType>

  <xs:simpleType name="RecipeCategory">
    <xs:union memberTypes="b:ExtensionToken">
      <xs:simpleType><xs:restriction base="xs:token">
        <xs:enumeration value="bread"/><xs:enumeration value="mixed"/><xs:enumeration value="wholegrain"/>
        <xs:enumeration value="tin"/><xs:enumeration value="rolls"/><xs:enumeration value="baguette"/>
        <xs:enumeration value="ciabatta"/><xs:enumeration value="flatbread"/><xs:enumeration value="lye"/>
        <xs:enumeration value="sweet"/><xs:enumeration value="crispbread"/><xs:enumeration value="glutenfree"/>
        <xs:enumeration value="other"/>
      </xs:restriction></xs:simpleType>
    </xs:union>
  </xs:simpleType>

  <xs:simpleType name="Leavening">
    <xs:union memberTypes="b:ExtensionToken">
      <xs:simpleType><xs:restriction base="xs:token">
        <xs:enumeration value="sourdough"/><xs:enumeration value="yeast"/><xs:enumeration value="hybrid"/>
        <xs:enumeration value="lievito"/><xs:enumeration value="yeast_water"/><xs:enumeration value="backferment"/>
        <xs:enumeration value="chemical"/><xs:enumeration value="none"/>
      </xs:restriction></xs:simpleType>
    </xs:union>
  </xs:simpleType>

  <xs:complexType name="RecipeVersion">
    <xs:sequence>
      <xs:element name="change-note" type="xs:string" minOccurs="0"/>
      <xs:element name="yield" minOccurs="0">
        <xs:complexType>
          <xs:attribute name="pieces" type="xs:positiveInteger"/>
          <xs:attribute name="piece-weight" type="b:Grams"/>
          <xs:attribute name="mold" type="xs:string"/>
        </xs:complexType>
      </xs:element>
      <xs:element name="properties" minOccurs="0">
        <xs:complexType>
          <xs:attribute name="difficulty" type="b:Rating"/>
          <xs:attribute name="target-dough-temp" type="b:Celsius"/>
          <xs:attribute name="knead-method" type="b:KneadMethod"/>
          <xs:attribute name="knead-slow" type="xs:duration"/>
          <xs:attribute name="knead-fast" type="xs:duration"/>
          <xs:attribute name="bake-method" type="b:BakeMethod"/>
          <xs:attribute name="preheat-temp" type="b:Celsius"/>
          <xs:attribute name="core-temp" type="b:Celsius"/>
          <xs:anyAttribute namespace="##other" processContents="lax"/>
        </xs:complexType>
      </xs:element>
      <xs:element name="scoring" type="xs:string" minOccurs="0"/>
      <xs:element name="finish" type="xs:string" minOccurs="0"/>
      <xs:element name="description" type="b:Text" minOccurs="0"/>
      <xs:element name="method" type="b:Text" minOccurs="0"/>
      <xs:element name="tips" type="b:Text" minOccurs="0"/>
      <xs:element name="notes" type="b:Text" minOccurs="0"/>
      <xs:element name="storage" type="b:Text" minOccurs="0"/>
      <xs:element name="stages">
        <xs:complexType>
          <xs:sequence><xs:element name="stage" type="b:Stage" minOccurs="0" maxOccurs="unbounded"/></xs:sequence>
        </xs:complexType>
        <xs:key name="stageKey"><xs:selector xpath="b:stage"/><xs:field xpath="@key"/></xs:key>
        <xs:keyref name="stageFeeds" refer="b:stageKey"><xs:selector xpath="b:stage"/><xs:field xpath="@feeds"/></xs:keyref>
        <xs:keyref name="lineFromStage" refer="b:stageKey"><xs:selector xpath="b:stage/b:line"/><xs:field xpath="@from-stage"/></xs:keyref>
      </xs:element>
      <xs:element name="oven" minOccurs="0">
        <xs:annotation><xs:documentation>Backprofil: Phasen nacheinander (z. B. 10 min 250 °C mit Schwaden, 45 min 210 °C).</xs:documentation></xs:annotation>
        <xs:complexType>
          <xs:sequence>
            <xs:element name="phase" maxOccurs="unbounded">
              <xs:complexType>
                <xs:simpleContent>
                  <xs:extension base="xs:string">
                    <xs:attribute name="temp" type="b:Celsius" use="required"/>
                    <xs:attribute name="duration" type="xs:duration" use="required"/>
                    <xs:attribute name="steam" type="xs:boolean" default="false"/>
                    <xs:attribute name="vent" type="xs:boolean" default="false">
                      <xs:annotation><xs:documentation>Ofentür/Zug öffnen, Dampf ablassen.</xs:documentation></xs:annotation>
                    </xs:attribute>
                    <xs:attribute name="lid" type="xs:boolean" default="false">
                      <xs:annotation><xs:documentation>Mit Deckel (Topf/Bräter geschlossen).</xs:documentation></xs:annotation>
                    </xs:attribute>
                  </xs:extension>
                </xs:simpleContent>
              </xs:complexType>
            </xs:element>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
      <xs:element name="metrics" minOccurs="0">
        <xs:annotation><xs:documentation>Berechnete Kennzahlen (informativ, werden beim Import neu berechnet).</xs:documentation></xs:annotation>
        <xs:complexType>
          <xs:attribute name="total-flour" type="b:Grams"/>
          <xs:attribute name="total-water" type="b:Grams"/>
          <xs:attribute name="total-dough" type="b:Grams"/>
          <xs:attribute name="hydration" type="b:Percent"/>
          <xs:attribute name="salt" type="b:Percent"/>
          <xs:attribute name="prefermented-flour" type="b:Percent"/>
          <xs:attribute name="total-time" type="xs:duration"/>
        </xs:complexType>
      </xs:element>
      <xs:element name="photos" type="b:Photos" minOccurs="0"/>
      <xs:element name="ext" type="b:Extensions" minOccurs="0"/>
    </xs:sequence>
    <xs:attribute name="number" type="xs:positiveInteger" use="required"/>
    <xs:attribute name="created" type="xs:dateTime"/>
    <xs:attribute name="by" type="xs:string"/>
    <xs:anyAttribute namespace="##other" processContents="lax"/>
  </xs:complexType>

  <xs:simpleType name="KneadMethod">
    <xs:union memberTypes="b:ExtensionToken">
      <xs:simpleType><xs:restriction base="xs:token">
        <xs:enumeration value="hand"/><xs:enumeration value="machine"/><xs:enumeration value="stretch_fold"/>
        <xs:enumeration value="no_knead"/><xs:enumeration value="mix_only"/>
      </xs:restriction></xs:simpleType>
    </xs:union>
  </xs:simpleType>

  <xs:simpleType name="BakeMethod">
    <xs:union memberTypes="b:ExtensionToken">
      <xs:simpleType><xs:restriction base="xs:token">
        <xs:enumeration value="stone"/><xs:enumeration value="pot"/><xs:enumeration value="tray"/>
        <xs:enumeration value="tin"/><xs:enumeration value="frame"/><xs:enumeration value="woodfire"/>
        <xs:enumeration value="pan"/><xs:enumeration value="other"/>
      </xs:restriction></xs:simpleType>
    </xs:union>
  </xs:simpleType>

  <xs:complexType name="Stage">
    <xs:annotation><xs:documentation>
      Eine Stufe: Vorstufe (Sauerteig, Poolish, Brühstück …) oder Hauptteig. Stufen münden
      über feeds in andere Stufen; eine Zeile mit from-stage verwendet eine ganze Stufe als Zutat.
    </xs:documentation></xs:annotation>
    <xs:sequence>
      <xs:element name="name" type="xs:string"/>
      <xs:element name="ripening" minOccurs="0">
        <xs:annotation><xs:documentation>Reife der ganzen Stufe (wenn keine einzelnen Ruhe-Schritte angegeben sind).</xs:documentation></xs:annotation>
        <xs:complexType>
          <xs:attribute name="duration" type="xs:duration"/>
          <xs:attribute name="temp" type="b:Celsius"/>
          <xs:attribute name="min-factor" type="b:Factor"/>
          <xs:attribute name="max-factor" type="b:Factor"/>
          <xs:attribute name="ta" type="b:Factor"/>
        </xs:complexType>
      </xs:element>
      <xs:element name="ripeness-hint" type="xs:string" minOccurs="0"/>
      <xs:element name="notes" type="b:Text" minOccurs="0"/>
      <xs:element name="line" type="b:Line" minOccurs="0" maxOccurs="unbounded"/>
      <xs:element name="step" type="b:Step" minOccurs="0" maxOccurs="unbounded"/>
      <xs:element name="ext" type="b:Extensions" minOccurs="0"/>
    </xs:sequence>
    <xs:attribute name="key" type="xs:NCName" use="required"/>
    <xs:attribute name="type" type="b:StageType" default="other"/>
    <xs:attribute name="main" type="xs:boolean" default="false"/>
    <xs:attribute name="feeds" type="xs:NCName"/>
    <xs:anyAttribute namespace="##other" processContents="lax"/>
  </xs:complexType>

  <xs:simpleType name="StageType">
    <xs:union memberTypes="b:ExtensionToken">
      <xs:simpleType><xs:restriction base="xs:token">
        <xs:enumeration value="starter_refresh"/><xs:enumeration value="sourdough"/><xs:enumeration value="levain"/>
        <xs:enumeration value="lievito"/><xs:enumeration value="poolish"/><xs:enumeration value="biga"/>
        <xs:enumeration value="predough"/><xs:enumeration value="scald"/><xs:enumeration value="cooked"/>
        <xs:enumeration value="soaker"/><xs:enumeration value="autolyse"/><xs:enumeration value="old_bread"/>
        <xs:enumeration value="main"/><xs:enumeration value="topping"/><xs:enumeration value="other"/>
      </xs:restriction></xs:simpleType>
    </xs:union>
  </xs:simpleType>

  <xs:complexType name="Line">
    <xs:annotation><xs:documentation>
      Eine Zutatenzeile. Menge in Gramm (amount) oder als Text (amount-text, z. B. "1 Prise").
      from-stage verweist auf eine Stufe derselben Version, die vollständig hineinkommt.
    </xs:documentation></xs:annotation>
    <xs:sequence>
      <xs:element name="ingredient" type="b:IngredientRef" minOccurs="0"/>
      <xs:element name="amount-text" type="xs:string" minOccurs="0"/>
      <xs:element name="note" type="xs:string" minOccurs="0"/>
      <xs:element name="ext" type="b:Extensions" minOccurs="0"/>
    </xs:sequence>
    <xs:attribute name="amount" type="b:Grams"/>
    <xs:attribute name="temp" type="b:Celsius"/>
    <xs:attribute name="bakers-percent" type="b:Percent">
      <xs:annotation><xs:documentation>Informativ; maßgeblich ist amount.</xs:documentation></xs:annotation>
    </xs:attribute>
    <xs:attribute name="from-stage" type="xs:NCName"/>
    <xs:anyAttribute namespace="##other" processContents="lax"/>
  </xs:complexType>

  <xs:complexType name="Step">
    <xs:annotation><xs:documentation>
      Ein Arbeits- oder Ruheschritt. min-factor/max-factor geben an, wie stark der Planer eine
      Ruhe verkürzen bzw. verlängern darf (z. B. 0,75 und 1,5); scalable = Dauer darf mit der
      Temperatur umgerechnet werden.
    </xs:documentation></xs:annotation>
    <xs:simpleContent>
      <xs:extension base="xs:string">
        <xs:attribute name="kind" type="b:StepKind" default="action"/>
        <xs:attribute name="duration" type="xs:duration"/>
        <xs:attribute name="temp" type="b:Celsius"/>
        <xs:attribute name="scalable" type="xs:boolean"/>
        <xs:attribute name="min-factor" type="b:Factor"/>
        <xs:attribute name="max-factor" type="b:Factor"/>
        <xs:anyAttribute namespace="##other" processContents="lax"/>
      </xs:extension>
    </xs:simpleContent>
  </xs:complexType>

  <xs:simpleType name="StepKind">
    <xs:union memberTypes="b:ExtensionToken">
      <xs:simpleType><xs:restriction base="xs:token">
        <xs:enumeration value="action"/><xs:enumeration value="rest"/><xs:enumeration value="preheat"/>
        <xs:enumeration value="bake"/><xs:enumeration value="cool"/>
      </xs:restriction></xs:simpleType>
    </xs:union>
  </xs:simpleType>

  <!-- =====================================================================================
       Sauerteige
       ===================================================================================== -->

  <xs:complexType name="StarterList">
    <xs:sequence><xs:element name="starter" type="b:Starter" minOccurs="0" maxOccurs="unbounded"/></xs:sequence>
  </xs:complexType>

  <xs:complexType name="Starter">
    <xs:sequence>
      <xs:element name="name" type="xs:string"/>
      <xs:element name="kind" type="b:StarterKind" minOccurs="0"/>
      <xs:element name="flour" type="b:IngredientRef" minOccurs="0"/>
      <xs:element name="ta" type="b:Factor" minOccurs="0"/>
      <xs:element name="origin" type="xs:string" minOccurs="0"/>
      <xs:element name="started-on" type="xs:date" minOccurs="0"/>
      <xs:element name="storage" minOccurs="0">
        <xs:simpleType><xs:union memberTypes="b:ExtensionToken"><xs:simpleType><xs:restriction base="xs:token">
          <xs:enumeration value="fridge"/><xs:enumeration value="room"/><xs:enumeration value="dried"/><xs:enumeration value="frozen"/>
        </xs:restriction></xs:simpleType></xs:union></xs:simpleType>
      </xs:element>
      <xs:element name="feeding-scheme" minOccurs="0">
        <xs:annotation><xs:documentation>Übliche Fütterung als Verhältnis Anstellgut : Mehl : Wasser und Intervall.</xs:documentation></xs:annotation>
        <xs:complexType>
          <xs:attribute name="seed" type="b:Factor"/>
          <xs:attribute name="flour" type="b:Factor"/>
          <xs:attribute name="water" type="b:Factor"/>
          <xs:attribute name="interval" type="xs:duration"/>
        </xs:complexType>
      </xs:element>
      <xs:element name="calibration" minOccurs="0">
        <xs:annotation><xs:documentation>Reifezeit bei 1:1:1 und 26 °C (tref) – Kalibrierwert des Gärmodells.</xs:documentation></xs:annotation>
        <xs:complexType>
          <xs:attribute name="tref" type="xs:duration"/>
        </xs:complexType>
      </xs:element>
      <xs:element name="active" type="xs:boolean" minOccurs="0"/>
      <xs:element name="notes" type="b:Text" minOccurs="0"/>
      <xs:element name="feedings" minOccurs="0">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="feeding" maxOccurs="unbounded">
              <xs:complexType>
                <xs:sequence>
                  <xs:element name="flour" type="b:IngredientRef" minOccurs="0"/>
                  <xs:element name="smell" type="xs:string" minOccurs="0"/>
                  <xs:element name="notes" type="b:Text" minOccurs="0"/>
                </xs:sequence>
                <xs:attribute name="at" type="xs:dateTime" use="required"/>
                <xs:attribute name="seed" type="b:Grams"/>
                <xs:attribute name="flour-amount" type="b:Grams"/>
                <xs:attribute name="water" type="b:Grams"/>
                <xs:attribute name="temp" type="b:Celsius"/>
                <xs:attribute name="peak-after" type="xs:duration"/>
                <xs:attribute name="rise" type="b:Factor"/>
              </xs:complexType>
            </xs:element>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
      <xs:element name="photos" type="b:Photos" minOccurs="0"/>
      <xs:element name="provenance" type="b:Provenance" minOccurs="0"/>
      <xs:element name="ext" type="b:Extensions" minOccurs="0"/>
    </xs:sequence>
    <xs:attributeGroup ref="b:EntityAttributes"/>
  </xs:complexType>

  <xs:simpleType name="StarterKind">
    <xs:union memberTypes="b:ExtensionToken">
      <xs:simpleType><xs:restriction base="xs:token">
        <xs:enumeration value="rye"/><xs:enumeration value="wheat"/><xs:enumeration value="spelt"/>
        <xs:enumeration value="lievito"/><xs:enumeration value="levain"/><xs:enumeration value="wholegrain"/>
        <xs:enumeration value="glutenfree"/><xs:enumeration value="yeast_water"/>
      </xs:restriction></xs:simpleType>
    </xs:union>
  </xs:simpleType>

  <!-- =====================================================================================
       Backprotokolle
       ===================================================================================== -->

  <xs:complexType name="BakeList">
    <xs:sequence><xs:element name="bake" type="b:Bake" minOccurs="0" maxOccurs="unbounded"/></xs:sequence>
  </xs:complexType>

  <xs:complexType name="RecipeRef">
    <xs:annotation><xs:documentation>Verweis auf ein Rezept (uid) und optional eine Version; der Text ist der Titel.</xs:documentation></xs:annotation>
    <xs:simpleContent>
      <xs:extension base="xs:string">
        <xs:attribute name="ref" type="b:Uid"/>
        <xs:attribute name="version" type="xs:positiveInteger"/>
        <xs:attribute name="source-url" type="xs:anyURI"/>
      </xs:extension>
    </xs:simpleContent>
  </xs:complexType>

  <xs:complexType name="Bake">
    <xs:sequence>
      <xs:element name="recipe" type="b:RecipeRef" minOccurs="0"/>
      <xs:element name="title" type="xs:string" minOccurs="0"/>
      <xs:element name="baked-on" type="xs:date"/>
      <xs:element name="scale" type="b:Factor" minOccurs="0"/>
      <xs:element name="conditions" minOccurs="0">
        <xs:complexType>
          <xs:attribute name="room-temp" type="b:Celsius"/>
          <xs:attribute name="dough-temp" type="b:Celsius"/>
        </xs:complexType>
      </xs:element>
      <xs:element name="flour-batch" type="xs:string" minOccurs="0"/>
      <xs:element name="ratings" minOccurs="0">
        <xs:complexType>
          <xs:attribute name="overall" type="b:Rating"/>
          <xs:attribute name="taste" type="b:Rating"/>
          <xs:attribute name="crumb" type="b:Rating"/>
          <xs:attribute name="crust" type="b:Rating"/>
          <xs:attribute name="oven-spring" type="b:Rating"/>
          <xs:attribute name="look" type="b:Rating"/>
        </xs:complexType>
      </xs:element>
      <xs:element name="deviations" type="b:Text" minOccurs="0"/>
      <xs:element name="notes" type="b:Text" minOccurs="0"/>
      <xs:element name="photos" type="b:Photos" minOccurs="0"/>
      <xs:element name="provenance" type="b:Provenance" minOccurs="0"/>
      <xs:element name="ext" type="b:Extensions" minOccurs="0"/>
    </xs:sequence>
    <xs:attributeGroup ref="b:EntityAttributes"/>
  </xs:complexType>

  <!-- =====================================================================================
       Backpläne
       ===================================================================================== -->

  <xs:complexType name="PlanList">
    <xs:sequence><xs:element name="plan" type="b:Plan" minOccurs="0" maxOccurs="unbounded"/></xs:sequence>
  </xs:complexType>

  <xs:complexType name="Plan">
    <xs:annotation><xs:documentation>
      Ein Backplan. anchor ist das Ende des Backens. Der Zeitplan (schedule) ist informativ –
      der Empfänger rechnet ihn mit seinen Räumen und Arbeitszeiten neu.
    </xs:documentation></xs:annotation>
    <xs:sequence>
      <xs:element name="recipe" type="b:RecipeRef"/>
      <xs:element name="title" type="xs:string" minOccurs="0"/>
      <xs:element name="anchor" type="xs:dateTime"/>
      <xs:element name="scale" type="b:Factor" minOccurs="0"/>
      <xs:element name="status" minOccurs="0">
        <xs:simpleType><xs:union memberTypes="b:ExtensionToken"><xs:simpleType><xs:restriction base="xs:token">
          <xs:enumeration value="planned"/><xs:enumeration value="running"/><xs:enumeration value="done"/><xs:enumeration value="cancelled"/>
        </xs:restriction></xs:simpleType></xs:union></xs:simpleType>
      </xs:element>
      <xs:element name="schedule" minOccurs="0">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="event" minOccurs="0" maxOccurs="unbounded">
              <xs:complexType>
                <xs:simpleContent>
                  <xs:extension base="xs:string">
                    <xs:attribute name="start" type="xs:dateTime" use="required"/>
                    <xs:attribute name="end" type="xs:dateTime" use="required"/>
                    <xs:attribute name="kind" type="b:StepKind"/>
                    <xs:attribute name="stage" type="xs:string"/>
                    <xs:attribute name="room" type="xs:string"/>
                    <xs:attribute name="temp" type="b:Celsius"/>
                  </xs:extension>
                </xs:simpleContent>
              </xs:complexType>
            </xs:element>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
      <xs:element name="ext" type="b:Extensions" minOccurs="0"/>
    </xs:sequence>
    <xs:attributeGroup ref="b:EntityAttributes"/>
  </xs:complexType>

  <!-- =====================================================================================
       Vorrat
       ===================================================================================== -->

  <xs:complexType name="Pantry">
    <xs:sequence>
      <xs:element name="item" minOccurs="0" maxOccurs="unbounded">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="ingredient" type="b:IngredientRef"/>
            <xs:element name="note" type="xs:string" minOccurs="0"/>
          </xs:sequence>
          <xs:attribute name="amount" type="b:Grams" use="required"/>
          <xs:attribute name="minimum" type="b:Grams"/>
          <xs:attribute name="best-before" type="xs:date"/>
          <xs:attribute name="best-before-estimated" type="xs:boolean" default="false"/>
          <xs:attribute name="modified" type="xs:dateTime"/>
        </xs:complexType>
      </xs:element>
    </xs:sequence>
  </xs:complexType>

</xs:schema>
