{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://shumen.uk/cost-of-living-schema.json",
  "title": "Shumen.UK cost-of-living dataset v2",
  "description": "Additive v2 contract. Existing fields and URL preserved. ISO dates in JSON; DD/MM/YYYY and MM/YYYY for readers. price_eur is historical evidence; only current_price_eur is eligible for current totals. Null means missing, never zero. last_checked_at does not renew observation dates.",
  "type": "object",
  "required": [
    "_metadata",
    "groceries",
    "rent",
    "fx",
    "calculator"
  ],
  "properties": {
    "_metadata": {
      "type": "object",
      "properties": {
        "schema_version": {
          "const": 2
        }
      }
    },
    "groceries": {
      "$ref": "#/$defs/section"
    },
    "utilities": {
      "$ref": "#/$defs/section"
    },
    "transport": {
      "$ref": "#/$defs/section"
    },
    "rent": {
      "$ref": "#/$defs/section"
    },
    "eating_out": {
      "$ref": "#/$defs/section"
    },
    "lifestyle": {
      "$ref": "#/$defs/section"
    },
    "grocery_cities": {
      "type": "object",
      "additionalProperties": {
        "$ref": "#/$defs/section"
      }
    },
    "household_examples": {
      "type": "object",
      "required": [
        "scenarios",
        "food",
        "reviewed_on",
        "review_due"
      ],
      "properties": {
        "scenarios": {
          "type": "array",
          "items": {
            "type": "object",
            "required": [
              "id",
              "complete",
              "monthly_total_eur",
              "headline_eur",
              "lines",
              "missing"
            ],
            "properties": {
              "complete": {
                "type": "boolean"
              },
              "monthly_total_eur": {
                "type": [
                  "number",
                  "null"
                ],
                "minimum": 0
              },
              "headline_eur": {
                "type": [
                  "integer",
                  "null"
                ],
                "minimum": 0
              },
              "lines": {
                "type": "array"
              },
              "missing": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "uk_essentials": {
      "type": "object",
      "properties": {
        "items": {
          "type": "array",
          "items": {
            "type": "object",
            "required": [
              "bg_item_id",
              "uk_price_gbp",
              "uk_quantity",
              "quantity_unit",
              "source_url",
              "observed_at",
              "review_due"
            ],
            "properties": {
              "uk_price_gbp": {
                "type": "number",
                "exclusiveMinimum": 0
              },
              "uk_quantity": {
                "type": "number",
                "exclusiveMinimum": 0
              },
              "bg_quantity": {
                "type": "number",
                "exclusiveMinimum": 0
              }
            }
          }
        }
      }
    },
    "evidence_register": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "id",
          "disposition",
          "reason",
          "reviewed_on"
        ],
        "properties": {
          "disposition": {
            "enum": [
              "verified",
              "replaced",
              "retired"
            ]
          }
        }
      }
    }
  },
  "$defs": {
    "section": {
      "type": "object",
      "properties": {
        "items": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/item"
          }
        }
      }
    },
    "item": {
      "type": "object",
      "required": [
        "id",
        "name",
        "evidence_type",
        "source_observed_at",
        "current_price_eur",
        "calculation_dependencies"
      ],
      "properties": {
        "id": {
          "type": "string"
        },
        "name": {
          "type": "string"
        },
        "evidence_type": {
          "enum": [
            "observed",
            "inflation_estimate",
            "user_entered"
          ]
        },
        "source_observed_at": {
          "type": [
            "string",
            "null"
          ],
          "format": "date"
        },
        "observed_at": {
          "type": "string"
        },
        "data_period": {
          "type": "string",
          "pattern": "^[0-9]{4}-(0[1-9]|1[0-2])$"
        },
        "last_checked_at": {
          "type": "string"
        },
        "effective_from": {
          "type": "string",
          "format": "date"
        },
        "review_due": {
          "type": "string",
          "format": "date"
        },
        "current_price_eur": {
          "type": [
            "number",
            "null"
          ],
          "minimum": 0
        },
        "calculation_dependencies": {
          "type": "array"
        },
        "source_provider": {
          "type": "string"
        },
        "price_basis": {
          "enum": [
            "minimum_reported_regular_price"
          ]
        },
        "locality": {
          "type": "string"
        },
        "retailer": {
          "type": "string"
        },
        "shop": {
          "type": "string"
        },
        "settlement_code": {
          "type": "string",
          "pattern": "^[0-9]{5}$"
        },
        "product_code": {
          "type": "string"
        },
        "product_name_bg": {
          "type": "string"
        },
        "category_code": {
          "type": "string"
        },
        "quantity": {
          "type": "number",
          "exclusiveMinimum": 0
        },
        "quantity_unit": {
          "enum": [
            "g",
            "kg",
            "L",
            "ml",
            "eggs"
          ]
        },
        "archive_url": {
          "type": "string",
          "format": "uri"
        },
        "archive_sha256": {
          "type": "string",
          "pattern": "^[a-f0-9]{64}$"
        },
        "offers": {
          "type": "array",
          "items": {
            "type": "object"
          }
        },
        "publication_status": {
          "enum": [
            "active",
            "retired"
          ]
        },
        "retired_on": {
          "type": "string",
          "format": "date"
        },
        "replacement_id": {
          "type": [
            "string",
            "null"
          ]
        },
        "replaces_id": {
          "type": "string"
        },
        "offer_expires": {
          "type": "string",
          "format": "date"
        },
        "listing_count": {
          "type": "integer",
          "minimum": 1
        },
        "statistic": {
          "type": "string"
        }
      }
    }
  }
}
