{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://melhores.net.br/dados/esquema.json",
  "title": "Dados abertos de uma categoria do Melhores",
  "type": "object",
  "description": "Uma categoria: regra da nota, casos de uso e produtos com especificações, fontes e preço conferido.",
  "additionalProperties": false,
  "required": [
    "fonte",
    "versaoDoEsquema",
    "esquema",
    "url",
    "licenca",
    "atualizadoEm",
    "geradoEm",
    "metodologia",
    "tipoDeAnalise",
    "naoInformado",
    "criterioDeCorte",
    "regraDaNota",
    "formulaRanking",
    "categoria",
    "paginas",
    "atributos",
    "casos",
    "comparacoes",
    "produtos"
  ],
  "properties": {
    "fonte": {
      "type": "string",
      "description": "Nome do site que publica os dados."
    },
    "versaoDoEsquema": {
      "type": "string",
      "description": "Versão deste formato. Campo removido ou com sentido novo muda o primeiro número."
    },
    "esquema": {
      "type": "string",
      "format": "uri",
      "description": "Endereço do JSON Schema que descreve este arquivo."
    },
    "url": {
      "type": "string",
      "format": "uri",
      "description": "Página da categoria no site."
    },
    "licenca": {
      "type": "string",
      "description": "Condição de uso dos dados."
    },
    "atualizadoEm": {
      "type": "string",
      "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      "description": "Data da última revisão editorial da categoria. Formato AAAA-MM-DD."
    },
    "geradoEm": {
      "type": "string",
      "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      "description": "Dia em que este arquivo foi gerado (o site é reconstruído a cada conferência de preço). Formato AAAA-MM-DD."
    },
    "metodologia": {
      "type": "string",
      "format": "uri",
      "description": "Página que explica as regras usadas."
    },
    "tipoDeAnalise": {
      "type": "string",
      "description": "Como os dados foram obtidos. A análise é documental: o site não testa produto."
    },
    "naoInformado": {
      "type": "string",
      "description": "Como ler o valor null nas especificações."
    },
    "criterioDeCorte": {
      "type": [
        "string",
        "null"
      ],
      "description": "Quem pode entrar na base desta categoria e por quê."
    },
    "regraDaNota": {
      "type": "object",
      "description": "Regra da nota de ficha técnica (5 a 10).",
      "additionalProperties": false,
      "required": [
        "escala",
        "calculo",
        "coberturaMinima",
        "parcelas"
      ],
      "properties": {
        "escala": {
          "type": "string",
          "description": "Escala da nota."
        },
        "calculo": {
          "type": "string",
          "description": "A conta, por extenso."
        },
        "coberturaMinima": {
          "type": "number",
          "description": "Fração mínima do peso da regra que precisa estar informada para o produto entrar na base."
        },
        "parcelas": {
          "type": "array",
          "description": "Uma parcela por atributo que entra na nota.",
          "items": {
            "type": "object",
            "description": "Parcela da nota.",
            "additionalProperties": false,
            "required": [
              "atributo",
              "peso"
            ],
            "properties": {
              "atributo": {
                "type": "string",
                "description": "Chave do atributo."
              },
              "peso": {
                "type": "number",
                "description": "Peso da parcela na média."
              },
              "de": {
                "type": "number",
                "description": "Valor em que a parcela vale 0 (atributo numérico)."
              },
              "ate": {
                "type": "number",
                "description": "Valor em que a parcela vale 1 (atributo numérico). Se \"de\" é maior que \"ate\", menor é melhor."
              }
            }
          }
        }
      }
    },
    "formulaRanking": {
      "type": "string",
      "description": "Fórmula da pontuação que ordena o ranking geral."
    },
    "categoria": {
      "type": "object",
      "description": "Identificação da categoria.",
      "additionalProperties": false,
      "required": [
        "slug",
        "nome",
        "nomePlural",
        "grupo"
      ],
      "properties": {
        "slug": {
          "type": "string",
          "description": "Identificador usado nas URLs."
        },
        "nome": {
          "type": "string",
          "description": "Nome no singular."
        },
        "nomePlural": {
          "type": "string",
          "description": "Nome no plural."
        },
        "grupo": {
          "type": "string",
          "description": "Grupo de categorias (Cozinha, Limpeza…)."
        }
      }
    },
    "paginas": {
      "type": "object",
      "description": "Páginas do site sobre esta categoria.",
      "additionalProperties": false,
      "required": [
        "ranking"
      ],
      "properties": {
        "ranking": {
          "type": "string",
          "format": "uri",
          "description": "Ranking e casos de uso."
        },
        "quiz": {
          "type": "string",
          "format": "uri",
          "description": "Quiz \"qual é o melhor pra mim?\"."
        },
        "guia": {
          "type": "string",
          "format": "uri",
          "description": "Guia \"como escolher\", quando publicado."
        }
      }
    },
    "atributos": {
      "type": "array",
      "description": "Atributos da ficha técnica nesta categoria.",
      "items": {
        "type": "object",
        "description": "Atributo.",
        "additionalProperties": false,
        "required": [
          "chave",
          "rotulo",
          "tipo"
        ],
        "properties": {
          "chave": {
            "type": "string",
            "description": "Nome do campo em \"especificacoes\"."
          },
          "rotulo": {
            "type": "string",
            "description": "Nome para leitura."
          },
          "unidade": {
            "type": "string",
            "description": "Unidade de medida, quando há."
          },
          "tipo": {
            "type": "string",
            "enum": [
              "numero",
              "booleano",
              "texto"
            ],
            "description": "Tipo do valor."
          },
          "melhor": {
            "type": "string",
            "enum": [
              "maior",
              "menor"
            ],
            "description": "Sentido em que o valor é melhor, quando há."
          },
          "glossario": {
            "type": "string",
            "format": "uri",
            "description": "Página do glossário que explica o atributo, quando publicada."
          }
        }
      }
    },
    "casos": {
      "type": "array",
      "description": "Casos de uso (necessidades). Cada um é um filtro e uma ordem sobre os produtos.",
      "items": {
        "type": "object",
        "description": "Caso de uso.",
        "additionalProperties": false,
        "required": [
          "slug",
          "titulo",
          "criterio",
          "filtros",
          "ordenar",
          "porAtributo",
          "vencedor",
          "passam",
          "url"
        ],
        "properties": {
          "slug": {
            "type": "string",
            "description": "Identificador usado na URL."
          },
          "titulo": {
            "type": "string",
            "description": "Nome curto do caso."
          },
          "criterio": {
            "type": "string",
            "description": "A regra, em português."
          },
          "filtros": {
            "type": "array",
            "description": "Condições que o produto precisa atender para concorrer.",
            "items": {
              "type": "object",
              "description": "Condição sobre um atributo.",
              "additionalProperties": false,
              "required": [
                "atributo",
                "op",
                "valor"
              ],
              "properties": {
                "atributo": {
                  "type": "string",
                  "description": "Chave de um atributo da categoria, \"preco\" (preço conferido na Shopee) ou \"nota\" (nota de ficha técnica)."
                },
                "op": {
                  "type": "string",
                  "enum": [
                    "=",
                    "!=",
                    "<",
                    "<=",
                    ">",
                    ">="
                  ],
                  "description": "Operador da comparação."
                },
                "valor": {
                  "type": [
                    "number",
                    "boolean",
                    "string"
                  ],
                  "description": "Valor de referência."
                }
              }
            }
          },
          "ordenar": {
            "type": "string",
            "enum": [
              "geral",
              "nota",
              "preco",
              "custo-beneficio"
            ],
            "description": "Critério de ordenação dos que passam."
          },
          "porAtributo": {
            "type": [
              "object",
              "null"
            ],
            "description": "Quando presente, os que passam são ordenados por este atributo (\"ordenar\" vira o desempate).",
            "additionalProperties": false,
            "required": [
              "chave",
              "melhor"
            ],
            "properties": {
              "chave": {
                "type": "string",
                "description": "Chave do atributo."
              },
              "melhor": {
                "type": "string",
                "enum": [
                  "maior",
                  "menor"
                ],
                "description": "Sentido da ordenação."
              }
            }
          },
          "vencedor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Slug do 1º colocado, ou null se nenhum produto passa."
          },
          "passam": {
            "type": "array",
            "description": "Slugs dos produtos que passam no filtro, na ordem da regra.",
            "items": {
              "type": "string"
            }
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Página do caso no site."
          }
        }
      }
    },
    "comparacoes": {
      "type": "array",
      "description": "Comparações lado a lado publicadas nesta categoria.",
      "items": {
        "type": "object",
        "description": "Comparação.",
        "additionalProperties": false,
        "required": [
          "a",
          "b",
          "url"
        ],
        "properties": {
          "a": {
            "type": "string",
            "description": "Slug do 1º produto."
          },
          "b": {
            "type": "string",
            "description": "Slug do 2º produto."
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Página da comparação."
          }
        }
      }
    },
    "produtos": {
      "type": "array",
      "description": "Produtos da categoria, na ordem do ranking geral.",
      "items": {
        "type": "object",
        "description": "Produto.",
        "additionalProperties": false,
        "required": [
          "posicao",
          "slug",
          "nome",
          "marca",
          "paginaDaMarca",
          "modelo",
          "notaFichaTecnica",
          "coberturaDaNota",
          "pontuacao",
          "especificacoes",
          "fontes",
          "especificacoesConferidasEm",
          "shopee",
          "historicoPreco",
          "valeAPena",
          "indicadoPara",
          "naoIndicadoPara",
          "url",
          "fichaTecnica"
        ],
        "properties": {
          "posicao": {
            "type": "integer",
            "description": "Posição no ranking geral."
          },
          "slug": {
            "type": "string",
            "description": "Identificador usado nas URLs."
          },
          "nome": {
            "type": "string",
            "description": "Nome de exibição."
          },
          "marca": {
            "type": "string",
            "description": "Marca."
          },
          "paginaDaMarca": {
            "type": [
              "string",
              "null"
            ],
            "description": "Página da marca no site, quando a marca tem 3 produtos ou mais na base."
          },
          "modelo": {
            "type": "string",
            "description": "Código do modelo como o fabricante escreve."
          },
          "notaFichaTecnica": {
            "type": "number",
            "description": "Nota de 5 a 10 calculada pela regra da categoria. Não é resultado de teste."
          },
          "coberturaDaNota": {
            "type": "number",
            "description": "Fração do peso da regra que o fabricante informa para este produto (0 a 1)."
          },
          "pontuacao": {
            "type": "number",
            "description": "Pontuação que ordena o ranking geral: nota menos o desconto do preço."
          },
          "especificacoes": {
            "type": "object",
            "description": "Chave do atributo → valor. null quer dizer que o fabricante não publica o dado; não é zero nem \"não tem\".",
            "additionalProperties": {
              "type": [
                "number",
                "boolean",
                "string",
                "null"
              ]
            }
          },
          "fontes": {
            "type": "array",
            "description": "Página oficial e manual de onde saíram as especificações.",
            "items": {
              "type": "object",
              "description": "Fonte.",
              "additionalProperties": false,
              "required": [
                "titulo",
                "url"
              ],
              "properties": {
                "titulo": {
                  "type": "string",
                  "description": "Descrição da fonte."
                },
                "url": {
                  "type": "string",
                  "format": "uri",
                  "description": "Endereço, sem login."
                }
              }
            }
          },
          "especificacoesConferidasEm": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
            "description": "Dia em que a ficha foi lida na fonte. Formato AAAA-MM-DD."
          },
          "shopee": {
            "type": "object",
            "description": "Dados do anúncio conferido na Shopee pela API de afiliados.",
            "additionalProperties": false,
            "required": [
              "preco",
              "precoMax",
              "moeda",
              "notaDosCompradores",
              "vendas",
              "vendedor",
              "lojaOficial",
              "conferidoEm",
              "link",
              "linkDeAfiliado"
            ],
            "properties": {
              "preco": {
                "type": "number",
                "description": "O valor mais baixo entre as variações do anúncio, sem cupom nem frete."
              },
              "precoMax": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Maior preço entre as variações, quando difere do menor."
              },
              "moeda": {
                "type": "string",
                "description": "Código da moeda."
              },
              "notaDosCompradores": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Nota dos compradores na Shopee (0 a 5). Não é nota do site."
              },
              "vendas": {
                "type": "integer",
                "description": "Unidades vendidas do anúncio, segundo a Shopee."
              },
              "vendedor": {
                "type": "string",
                "description": "Nome da loja na Shopee."
              },
              "lojaOficial": {
                "type": "boolean",
                "description": "true quando a Shopee marca o vendedor como Loja Oficial. Pode ser a loja do fabricante ou de um varejista."
              },
              "conferidoEm": {
                "type": "string",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                "description": "Dia da conferência de preço, nota e vendas. Formato AAAA-MM-DD."
              },
              "link": {
                "type": "string",
                "format": "uri",
                "description": "Link do anúncio."
              },
              "linkDeAfiliado": {
                "type": "boolean",
                "description": "true: a compra por este link pode gerar comissão para o site."
              }
            }
          },
          "historicoPreco": {
            "type": "array",
            "description": "Um ponto por conferência de preço. Começa no dia em que o produto entrou na base; nenhum ponto é estimado.",
            "items": {
              "type": "object",
              "description": "Ponto do histórico.",
              "additionalProperties": false,
              "required": [
                "data",
                "preco"
              ],
              "properties": {
                "data": {
                  "type": "string",
                  "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                  "description": "Dia da conferência. Formato AAAA-MM-DD."
                },
                "preco": {
                  "type": "number",
                  "description": "Preço conferido."
                }
              }
            }
          },
          "valeAPena": {
            "type": "object",
            "description": "Resposta calculada da página \"vale a pena?\".",
            "additionalProperties": false,
            "required": [
              "resposta",
              "texto"
            ],
            "properties": {
              "resposta": {
                "type": "string",
                "enum": [
                  "Sim",
                  "Depende",
                  "Não"
                ],
                "description": "Sim: 1º do ranking ou de um caso. Não: outro modelo iguala ou supera em tudo, com preço igual ou menor. Depende: o resto."
              },
              "texto": {
                "type": "string",
                "description": "O motivo, por extenso."
              }
            }
          },
          "indicadoPara": {
            "type": "array",
            "description": "Para quem a ficha atende.",
            "items": {
              "type": "string"
            }
          },
          "naoIndicadoPara": {
            "type": "array",
            "description": "Para quem a ficha não atende.",
            "items": {
              "type": "string"
            }
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Página \"vale a pena?\" do produto."
          },
          "fichaTecnica": {
            "type": "string",
            "format": "uri",
            "description": "Página da ficha técnica do produto."
          }
        }
      }
    }
  }
}