{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://ww3.humansbe.ing/ntoid/schema/country-board.schema.json",
  "title": "N.T.O.I.D. country board",
  "description": "One national threat-observation board. See METHOD.md. Composite and watch level are recomputed by tools/validate.py and must match.",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "schema_version",
    "country",
    "status",
    "updated_at",
    "indicators",
    "changelog"
  ],
  "properties": {
    "schema_version": {
      "const": "1.0"
    },
    "country": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "code",
        "name"
      ],
      "properties": {
        "code": {
          "type": "string",
          "description": "ISO 3166-1 alpha-2 for a country board (UK instead of GB on purpose). A regional board uses a 3-4 letter code and must list its members.",
          "pattern": "^[A-Z]{2,4}$"
        },
        "name": {
          "type": "string",
          "minLength": 2
        },
        "members": {
          "type": "array",
          "description": "Regional board only: the ISO alpha-2 codes of the countries it covers. Required when code is longer than 2 letters; forbidden otherwise (tools/validate.py).",
          "minItems": 2,
          "items": {
            "type": "string",
            "pattern": "^[A-Z]{2}$"
          }
        },
        "preparedness_authority": {
          "$ref": "#/$defs/source"
        }
      }
    },
    "status": {
      "enum": [
        "active",
        "template"
      ]
    },
    "updated_at": {
      "type": "string",
      "description": "ISO-8601 with Europe/Amsterdam offset (+01:00 or +02:00)",
      "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}(:\\d{2})?\\+0[12]:00$"
    },
    "composite": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "score"
      ],
      "properties": {
        "score": {
          "type": [
            "integer",
            "null"
          ],
          "minimum": 0,
          "maximum": 100
        },
        "previous_score": {
          "type": [
            "integer",
            "null"
          ],
          "minimum": 0,
          "maximum": 100
        }
      }
    },
    "watch_level": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "level",
        "previous",
        "since"
      ],
      "properties": {
        "level": {
          "enum": [
            "V",
            "IV",
            "III",
            "II",
            "I",
            "unrated"
          ]
        },
        "previous": {
          "enum": [
            "V",
            "IV",
            "III",
            "II",
            "I",
            "unrated",
            null
          ]
        },
        "since": {
          "$ref": "#/$defs/date"
        },
        "hold": {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "reason"
          ],
          "properties": {
            "reason": {
              "type": "string",
              "minLength": 10
            },
            "computed_level": {
              "type": "string"
            }
          }
        }
      }
    },
    "hazard_band": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "band",
        "previous",
        "since",
        "basis",
        "sources"
      ],
      "properties": {
        "band": {
          "enum": [
            "low",
            "moderate",
            "high",
            "severe",
            "extreme"
          ]
        },
        "previous": {
          "enum": [
            "low",
            "moderate",
            "high",
            "severe",
            "extreme",
            null
          ]
        },
        "since": {
          "$ref": "#/$defs/date"
        },
        "basis": {
          "type": "string",
          "minLength": 20
        },
        "sources": {
          "type": "array",
          "minItems": 1,
          "items": {
            "$ref": "#/$defs/source"
          }
        }
      }
    },
    "story_stage": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "stage",
        "previous",
        "since",
        "basis",
        "sources"
      ],
      "properties": {
        "stage": {
          "enum": [
            "quiet",
            "pressure",
            "confrontation",
            "crisis",
            "break",
            "recovery"
          ]
        },
        "previous": {
          "enum": [
            "quiet",
            "pressure",
            "confrontation",
            "crisis",
            "break",
            "recovery",
            null
          ]
        },
        "since": {
          "$ref": "#/$defs/date"
        },
        "basis": {
          "type": "string",
          "minLength": 20
        },
        "sources": {
          "type": "array",
          "minItems": 1,
          "items": {
            "$ref": "#/$defs/source"
          }
        }
      }
    },
    "indicators": {
      "type": "array",
      "maxItems": 12,
      "items": {
        "$ref": "#/$defs/indicator"
      }
    },
    "household": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "what_changed",
        "why_it_matters",
        "prepare"
      ],
      "properties": {
        "what_changed": {
          "type": "string",
          "minLength": 10
        },
        "why_it_matters": {
          "type": "string",
          "minLength": 10
        },
        "prepare": {
          "type": "array",
          "minItems": 1,
          "maxItems": 6,
          "items": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "text",
              "source"
            ],
            "properties": {
              "text": {
                "type": "string",
                "minLength": 10
              },
              "source": {
                "$ref": "#/$defs/source"
              }
            }
          }
        }
      }
    },
    "changelog": {
      "type": "array",
      "items": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "date",
          "note"
        ],
        "properties": {
          "date": {
            "$ref": "#/$defs/date"
          },
          "note": {
            "type": "string",
            "minLength": 5
          }
        }
      }
    },
    "notes": {
      "type": "string"
    }
  },
  "$defs": {
    "date": {
      "type": "string",
      "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
    },
    "source": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "name",
        "url",
        "date"
      ],
      "properties": {
        "name": {
          "type": "string",
          "minLength": 3
        },
        "url": {
          "type": "string",
          "pattern": "^https://[^\\s]+$"
        },
        "date": {
          "$ref": "#/$defs/date"
        },
        "note": {
          "type": "string"
        }
      }
    },
    "bullet": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "text",
        "kind",
        "attribution",
        "source"
      ],
      "properties": {
        "text": {
          "type": "string",
          "minLength": 15,
          "maxLength": 600
        },
        "kind": {
          "enum": [
            "fact",
            "official-claim",
            "analysis"
          ]
        },
        "attribution": {
          "enum": [
            "confirmed",
            "open",
            "not-applicable"
          ]
        },
        "source": {
          "$ref": "#/$defs/source"
        }
      }
    },
    "indicator": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "id",
        "name",
        "domain",
        "level",
        "previous_level",
        "last_change",
        "moved_this_update",
        "level_basis",
        "bullets"
      ],
      "properties": {
        "id": {
          "type": "string",
          "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$"
        },
        "name": {
          "type": "string",
          "minLength": 5,
          "maxLength": 90
        },
        "domain": {
          "enum": [
            "cyber-critical-infrastructure",
            "hybrid-influence",
            "military-territorial",
            "energy-resources",
            "economy-supply-chains",
            "social-cohesion-unrest",
            "diplomatic-alignment",
            "legal-emergency-powers"
          ]
        },
        "level": {
          "type": "integer",
          "minimum": 0,
          "maximum": 4
        },
        "previous_level": {
          "type": [
            "integer",
            "null"
          ],
          "minimum": 0,
          "maximum": 4
        },
        "last_change": {
          "$ref": "#/$defs/date"
        },
        "moved_this_update": {
          "type": "boolean"
        },
        "level_basis": {
          "type": "string",
          "minLength": 20,
          "description": "Why this level, and how an official scale maps onto ours if one exists."
        },
        "weight": {
          "type": "number",
          "minimum": 0.5,
          "maximum": 2
        },
        "weight_basis": {
          "type": "string",
          "minLength": 10
        },
        "summary": {
          "type": "string",
          "maxLength": 300
        },
        "bullets": {
          "type": "array",
          "minItems": 2,
          "maxItems": 4,
          "items": {
            "$ref": "#/$defs/bullet"
          }
        }
      }
    }
  }
}