{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://mapoflogic.com/studio/schema.json",
  "title": "MapOfLogic Studio Diagram",
  "description": "Import/export format for MapOfLogic Studio (https://mapoflogic.com/studio/). A diagram is a set of nodes plus directed links between them. Node positions are NOT included: omit x/y and the Studio lays out nodes automatically from the 'level' field. Paste a document that validates against this schema into Studio via 'Import JSON'.",
  "type": "object",
  "required": ["nodes"],
  "additionalProperties": false,
  "properties": {
    "version": {
      "type": "integer",
      "const": 1,
      "description": "Format version. Always 1."
    },
    "accent": {
      "type": "string",
      "pattern": "^#[0-9A-Fa-f]{6}$",
      "description": "Theme accent color as a 6-digit hex string (e.g. '#EF4444'). Optional; sets the canvas accent."
    },
    "templateId": {
      "type": "string",
      "enum": ["seo", "org", "mindmap", "flow", "arch", "roadmap", "blank"],
      "description": "Internal id of the base template the diagram started from. Optional; appears in exports. You can omit it when generating a new diagram."
    },
    "nodes": {
      "type": "array",
      "minItems": 1,
      "description": "The diagram's nodes. At least one is required.",
      "items": { "$ref": "#/$defs/node" }
    },
    "links": {
      "type": "array",
      "description": "Directed connections between nodes. A link whose 'from' or 'to' does not match an existing node id is silently dropped on import.",
      "items": { "$ref": "#/$defs/link" }
    }
  },
  "$defs": {
    "node": {
      "type": "object",
      "required": ["id", "title"],
      "additionalProperties": false,
      "properties": {
        "id": {
          "type": "string",
          "minLength": 1,
          "description": "Unique, short, stable identifier (e.g. 'home', 'svc-hvac'). Referenced by links. Keep it slug-like and unique within the document."
        },
        "title": {
          "type": "string",
          "minLength": 1,
          "description": "The node's main label. Short and concrete (e.g. 'Homepage', 'Operations', 'Discovery')."
        },
        "subtitle": {
          "type": "string",
          "description": "Secondary line under the title (e.g. a URL path '/services', a role 'COO', a phase 'Q2'). Optional but recommended for operational clarity."
        },
        "description": {
          "type": "string",
          "description": "The node's substance: what it IS or DOES. One or two sentences of real information, never filler. Shown when the card is expanded. This is what turns a box into an operational unit."
        },
        "tags": {
          "type": "array",
          "items": { "type": "string", "maxLength": 24 },
          "maxItems": 12,
          "description": "Up to 12 short labels (each <= 24 chars) for classification (e.g. 'pillar', 'CMS', 'phase-1'). Optional."
        },
        "link": {
          "type": "string",
          "description": "An external URL the node points to (http/https only; other schemes are rejected when used). Optional."
        },
        "image": {
          "type": ["string", "null"],
          "description": "URL of an image to show inside the card, or null. Optional."
        },
        "shape": {
          "type": "string",
          "enum": ["card", "browser", "box", "circle", "pill", "diamond"],
          "default": "card",
          "description": "Node geometry. 'card' = general unit with title/subtitle/icon; 'browser' = a web page (use for site maps / SEO); 'box' = compact block; 'circle' = node/endpoint; 'pill' = tag/state; 'diamond' = decision/gateway (use in flows)."
        },
        "icon": {
          "type": "string",
          "enum": ["", "home", "search", "gear", "chart", "doc", "box", "database", "bolt", "flag", "link", "user", "globe", "target", "layers", "play", "stop", "check", "cpu", "bulb", "shield", "briefcase", "rocket", "server", "pin"],
          "default": "",
          "description": "Optional monochrome line icon. Must be one of the listed keys (empty string = no icon). Any other value is dropped on import."
        },
        "color": {
          "type": "string",
          "pattern": "^#[0-9A-Fa-f]{6}$",
          "default": "#64748B",
          "description": "Node accent color as 6-digit hex. Use color to MEAN something (group, status, branch) — not decoration. Reuse a small consistent palette across the diagram."
        },
        "level": {
          "type": "integer",
          "minimum": 1,
          "maximum": 6,
          "default": 1,
          "description": "Hierarchy depth (1 = top). DRIVES AUTOMATIC LAYOUT: level 1 nodes sit at the top, level 2 below them, and so on. Set this thoughtfully instead of providing coordinates."
        },
        "x": {
          "type": ["number", "null"],
          "description": "Canvas x coordinate. OMIT when generating a diagram — the Studio auto-positions nodes from 'level'. Present only in exports of manually-arranged canvases."
        },
        "y": {
          "type": ["number", "null"],
          "description": "Canvas y coordinate. OMIT when generating a diagram — the Studio auto-positions nodes from 'level'. Present only in exports of manually-arranged canvases."
        }
      }
    },
    "link": {
      "type": "object",
      "required": ["from", "to"],
      "additionalProperties": false,
      "properties": {
        "from": {
          "type": "string",
          "description": "Source node id. Must match an existing node's id."
        },
        "to": {
          "type": "string",
          "description": "Target node id. Must match an existing node's id."
        },
        "label": {
          "type": "string",
          "description": "Optional text shown on the connection (e.g. 'yes', 'escalates to', 'depends on')."
        },
        "style": {
          "type": "string",
          "enum": ["solid", "dashed"],
          "default": "solid",
          "description": "Line style. 'solid' = primary/required relation; 'dashed' = secondary/optional/weak relation."
        }
      }
    }
  }
}
