{
  "openapi": "3.1.0",
  "info": {
    "title": "onto·fincas Catalogación API v2 (GPT)",
    "version": "2.0.0",
    "description": "Clasifica una incidencia textual en la taxonomía onto·fincas con augmentación vectorial semántica. Incluye los campos vectorAugmented y semanticMatches adicionales respecto a v1."
  },
  "servers": [
    {
      "url": "https://api.aaff.pro"
    }
  ],
  "paths": {
    "/api/v2/catalogar-incidencia": {
      "post": {
        "operationId": "catalogarIncidenciaV2",
        "summary": "Catalogar incidencia (v2 con vector semántico)",
        "description": "Devuelve categoría más probable, confianza, revisión humana, evaluación operativa v1 (o null), actuaciones derivadas, alternativas y campos de augmentación vectorial.",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "text"
                ],
                "properties": {
                  "text": {
                    "type": "string",
                    "description": "Texto libre de la incidencia.",
                    "minLength": 3,
                    "maxLength": 2000
                  },
                  "minConfidence": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 1,
                    "default": 0.55
                  },
                  "maxAlternatives": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 5,
                    "default": 3
                  },
                  "originalText": {
                    "type": "string",
                    "description": "Mensaje original del usuario, para trazabilidad. No se usa en la clasificacion.",
                    "maxLength": 4000
                  }
                },
                "example": {
                  "text": "cae agua en el patio",
                  "minConfidence": 0.55,
                  "maxAlternatives": 3,
                  "originalText": "Buenos dias, me cae agua del techo y el ascensor tampoco funciona."
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Clasificación realizada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CatalogacionSuccessV2"
                },
                "example": {
                  "ok": true,
                  "apiVersion": "2",
                  "input": "cae agua en el patio",
                  "bestNodeId": "01.02.01.04.01",
                  "bestNodeName": "Fuga en tramo claramente común (patio, garaje, cuarto)",
                  "ruta": "Incidencias técnicas y de mantenimiento > Instalaciones de agua > Agua fría sanitaria (AFS) > Fugas y humedades AFS > Fuga en tramo claramente común (patio, garaje, cuarto)",
                  "confidence": 0.5108,
                  "appliedMinConfidence": 0.55,
                  "reviewRequired": true,
                  "coherenceAdjustments": [],
                  "coherenceRules": "v1",
                  "evaluacionOperativa": null,
                  "actuacionesDerivadas": [],
                  "alternatives": [],
                  "vectorAugmented": true,
                  "semanticMatches": [
                    {
                      "nodeId": "01.02.01.04.01",
                      "similarity": 0.91
                    }
                  ],
                  "fmStandardRefs": {
                    "iso41001": {
                      "section": "8.3",
                      "type": "hard_fm"
                    },
                    "gefma100": {
                      "code": "310",
                      "domain": "Instandhalten"
                    },
                    "din_en13306": {
                      "failure": "potential",
                      "intervention": "deferred"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Solicitud inválida",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "ok": false,
                  "error": {
                    "code": "BAD_REQUEST",
                    "message": "El campo `text` es obligatorio."
                  }
                }
              }
            }
          },
          "401": {
            "description": "No autorizado",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "ok": false,
                  "error": {
                    "code": "UNAUTHORIZED",
                    "message": "No autorizado."
                  }
                }
              }
            }
          },
          "429": {
            "description": "Demasiadas peticiones",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "ok": false,
                  "error": {
                    "code": "RATE_LIMITED",
                    "message": "Demasiadas peticiones. Intenta de nuevo en unos segundos."
                  }
                }
              }
            }
          },
          "500": {
            "description": "Error interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "ok": false,
                  "error": {
                    "code": "INTERNAL_ERROR",
                    "message": "Error interno."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v2/taxonomia-plan-cuentas": {
      "get": {
        "operationId": "taxonomiaPlanCuentasV2",
        "summary": "Obtener taxonomía como plan de cuentas",
        "description": "Devuelve la estructura jerárquica de la taxonomía en formato plan contable (código + nombre + jerarquía), excluyendo bloques de IA (`ai`, `signals`, `examples`, `disambiguation`).",
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Árbol de taxonomía obtenido",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaxonomiaPlanCuentasResponse"
                },
                "example": {
                  "ok": true,
                  "apiVersion": "2",
                  "formato": "plan-cuentas",
                  "excludes": [
                    "ai",
                    "signals",
                    "examples",
                    "disambiguation"
                  ],
                  "totalCuentas": 3,
                  "arbol": [
                    {
                      "codigo": "01",
                      "nombre": "Incidencias técnicas y de mantenimiento",
                      "nivel": 1,
                      "ruta": "Incidencias técnicas y de mantenimiento",
                      "esHoja": false,
                      "hijos": [
                        {
                          "codigo": "1.1",
                          "nombre": "Estructura y envolvente",
                          "nivel": 2,
                          "ruta": "Incidencias técnicas y de mantenimiento > Estructura y envolvente",
                          "esHoja": false,
                          "hijos": []
                        }
                      ]
                    }
                  ],
                  "listado": [
                    {
                      "codigo": "01",
                      "nombre": "Incidencias técnicas y de mantenimiento",
                      "nivel": 1,
                      "ruta": "Incidencias técnicas y de mantenimiento",
                      "esHoja": false,
                      "hijos": []
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "No autorizado",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "ok": false,
                  "error": {
                    "code": "UNAUTHORIZED",
                    "message": "No autorizado."
                  }
                }
              }
            }
          },
          "500": {
            "description": "Error interno",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "ok": false,
                  "error": {
                    "code": "INTERNAL_ERROR",
                    "message": "Error interno."
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "CuentaNode": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "codigo",
          "nombre",
          "nivel",
          "ruta",
          "esHoja",
          "hijos"
        ],
        "properties": {
          "codigo": {
            "type": "string"
          },
          "nombre": {
            "type": "string"
          },
          "nivel": {
            "type": "integer",
            "minimum": 1
          },
          "ruta": {
            "type": "string"
          },
          "esHoja": {
            "type": "boolean"
          },
          "hijos": {
            "type": "array",
            "description": "Hijos inmediatos en formato resumido. Se evita recursividad OpenAPI para maximizar compatibilidad con parsers de Actions/GPT.",
            "items": {
              "$ref": "#/components/schemas/CuentaNodeShallow"
            }
          }
        }
      },
      "CuentaNodeShallow": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "codigo",
          "nombre",
          "nivel",
          "ruta",
          "esHoja"
        ],
        "properties": {
          "codigo": {
            "type": "string"
          },
          "nombre": {
            "type": "string"
          },
          "nivel": {
            "type": "integer",
            "minimum": 1
          },
          "ruta": {
            "type": "string"
          },
          "esHoja": {
            "type": "boolean"
          },
          "hijos": {
            "type": "array",
            "description": "Opcional. Si existe, su estructura no se expande en el schema GPT para evitar referencias circulares.",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          }
        }
      },
      "TaxonomiaPlanCuentasResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "ok",
          "apiVersion",
          "formato",
          "excludes",
          "totalCuentas",
          "arbol",
          "listado"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "apiVersion": {
            "type": "string",
            "enum": [
              "2"
            ]
          },
          "formato": {
            "type": "string",
            "enum": [
              "plan-cuentas"
            ]
          },
          "excludes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "totalCuentas": {
            "type": "integer",
            "minimum": 0
          },
          "arbol": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CuentaNode"
            }
          },
          "listado": {
            "type": "array",
            "description": "Vista plana del árbol para consumo tipo catálogo contable.",
            "items": {
              "$ref": "#/components/schemas/CuentaNode"
            }
          }
        }
      },
      "CoherenceAdjustment": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "ruleId",
          "fromNodeId",
          "toNodeId",
          "reason"
        ],
        "properties": {
          "ruleId": {
            "type": "string"
          },
          "fromNodeId": {
            "type": "string"
          },
          "toNodeId": {
            "type": "string"
          },
          "reason": {
            "type": "string"
          }
        }
      },
      "EvaluacionOperativaV1": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "version",
          "riesgoOperativo",
          "impactoServicio",
          "criticidadActivo",
          "tipoActuacion",
          "prioridadSugerida",
          "resumenCriterio"
        ],
        "properties": {
          "version": {
            "type": "string",
            "enum": [
              "v1"
            ]
          },
          "riesgoOperativo": {
            "type": "string",
            "enum": [
              "Bajo",
              "Medio",
              "Alto"
            ]
          },
          "impactoServicio": {
            "type": "string",
            "enum": [
              "Bajo",
              "Medio",
              "Alto"
            ]
          },
          "criticidadActivo": {
            "type": "string",
            "enum": [
              "Baja",
              "Media",
              "Alta"
            ]
          },
          "tipoActuacion": {
            "type": "string",
            "enum": [
              "Correctiva",
              "Preventiva",
              "Correctiva y preventiva"
            ]
          },
          "prioridadSugerida": {
            "type": "string",
            "enum": [
              "Baja",
              "Media",
              "Alta"
            ]
          },
          "resumenCriterio": {
            "type": "string"
          }
        }
      },
      "SemanticMatch": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "nodeId",
          "similarity"
        ],
        "properties": {
          "nodeId": {
            "type": "string",
            "description": "ID del nodo de la taxonomía que resultó similar semánticamente."
          },
          "similarity": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "Similitud coseno [0,1]. 1 = idéntico."
          }
        }
      },
      "CatalogacionSuccessV2": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "ok",
          "apiVersion",
          "input",
          "bestNodeId",
          "bestNodeName",
          "ruta",
          "confidence",
          "appliedMinConfidence",
          "reviewRequired",
          "evaluacionOperativa",
          "coherenceAdjustments",
          "coherenceRules",
          "actuacionesDerivadas",
          "alternatives",
          "vectorAugmented",
          "semanticMatches"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "apiVersion": {
            "type": "string",
            "enum": [
              "2"
            ]
          },
          "input": {
            "type": "string"
          },
          "bestNodeId": {
            "type": [
              "string",
              "null"
            ]
          },
          "bestNodeName": {
            "type": [
              "string",
              "null"
            ]
          },
          "ruta": {
            "type": [
              "string",
              "null"
            ]
          },
          "confidence": {
            "type": "number",
            "minimum": 0,
            "maximum": 1
          },
          "appliedMinConfidence": {
            "type": "number",
            "minimum": 0,
            "maximum": 1
          },
          "reviewRequired": {
            "type": "boolean"
          },
          "evaluacionOperativa": {
            "description": "Triaje operativo derivado del nodo y riesgos R.xx. Null si no hay nodo clasificado.",
            "anyOf": [
              {
                "$ref": "#/components/schemas/EvaluacionOperativaV1"
              },
              {
                "type": "null"
              }
            ]
          },
          "coherenceAdjustments": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CoherenceAdjustment"
            }
          },
          "coherenceRules": {
            "type": [
              "string",
              "null"
            ]
          },
          "actuacionesDerivadas": {
            "type": "array",
            "minItems": 0,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "id",
                "nombre",
                "descripcion"
              ],
              "properties": {
                "id": {
                  "type": "string"
                },
                "nombre": {
                  "type": "string"
                },
                "descripcion": {
                  "type": "string"
                }
              }
            }
          },
          "alternatives": {
            "type": "array",
            "minItems": 0,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "nodeId",
                "nodeName",
                "confidence"
              ],
              "properties": {
                "nodeId": {
                  "type": "string"
                },
                "nodeName": {
                  "type": "string"
                },
                "confidence": {
                  "type": "number",
                  "minimum": 0,
                  "maximum": 1
                }
              }
            }
          },
          "vectorAugmented": {
            "type": "boolean",
            "description": "true si la clasificación fue mejorada con búsqueda vectorial semántica (requiere DB + Ollama configurados)."
          },
          "semanticMatches": {
            "type": "array",
            "description": "Nodos encontrados por similitud semántica que contribuyeron al scoring.",
            "items": {
              "$ref": "#/components/schemas/SemanticMatch"
            }
          },
          "fmStandardRefs": {
            "description": "Alineación con estándares FM internacionales (ISO 41001, GEFMA 100, DIN EN 13306). Null si el nodo no está clasificado. din_en13306 solo para nodos hard/mixto en familias técnicas.",
            "anyOf": [
              {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "iso41001": {
                    "type": "object",
                    "properties": {
                      "section": {
                        "type": "string"
                      },
                      "type": {
                        "type": "string"
                      }
                    }
                  },
                  "gefma100": {
                    "type": "object",
                    "properties": {
                      "code": {
                        "type": "string"
                      },
                      "domain": {
                        "type": "string"
                      }
                    }
                  },
                  "din_en13306": {
                    "type": "object",
                    "properties": {
                      "failure": {
                        "type": "string",
                        "enum": [
                          "functional",
                          "potential"
                        ]
                      },
                      "intervention": {
                        "type": "string",
                        "enum": [
                          "immediate",
                          "urgent",
                          "deferred",
                          "planned"
                        ]
                      }
                    }
                  }
                }
              },
              {
                "type": "null"
              }
            ]
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "ok",
          "error"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "enum": [
              false
            ]
          },
          "error": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "BAD_REQUEST",
                  "UNAUTHORIZED",
                  "RATE_LIMITED",
                  "INTERNAL_ERROR"
                ]
              },
              "message": {
                "type": "string"
              }
            }
          }
        }
      }
    },
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key"
      }
    }
  }
}
