{
  "openapi": "3.1.0",
  "info": {
    "title": "Ganado Pro API - superficie publica",
    "version": "2026-09-16",
    "summary": "Endpoints de la API de Ganado Pro accesibles sin sesion iniciada.",
    "description": "Este documento describe unicamente la superficie **publica** de la API de Ganado Pro: autenticacion, restablecimiento de contrasena y estado del servicio. El resto de la API (animales, fincas, potreros, lotes, eventos, producciones lecheras, registros de pesaje, usuarios, notificaciones y pagos) requiere un token valido y no se documenta aqui porque no es de acceso publico. Para el procedimiento de autenticacion de agentes, ver https://ganadopro.site/auth.md",
    "contact": {
      "name": "Ganado Pro",
      "url": "https://ganadopro.site"
    }
  },
  "servers": [
    {
      "url": "https://api.ganadopro.site/Api",
      "description": "Produccion"
    },
    {
      "url": "https://api-test.ganadopro.site/Api",
      "description": "Entorno de pruebas"
    }
  ],
  "tags": [
    { "name": "auth", "description": "Autenticacion" },
    { "name": "password-reset", "description": "Restablecimiento de contrasena" },
    { "name": "operations", "description": "Estado del servicio" }
  ],
  "paths": {
    "/login": {
      "post": {
        "tags": ["auth"],
        "operationId": "login",
        "summary": "Autentica un usuario y devuelve un token de acceso",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/LoginRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Credenciales validas. La respuesta incluye el token que debe enviarse en la cabecera Authorization de las peticiones autenticadas.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/LoginResponse" }
              }
            }
          },
          "401": { "description": "Credenciales invalidas" }
        },
        "security": []
      }
    },
    "/login/validate-token": {
      "get": {
        "tags": ["auth"],
        "operationId": "validateToken",
        "summary": "Comprueba si el token de la cabecera Authorization sigue siendo valido",
        "responses": {
          "200": { "description": "El token es valido" },
          "400": { "description": "Falta la cabecera Authorization o el token esta mal formado" },
          "401": { "description": "El token es invalido o ha expirado" }
        },
        "security": [{ "accountToken": [] }]
      }
    },
    "/password-reset/request": {
      "post": {
        "tags": ["password-reset"],
        "operationId": "requestPasswordReset",
        "summary": "Envia por correo un token de restablecimiento de contrasena",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["email"],
                "properties": {
                  "email": { "type": "string", "format": "email" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Solicitud aceptada" }
        },
        "security": []
      }
    },
    "/password-reset/validate": {
      "get": {
        "tags": ["password-reset"],
        "operationId": "validatePasswordResetToken",
        "summary": "Valida un token de restablecimiento antes de mostrar el formulario",
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": { "description": "El token es valido" },
          "400": { "description": "El token es invalido o ha expirado" }
        },
        "security": []
      }
    },
    "/password-reset/confirm": {
      "post": {
        "tags": ["password-reset"],
        "operationId": "confirmPasswordReset",
        "summary": "Fija una nueva contrasena usando un token de restablecimiento",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["token", "newPassword"],
                "properties": {
                  "token": { "type": "string" },
                  "newPassword": { "type": "string", "format": "password" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Contrasena actualizada" },
          "400": { "description": "Token invalido o contrasena no valida" }
        },
        "security": []
      }
    },
    "/actuator/health": {
      "get": {
        "tags": ["operations"],
        "operationId": "health",
        "summary": "Estado del servicio",
        "responses": {
          "200": {
            "description": "Servicio operativo",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": { "type": "string", "examples": ["UP"] }
                  }
                }
              }
            }
          }
        },
        "security": []
      }
    }
  },
  "components": {
    "securitySchemes": {
      "accountToken": {
        "type": "apiKey",
        "in": "header",
        "name": "Authorization",
        "description": "Token devuelto por POST /login. Se envia tal cual en la cabecera Authorization, sin el prefijo 'Bearer '."
      }
    },
    "schemas": {
      "LoginRequest": {
        "type": "object",
        "required": ["email", "password"],
        "properties": {
          "email": { "type": "string", "format": "email" },
          "password": { "type": "string", "format": "password" }
        }
      },
      "LoginResponse": {
        "type": "object",
        "properties": {
          "token": {
            "type": "string",
            "description": "Token de acceso para la cabecera Authorization"
          }
        }
      }
    }
  },
  "security": [{ "accountToken": [] }]
}
