<?xml version="1.0" encoding="UTF-8"?>
<!--
  Housebook developer and partner feed, version 1 - XML form.

  XML and JSON are equal: same fields, same rules, same validator on our side
  (owner decision 189, 14 September 2026). Pick whichever your system already
  produces. The JSON form is described by housebook-feed-v1.schema.json and is
  generated from the same source of truth as the enumerations below; a test in
  our repository fails if the two forms drift apart.

  Rules that apply to both forms:
    * Ids are stable. The same building or unit keeps the same id across
      exports, forever. A changed id means a new object to us and the loss of
      its whole price history.
    * updated_at is ISO 8601 on every record. If it carries a time, it carries
      a time zone: "2026-09-14 10:00" without an offset is a different moment
      in Panama and in Bangkok.
    * Prices are numbers. Not "1 200 000 THB", not "from 1.2M".
    * Photos are direct links over http or https. A permanent URL per image:
      when the picture changes, the URL changes. We copy every file to our own
      storage and never hotlink.
    * The file is UTF-8, and the XML declaration must not claim anything else.
    * DOCTYPE is rejected. We do not resolve external entities, and a document
      that relies on them will not be read.
    * One file per URL. next_url exists only for exports that do not fit into a
      single response.
    * A field you do not have is better left out than filled in approximately.
-->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">

  <!-- ── Primitive types ──────────────────────────────────────────── -->

  <xs:simpleType name="NonEmptyString">
    <xs:restriction base="xs:string">
      <xs:minLength value="1"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="Iso8601">
    <xs:annotation>
      <xs:documentation>Date, or date and time with a time zone offset.</xs:documentation>
    </xs:annotation>
    <xs:restriction base="xs:string">
      <xs:pattern value="\d{4}-\d{2}-\d{2}([Tt ]\d{2}:\d{2}(:\d{2}(\.\d+)?)?([Zz]|[+\-]\d{2}:?\d{2}))?"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="CalendarDate">
    <xs:annotation>
      <xs:documentation>YYYY-MM-DD, or YYYY-MM when the day is not known.</xs:documentation>
    </xs:annotation>
    <xs:restriction base="xs:string">
      <xs:pattern value="\d{4}-\d{2}(-\d{2})?"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="CurrencyCode">
    <xs:annotation>
      <xs:documentation>ISO 4217, three capital letters. Currency symbols are not accepted.</xs:documentation>
    </xs:annotation>
    <xs:restriction base="xs:string">
      <xs:pattern value="[A-Z]{3}"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="DirectUrl">
    <xs:restriction base="xs:string">
      <xs:pattern value="https?://.+"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="PositiveNumber">
    <xs:restriction base="xs:decimal">
      <xs:minExclusive value="0"/>
    </xs:restriction>
  </xs:simpleType>

  <!-- ── Enumerations. Kept in step with src/lib/feed-intake/schema.ts ── -->

  <xs:simpleType name="CountryCode">
    <xs:annotation>
      <xs:documentation>ISO 3166-1 alpha-2 of a Housebook market.</xs:documentation>
    </xs:annotation>
    <xs:restriction base="xs:string">
      <xs:enumeration value="AE"/>
      <xs:enumeration value="AZ"/>
      <xs:enumeration value="CL"/>
      <xs:enumeration value="CY"/>
      <xs:enumeration value="GE"/>
      <xs:enumeration value="ID"/>
      <xs:enumeration value="OM"/>
      <xs:enumeration value="PA"/>
      <xs:enumeration value="SA"/>
      <xs:enumeration value="TH"/>
      <xs:enumeration value="TR"/>
      <xs:enumeration value="US"/>
      <xs:enumeration value="UZ"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="CompletionStatus">
    <xs:restriction base="xs:string">
      <xs:enumeration value="planned"/>
      <xs:enumeration value="under_construction"/>
      <xs:enumeration value="completed"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="Ownership">
    <xs:restriction base="xs:string">
      <xs:enumeration value="freehold"/>
      <xs:enumeration value="leasehold"/>
      <xs:enumeration value="other"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="PhotoKind">
    <xs:restriction base="xs:string">
      <xs:enumeration value="photo"/>
      <xs:enumeration value="plan"/>
      <xs:enumeration value="masterplan"/>
      <xs:enumeration value="facility"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="UnitType">
    <xs:restriction base="xs:string">
      <xs:enumeration value="studio"/>
      <xs:enumeration value="1br"/>
      <xs:enumeration value="2br"/>
      <xs:enumeration value="3br"/>
      <xs:enumeration value="4br+"/>
      <xs:enumeration value="villa"/>
      <xs:enumeration value="townhouse"/>
      <xs:enumeration value="penthouse"/>
      <xs:enumeration value="land"/>
      <xs:enumeration value="commercial"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="AreaUnit">
    <xs:annotation>
      <xs:documentation>Always stated. We never infer the unit from the country.</xs:documentation>
    </xs:annotation>
    <xs:restriction base="xs:string">
      <xs:enumeration value="sqm"/>
      <xs:enumeration value="sqft"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="PriceBasis">
    <xs:annotation>
      <xs:documentation>What the amount is for: the whole unit, a square metre, or a square foot.</xs:documentation>
    </xs:annotation>
    <xs:restriction base="xs:string">
      <xs:enumeration value="total"/>
      <xs:enumeration value="sqm"/>
      <xs:enumeration value="sqft"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="UnitStatus">
    <xs:restriction base="xs:string">
      <xs:enumeration value="available"/>
      <xs:enumeration value="reserved"/>
      <xs:enumeration value="sold"/>
    </xs:restriction>
  </xs:simpleType>

  <!-- ── Complex types ────────────────────────────────────────────── -->

  <xs:complexType name="Provider">
    <xs:sequence>
      <xs:element name="name" type="NonEmptyString"/>
      <xs:element name="country" type="CountryCode"/>
      <xs:element name="contact" type="NonEmptyString">
        <xs:annotation>
          <xs:documentation>A live contact for questions about the data: email or phone.</xs:documentation>
        </xs:annotation>
      </xs:element>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="Developer">
    <xs:sequence>
      <xs:element name="name" type="NonEmptyString"/>
      <xs:element name="id" type="xs:string" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="Completion">
    <xs:sequence>
      <xs:element name="status" type="CompletionStatus"/>
      <xs:element name="date" type="CalendarDate" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="Photo">
    <xs:sequence>
      <xs:element name="url" type="DirectUrl"/>
      <xs:element name="kind" type="PhotoKind" minOccurs="0">
        <xs:annotation>
          <xs:documentation>Missing kind is read as photo.</xs:documentation>
        </xs:annotation>
      </xs:element>
    </xs:sequence>
  </xs:complexType>

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

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

  <xs:complexType name="Description">
    <xs:annotation>
      <xs:documentation>
        One child element per locale, named by its two-letter code: en, ru, de.
        No phone numbers, no messenger handles, no links to other sites: this
        text goes onto a public page of ours.
      </xs:documentation>
    </xs:annotation>
    <xs:sequence>
      <xs:any processContents="skip" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="Building">
    <xs:sequence>
      <xs:element name="id" type="NonEmptyString"/>
      <xs:element name="name" type="NonEmptyString"/>
      <xs:element name="country" type="CountryCode"/>
      <xs:element name="city" type="NonEmptyString"/>
      <xs:element name="district" type="xs:string" minOccurs="0"/>
      <xs:element name="address" type="xs:string" minOccurs="0"/>
      <xs:element name="lat" type="xs:decimal" minOccurs="0"/>
      <xs:element name="lng" type="xs:decimal" minOccurs="0"/>
      <xs:element name="developer" type="Developer"/>
      <xs:element name="completion" type="Completion" minOccurs="0"/>
      <xs:element name="ownership" type="Ownership" minOccurs="0"/>
      <xs:element name="description" type="Description" minOccurs="0"/>
      <xs:element name="photos" type="Photos" minOccurs="0"/>
      <xs:element name="amenities" type="Amenities" minOccurs="0"/>
      <xs:element name="updated_at" type="Iso8601"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="Area">
    <xs:sequence>
      <xs:element name="value" type="PositiveNumber"/>
      <xs:element name="unit" type="AreaUnit"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="Price">
    <xs:sequence>
      <xs:element name="amount" type="PositiveNumber"/>
      <xs:element name="currency" type="CurrencyCode"/>
      <xs:element name="per" type="PriceBasis"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="Unit">
    <xs:sequence>
      <xs:element name="id" type="NonEmptyString"/>
      <xs:element name="building_id" type="NonEmptyString">
        <xs:annotation>
          <xs:documentation>Must match the id of a building in the same file.</xs:documentation>
        </xs:annotation>
      </xs:element>
      <xs:element name="type" type="UnitType"/>
      <xs:element name="bedrooms" type="xs:nonNegativeInteger" minOccurs="0">
        <xs:annotation>
          <xs:documentation>Leave out for land and commercial units: zero would read as a studio.</xs:documentation>
        </xs:annotation>
      </xs:element>
      <xs:element name="bathrooms" type="xs:nonNegativeInteger" minOccurs="0"/>
      <xs:element name="area" type="Area"/>
      <xs:element name="floor" type="xs:integer" minOccurs="0"/>
      <xs:element name="price" type="Price"/>
      <xs:element name="status" type="UnitStatus"/>
      <xs:element name="floor_plan_url" type="DirectUrl" minOccurs="0"/>
      <xs:element name="updated_at" type="Iso8601"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="Buildings">
    <xs:sequence>
      <xs:element name="building" type="Building" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="Units">
    <xs:sequence>
      <xs:element name="unit" type="Unit" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
  </xs:complexType>

  <!-- ── Root ─────────────────────────────────────────────────────── -->

  <xs:element name="feed">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="version" type="xs:string" fixed="1"/>
        <xs:element name="provider" type="Provider"/>
        <xs:element name="generated_at" type="Iso8601"/>
        <xs:element name="buildings" type="Buildings"/>
        <xs:element name="units" type="Units"/>
        <xs:element name="next_url" type="DirectUrl" minOccurs="0"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>

</xs:schema>
