{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://qwanfan.github.io/BuyOrRent/v1/property-costs-v1.schema.json",
  "title": "BuyOrRent owner-occupied property cost catalog",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "schemaVersion",
    "datasetVersion",
    "publishedAt",
    "checkedAt",
    "nextReviewAt",
    "methodology",
    "contentDigest",
    "countries",
    "investmentReturn"
  ],
  "properties": {
    "schemaVersion": {
      "const": 1
    },
    "datasetVersion": {
      "type": "string",
      "pattern": "^[0-9]{4}\\.[0-9]{2}\\.[0-9]{2}(\\.[0-9]+)?$"
    },
    "publishedAt": {
      "type": "string",
      "format": "date-time"
    },
    "checkedAt": {
      "type": "string",
      "format": "date-time"
    },
    "nextReviewAt": {
      "type": "string",
      "format": "date"
    },
    "methodology": {
      "type": "string",
      "minLength": 20
    },
    "contentDigest": {
      "type": "string",
      "pattern": "^[a-f0-9]{64}$"
    },
    "countries": {
      "type": "object",
      "minProperties": 14,
      "maxProperties": 14,
      "additionalProperties": {
        "$ref": "#/$defs/countryCost"
      }
    },
    "investmentReturn": {
      "$ref": "#/$defs/investmentReturn"
    }
  },
  "$defs": {
    "investmentReturn": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "rate",
        "method",
        "startDate",
        "endDate",
        "startLevel",
        "endLevel",
        "sourceName",
        "sourceUrl"
      ],
      "properties": {
        "rate": {
          "type": "number",
          "minimum": -0.5,
          "maximum": 0.5
        },
        "method": {
          "const": "spxPriceCagr10Y"
        },
        "startDate": {
          "type": "string",
          "format": "date"
        },
        "endDate": {
          "type": "string",
          "format": "date"
        },
        "startLevel": {
          "type": "number",
          "exclusiveMinimum": 0
        },
        "endLevel": {
          "type": "number",
          "exclusiveMinimum": 0
        },
        "sourceName": {
          "type": "string",
          "minLength": 2
        },
        "sourceUrl": {
          "type": "string",
          "pattern": "^https://"
        }
      }
    },
    "source": {
      "type": "object",
      "additionalProperties": false,
      "required": ["name", "url"],
      "properties": {
        "name": {
          "type": "string",
          "minLength": 2
        },
        "url": {
          "type": "string",
          "format": "uri",
          "pattern": "^https://"
        }
      }
    },
    "countryCost": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "propertyTaxRate",
        "buyingCostRate",
        "sellingCostRate",
        "verifiedAt",
        "confidence",
        "methodologyNote",
        "sources",
        "mortgageRate",
        "rentGrowth",
        "appreciation"
      ],
      "properties": {
        "propertyTaxRate": {
          "type": "number",
          "minimum": 0,
          "maximum": 0.06
        },
        "buyingCostRate": {
          "type": "number",
          "minimum": 0,
          "maximum": 0.8
        },
        "sellingCostRate": {
          "type": "number",
          "minimum": 0,
          "maximum": 0.3
        },
        "verifiedAt": {
          "type": "string",
          "format": "date"
        },
        "confidence": {
          "enum": ["high", "medium", "low"]
        },
        "methodologyNote": {
          "type": "string",
          "minLength": 10
        },
        "sources": {
          "type": "array",
          "minItems": 1,
          "items": {
            "$ref": "#/$defs/source"
          }
        },
        "mortgageRate": {
          "$ref": "#/$defs/mortgageRate"
        },
        "rentGrowth": {
          "$ref": "#/$defs/rentGrowth"
        },
        "appreciation": {
          "$ref": "#/$defs/appreciation"
        }
      }
    },
    "seriesObservation": {
      "type": "object",
      "additionalProperties": false,
      "required": ["rate", "periodLabel", "sourceName", "sourceUrl"],
      "properties": {
        "rate": {
          "type": "number"
        },
        "periodLabel": {
          "type": "string",
          "minLength": 4
        },
        "sourceName": {
          "type": "string",
          "minLength": 2
        },
        "sourceUrl": {
          "type": "string",
          "pattern": "^https://"
        }
      }
    },
    "mortgageRate": {
      "allOf": [
        { "$ref": "#/$defs/seriesObservation" },
        {
          "type": "object",
          "properties": {
            "rate": { "type": "number", "exclusiveMinimum": 0, "maximum": 0.2 }
          }
        }
      ]
    },
    "rentGrowth": {
      "allOf": [
        { "$ref": "#/$defs/seriesObservation" },
        {
          "type": "object",
          "properties": {
            "rate": { "type": "number", "minimum": -0.05, "maximum": 0.15 }
          }
        }
      ]
    },
    "appreciation": {
      "allOf": [
        { "$ref": "#/$defs/seriesObservation" },
        {
          "type": "object",
          "properties": {
            "rate": { "type": "number", "minimum": -0.2, "maximum": 0.2 }
          }
        }
      ]
    }
  }
}
