{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://oto.dtp/schemas/seo/seo.schema.json",
  "title": "Contrat de sortie du generateur SEO (bundle keywords + schema.org + hreflang)",
  "description": "Valide par le validateur maison Publiciste (draft-07, sous-ensemble). La cross-coherence fine (sources resolubles, anti-invention, mapping projets) est verifiee par les invariants de seo_gen.py.",
  "type": "object",
  "required": ["keywords", "schema_org", "hreflang", "manifest"],
  "additionalProperties": false,
  "properties": {
    "keywords": {
      "type": "array",
      "minItems": 1,
      "items": {
        "type": "object",
        "required": ["term", "lang", "scope", "projet", "intent", "category", "sources"],
        "additionalProperties": false,
        "properties": {
          "term": { "type": "string", "minLength": 1 },
          "lang": { "type": "string", "enum": ["fr", "en", "es"] },
          "scope": { "type": "string", "enum": ["global", "projet"] },
          "projet": { "type": ["string", "null"] },
          "intent": { "type": ["string", "null"] },
          "category": { "type": ["string", "null"] },
          "sources": {
            "type": "array",
            "minItems": 1,
            "items": { "type": "string", "minLength": 1 }
          }
        }
      }
    },
    "schema_org": {
      "type": "object",
      "required": ["@context", "@graph"],
      "additionalProperties": false,
      "properties": {
        "@context": { "type": "string", "const": "https://schema.org" },
        "@graph": {
          "type": "array",
          "minItems": 1,
          "items": {
            "type": "object",
            "required": ["@type", "@id"],
            "additionalProperties": true,
            "properties": {
              "@type": { "type": "string", "minLength": 1 },
              "@id": { "type": "string", "pattern": "^https://" }
            }
          }
        }
      }
    },
    "hreflang": {
      "type": "object",
      "required": ["base_url", "x_default_lang", "pages"],
      "additionalProperties": false,
      "properties": {
        "base_url": { "type": "string", "pattern": "^https://" },
        "x_default_lang": { "type": "string", "minLength": 1 },
        "pages": {
          "type": "array",
          "minItems": 1,
          "items": {
            "type": "object",
            "required": ["page", "canonical", "alternates"],
            "additionalProperties": false,
            "properties": {
              "page": { "type": "string", "minLength": 1 },
              "canonical": { "type": "string", "pattern": "^https://" },
              "alternates": {
                "type": "array",
                "minItems": 2,
                "items": {
                  "type": "object",
                  "required": ["hreflang", "href"],
                  "additionalProperties": false,
                  "properties": {
                    "hreflang": { "type": "string", "minLength": 1 },
                    "href": { "type": "string", "pattern": "^https://" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "manifest": {
      "type": "object",
      "required": ["deliverable", "base_url", "langs", "default_lang", "counts", "targets"],
      "additionalProperties": true,
      "properties": {
        "deliverable": { "type": "string", "const": "seo" },
        "base_url": { "type": "string", "pattern": "^https://" },
        "langs": { "type": "array", "minItems": 1, "items": { "type": "string" } },
        "default_lang": { "type": "string", "minLength": 1 },
        "counts": {
          "type": "object",
          "required": ["keywords_total", "schema_org_nodes", "hreflang_pages", "projects"],
          "additionalProperties": true,
          "properties": {
            "keywords_total": { "type": "integer", "minimum": 0 },
            "schema_org_nodes": { "type": "integer", "minimum": 0 },
            "hreflang_pages": { "type": "integer", "minimum": 0 },
            "projects": { "type": "integer", "minimum": 0 }
          }
        },
        "targets": {
          "type": "object",
          "required": ["min_keywords_total", "min_keywords_per_lang"],
          "additionalProperties": false,
          "properties": {
            "min_keywords_total": { "type": "integer", "minimum": 0 },
            "min_keywords_per_lang": { "type": "integer", "minimum": 0 }
          }
        }
      }
    }
  }
}
