{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://faultypacket.co.uk/assets/schema/domain-health-v1.json",
  "title": "FaultyPacket domain health file, version 1",
  "description": "Portable file of DNS and email-authentication scan results. Written and read by the free scanner at https://faultypacket.co.uk/ (export / import in the browser; nothing is uploaded) and by FaultyPacket command-line tools. Readers must check format and version; unknown extra properties must be ignored so later minor additions stay compatible. A breaking change ships as a new file name (domain-health-v2.json).",
  "type": "object",
  "required": ["format", "version", "exported_utc", "domains"],
  "properties": {
    "$schema": { "type": "string", "description": "Optional pointer to this schema." },
    "format": { "const": "faultypacket-domain-health" },
    "version": { "const": 1 },
    "exported_utc": { "type": "string", "format": "date-time", "description": "When the file was written (ISO 8601, UTC)." },
    "generator": { "type": "string", "description": "Tool that wrote the file, e.g. faultypacket-web/1." },
    "domains": {
      "type": "array",
      "maxItems": 1000,
      "description": "One entry per domain: its latest scan. The web scanner keeps the last 10 domains.",
      "items": { "$ref": "#/$defs/scan" }
    }
  },
  "$defs": {
    "scan": {
      "type": "object",
      "required": ["domain", "scanned_utc", "score", "grade", "controls"],
      "properties": {
        "domain": { "type": "string", "pattern": "^[a-z0-9-]+(\\.[a-z0-9-]+)+$" },
        "scanned_utc": { "type": "string", "format": "date-time" },
        "score": { "type": "integer", "minimum": 0, "maximum": 100 },
        "grade": { "type": "string", "enum": ["A+", "A", "B", "C", "D", "F"] },
        "controls": { "type": "array", "items": { "$ref": "#/$defs/control" } }
      }
    },
    "control": {
      "type": "object",
      "required": ["name", "status"],
      "properties": {
        "name": { "type": "string", "description": "Check name, e.g. DMARC Policy." },
        "status": { "enum": ["pass", "warn", "fail"], "description": "pass = Passed, warn = Needs attention, fail = Critical." },
        "finding": { "type": "string" },
        "observed": { "type": "string", "description": "Record(s) as seen in public DNS at scan time; newline separated." },
        "changes": { "type": "array", "items": { "$ref": "#/$defs/change" } }
      }
    },
    "change": {
      "type": "object",
      "required": ["action", "type", "name", "value"],
      "properties": {
        "action": { "enum": ["add", "change"] },
        "type": { "enum": ["TXT", "MX", "CAA", "FILE"], "description": "FILE = a file to publish over HTTPS (e.g. the MTA-STS policy), not a DNS record." },
        "name": { "type": "string", "description": "Fully qualified record name, or the HTTPS URL for FILE." },
        "value": { "type": "string", "description": "Record content without surrounding quotes (TXT), MX target, CAA 'flags tag \"value\"', or the file body." },
        "ttl": { "type": "integer", "minimum": 60 },
        "priority": { "type": "integer", "minimum": 0 },
        "note": { "type": "string" }
      }
    }
  }
}
