{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://vrgo360.com/data/routes.schema.json",
  "title": "VRGO route catalog",
  "type": "object",
  "required": ["updatedAt", "source", "routes"],
  "additionalProperties": false,
  "properties": {
    "updatedAt": {
      "type": "string",
      "description": "ISO date or datetime when this catalog was last refreshed."
    },
    "source": {
      "type": "string",
      "description": "Data source label, for example manual-seed, n8n-deovr, vrgo-player."
    },
    "schema": {
      "type": "string",
      "description": "Public schema URL used by automation clients."
    },
    "routes": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "slug",
          "title",
          "shortTitle",
          "location",
          "summary",
          "description",
          "durationLabel",
          "durationIso",
          "paceKmh",
          "difficulty",
          "terrain",
          "routeType",
          "inclineRecommendation",
          "motionComfort",
          "deovrUrl",
          "nativePlayerUrl",
          "thumbnail",
          "screenshots",
          "keywords",
          "features"
        ],
        "additionalProperties": true,
        "properties": {
          "slug": {
            "type": "string",
            "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
            "description": "Stable URL key. Do not change after publishing unless a redirect is added."
          },
          "title": { "type": "string" },
          "shortTitle": { "type": "string" },
          "status": {
            "type": "string",
            "enum": ["published", "draft", "hidden", "archived"],
            "description": "Public route pages use only published routes. n8n imports should stay draft until metadata is reviewed."
          },
          "published": {
            "type": "boolean",
            "description": "Set false to keep an imported or incomplete route out of the public catalog, sitemap, and route detail pages."
          },
          "reviewRequired": {
            "type": "boolean",
            "description": "Marks automatically imported DeoVR videos that still need route metadata."
          },
          "location": { "type": "string" },
          "summary": { "type": "string" },
          "description": { "type": "string" },
          "durationLabel": { "type": "string" },
          "durationIso": {
            "type": "string",
            "pattern": "^PT[0-9]+[HMS].*|^PT[0-9]+M$",
            "description": "ISO 8601 duration, for example PT25M."
          },
          "distanceKm": {
            "type": ["number", "null"]
          },
          "paceKmh": {
            "type": "number",
            "minimum": 0
          },
          "difficulty": {
            "type": "string",
            "enum": ["Beginner", "Intermediate", "Advanced"]
          },
          "terrain": { "type": "string" },
          "routeType": { "type": "string" },
          "inclineRecommendation": { "type": "string" },
          "motionComfort": {
            "type": "string",
            "enum": ["Low", "Moderate", "High"]
          },
          "deovrUrl": {
            "type": ["string", "null"]
          },
          "nativePlayerUrl": {
            "type": ["string", "null"]
          },
          "thumbnail": {
            "type": "string",
            "description": "Local public site path, for example images/routes/example-cover.jpg. Do not store CDN URLs here."
          },
          "cardImage": {
            "type": ["string", "null"],
            "description": "Optional local public site path used by route cards. Do not store CDN URLs here."
          },
          "heroImage": {
            "type": ["string", "null"],
            "description": "Optional local public site path used by the route hero. Do not store CDN URLs here."
          },
          "screenshots": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "Local public site path. Do not store CDN URLs here."
            }
          },
          "keywords": {
            "type": "array",
            "items": { "type": "string" }
          },
          "features": {
            "type": "object",
            "required": ["deovrAvailable", "autopilotTurns", "mirrorRoute", "speedControl", "offlineCopies"],
            "additionalProperties": true,
            "properties": {
              "deovrAvailable": { "type": "boolean" },
              "autopilotTurns": { "type": ["boolean", "string"] },
              "mirrorRoute": { "type": ["boolean", "string"] },
              "speedControl": { "type": ["boolean", "string"] },
              "offlineCopies": { "type": ["boolean", "string"] }
            }
          }
        }
      }
    }
  }
}
