{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://elsegundo.xyz/atlas.schema.json",
  "title": "Atlas",
  "description": "One open map of everything a site knows: a site atlas or a merged index of several. Spec: https://pointcast.xyz/cartography/atlas. License for this schema: CC0-1.0.",
  "type": "object",
  "required": ["schemaVersion", "kind", "site", "name", "generated", "license", "notOfficial", "center", "radiusMiles", "layers", "records", "counts"],
  "additionalProperties": true,
  "properties": {
    "$schema": { "type": "string", "format": "uri" },
    "schemaVersion": { "type": "string", "pattern": "^1\\.[0-9]+\\.[0-9]+$" },
    "kind": { "type": "string", "enum": ["site-atlas", "merged-index"] },
    "site": { "type": "string", "pattern": "^[a-z0-9.-]+\\.[a-z]{2,}$" },
    "name": { "type": "string", "minLength": 1, "maxLength": 120 },
    "description": { "type": "string", "maxLength": 600 },
    "generated": { "type": "string", "format": "date-time" },
    "license": { "$ref": "#/$defs/spdx" },
    "licenseNote": { "type": "string" },
    "attribution": { "type": "string" },
    "notOfficial": { "type": "string", "minLength": 1 },
    "spec": { "type": "string", "format": "uri" },
    "map": { "type": "string", "format": "uri" },
    "center": {
      "type": "object",
      "required": ["lat", "lon", "name", "source"],
      "properties": {
        "lat": { "$ref": "#/$defs/lat" },
        "lon": { "$ref": "#/$defs/lon" },
        "name": { "type": "string" },
        "source": { "type": "string", "format": "uri" },
        "method": { "type": "string" }
      }
    },
    "radiusMiles": { "type": "number", "minimum": 1, "maximum": 500 },
    "sites": {
      "description": "merged-index only: one entry per site atlas that was merged.",
      "type": "array",
      "items": {
        "type": "object",
        "required": ["site", "atlas", "records", "ok"],
        "properties": {
          "site": { "type": "string" },
          "atlas": { "type": "string", "format": "uri" },
          "generated": { "type": ["string", "null"] },
          "snapshot": { "type": ["string", "null"], "description": "YYYY-MM-DD the committed snapshot was taken, or null when read live." },
          "records": { "type": "integer", "minimum": 0 },
          "ok": { "type": "boolean" },
          "note": { "type": "string" }
        }
      }
    },
    "crossLinks": {
      "type": "array",
      "items": {
        "type": "object",
        "required": ["from", "rel", "to"],
        "properties": { "from": { "$ref": "#/$defs/id" }, "rel": { "$ref": "#/$defs/rel" }, "to": { "$ref": "#/$defs/id" } }
      }
    },
    "layers": {
      "type": "array",
      "items": {
        "type": "object",
        "required": ["id", "name", "types", "count", "inline", "license", "updated"],
        "properties": {
          "id": { "type": "string", "pattern": "^[a-z0-9][a-z0-9-]*$" },
          "name": { "type": "string" },
          "description": { "type": "string" },
          "types": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/type" } },
          "count": { "type": "integer", "minimum": 0, "description": "Rows in the source dataset, whether or not they are inline here." },
          "inline": { "type": "boolean", "description": "true when the layer's records are in records[]; false when only referenced." },
          "data": { "type": "string", "format": "uri", "description": "The source dataset's public machine URL." },
          "page": { "type": "string", "format": "uri" },
          "license": { "$ref": "#/$defs/spdx" },
          "attribution": { "type": "string" },
          "updated": { "$ref": "#/$defs/date" },
          "source": { "$ref": "#/$defs/source" },
          "notes": { "type": "string" },
          "sensitive": { "type": "array", "items": { "type": "string" } }
        }
      }
    },
    "records": { "type": "array", "items": { "$ref": "#/$defs/record" } },
    "counts": {
      "type": "object",
      "required": ["total", "located", "byType", "byLayer"],
      "properties": {
        "total": { "type": "integer", "minimum": 0 },
        "located": { "type": "integer", "minimum": 0 },
        "byType": { "type": "object", "additionalProperties": { "type": "integer" } },
        "byLayer": { "type": "object", "additionalProperties": { "type": "integer" } }
      }
    }
  },
  "$defs": {
    "id": { "type": "string", "pattern": "^(es|pc|in|ues):(place|court|player|gear|event|league|business|quiet-place|shrine|ping|page|bot|agent|route|area|dataset|feed|tool):[a-z0-9][a-z0-9._-]*$" },
    "type": { "type": "string", "enum": ["place", "court", "player", "gear", "event", "league", "business", "quiet-place", "shrine", "ping", "page", "bot", "agent", "route", "area", "dataset", "feed", "tool"] },
    "rel": { "type": "string", "enum": ["near", "in", "part-of", "has-part", "same-as", "about", "plays-at", "hosted-at", "made-by", "sells", "reads", "answers", "see-also"] },
    "spdx": { "type": "string", "enum": ["CC0-1.0", "CC-BY-4.0", "CC-BY-SA-4.0", "ODbL-1.0", "PDDL-1.0", "MIT", "public-domain-us-government"] },
    "date": { "type": "string", "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$" },
    "lat": { "type": "number", "minimum": -90, "maximum": 90 },
    "lon": { "type": "number", "minimum": -180, "maximum": 180 },
    "label": { "type": "string", "enum": ["fact", "listing", "reported", "estimate", "derived"] },
    "source": {
      "type": "object",
      "required": ["url", "checked", "label"],
      "properties": {
        "url": { "type": "string", "format": "uri", "pattern": "^https://" },
        "title": { "type": "string" },
        "checked": { "$ref": "#/$defs/date" },
        "label": { "$ref": "#/$defs/label" },
        "quote": { "type": "string", "maxLength": 300 }
      }
    },
    "location": {
      "type": "object",
      "required": ["lat", "lon", "precision"],
      "properties": {
        "lat": { "$ref": "#/$defs/lat" },
        "lon": { "$ref": "#/$defs/lon" },
        "precision": { "type": "string", "enum": ["point", "address", "block", "neighborhood", "city", "region"] },
        "address": { "type": "string" },
        "area": { "type": "string", "pattern": "^[a-z0-9][a-z0-9-]*$" },
        "method": { "type": "string" },
        "source": { "type": "string", "format": "uri" },
        "license": { "$ref": "#/$defs/spdx" }
      }
    },
    "link": {
      "type": "object",
      "required": ["rel", "id"],
      "properties": { "rel": { "$ref": "#/$defs/rel" }, "id": { "$ref": "#/$defs/id" }, "note": { "type": "string", "maxLength": 200 } }
    },
    "record": {
      "type": "object",
      "required": ["id", "type", "name", "site", "url", "source", "updated", "license", "layer"],
      "additionalProperties": false,
      "properties": {
        "id": { "$ref": "#/$defs/id" },
        "type": { "$ref": "#/$defs/type" },
        "name": { "type": "string", "minLength": 1, "maxLength": 200 },
        "summary": { "type": "string", "maxLength": 280 },
        "site": { "type": "string", "pattern": "^[a-z0-9.-]+\\.[a-z]{2,}$" },
        "url": { "type": "string", "format": "uri", "pattern": "^https://" },
        "data": { "type": "string", "format": "uri", "pattern": "^https://" },
        "location": { "$ref": "#/$defs/location" },
        "source": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/source" } },
        "updated": { "$ref": "#/$defs/date" },
        "links": { "type": "array", "items": { "$ref": "#/$defs/link" } },
        "license": { "$ref": "#/$defs/spdx" },
        "attribution": { "type": "string" },
        "tags": { "type": "array", "items": { "type": "string", "pattern": "^[a-z0-9][a-z0-9:._-]*$" } },
        "layer": { "type": "string", "pattern": "^[a-z0-9][a-z0-9-]*$" },
        "status": { "type": "string", "enum": ["live", "planned", "historical", "draft"] },
        "sensitive": { "type": "array", "items": { "type": "string" } },
        "when": {
          "description": "events only",
          "type": "object",
          "properties": { "start": { "type": "string" }, "end": { "type": ["string", "null"] }, "timezone": { "type": "string" } }
        },
        "image": { "type": "string", "format": "uri" }
      }
    }
  }
}
