{
  "openapi": "3.1.0",
  "info": {
    "title": "AidVenezuela Public API",
    "version": "1.0.0",
    "description": "Contrato público de la plataforma AidVenezuela. Algunos endpoints requieren `Authorization: Bearer <token>` emitido por Cognito.\n\n**Base URL producción:** `https://api.aidvenezuela.help`\n\n- Endpoints `public`: lectura libre, CORS abierto.\n- Endpoints `bearer`: requieren JWT Cognito.\n- Endpoints `internal`: solo apps federadas con acuerdo de datos.\n- `GET /api/v1/eoc/analytics` está gated por `VITE_EOC_ANALYTICS_ENABLED`. Cuando está apagado devuelve `503 Service Unavailable` con `Retry-After`."
  },
  "servers": [
    { "url": "https://api.aidvenezuela.help", "description": "Producción" }
  ],
  "tags": [
    { "name": "denuncias", "description": "Denuncias ciudadanas" },
    { "name": "estructuras", "description": "Reportes estructurales" },
    { "name": "alerts", "description": "Alertas operativas" },
    { "name": "incidents", "description": "Incidentes y casos" },
    { "name": "eoc", "description": "Dashboards y mapa unificado" },
    { "name": "voluntarios", "description": "Registro de voluntarios" },
    { "name": "recursos", "description": "Recursos y refugios" },
    { "name": "internal", "description": "APIs federadas / internas" }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "Token Cognito (`id_token` o `access_token`). Scopes por rol vía claim `cognito:groups`."
      }
    },
    "schemas": {
      "GeoPoint": {
        "type": "object",
        "required": ["lat", "lng"],
        "properties": {
          "lat": { "type": "number", "format": "double" },
          "lng": { "type": "number", "format": "double" }
        }
      },
      "Denuncia": {
        "type": "object",
        "required": ["categoria", "descripcion"],
        "properties": {
          "id": { "type": "string", "readOnly": true },
          "categoria": { "type": "string", "enum": ["corrupcion", "ddhh", "servicios", "seguridad", "otra"] },
          "descripcion": { "type": "string", "minLength": 30, "maxLength": 4000 },
          "estado": { "type": "string" },
          "municipio": { "type": "string" },
          "parroquia": { "type": "string" },
          "anonimo": { "type": "boolean", "default": true },
          "evidenciaUrls": { "type": "array", "items": { "type": "string", "format": "uri" } },
          "createdAt": { "type": "string", "format": "date-time", "readOnly": true }
        }
      },
      "StructuralReport": {
        "type": "object",
        "required": ["geo", "severidad"],
        "properties": {
          "id": { "type": "string", "readOnly": true },
          "geo": { "$ref": "#/components/schemas/GeoPoint" },
          "severidad": { "type": "string", "enum": ["leve", "moderado", "grave", "colapso"] },
          "descripcion": { "type": "string" },
          "fotos": { "type": "array", "items": { "type": "string", "format": "uri" } }
        }
      },
      "Alert": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "tipo": { "type": "string" },
          "severidad": { "type": "string", "enum": ["info", "warning", "critical"] },
          "titulo": { "type": "string" },
          "mensaje": { "type": "string" },
          "geo": { "$ref": "#/components/schemas/GeoPoint" },
          "createdAt": { "type": "string", "format": "date-time" }
        }
      },
      "Incident": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "titulo": { "type": "string" },
          "prioridad": { "type": "string", "enum": ["low", "med", "high", "critical"] },
          "estado": { "type": "string", "enum": ["open", "in_progress", "resolved", "closed"] },
          "responsable": { "type": "string" },
          "geo": { "$ref": "#/components/schemas/GeoPoint" }
        }
      },
      "DashboardKpis": {
        "type": "object",
        "properties": {
          "denuncias24h": { "type": "integer" },
          "alertasActivas": { "type": "integer" },
          "voluntariosOnline": { "type": "integer" },
          "refugiosOcupacionPct": { "type": "number" }
        }
      },
      "MapFeatureCollection": {
        "type": "object",
        "properties": {
          "type": { "type": "string", "const": "FeatureCollection" },
          "features": { "type": "array", "items": { "type": "object" } }
        }
      },
      "Voluntario": {
        "type": "object",
        "required": ["nombre", "email", "profesion"],
        "properties": {
          "id": { "type": "string", "readOnly": true },
          "nombre": { "type": "string" },
          "email": { "type": "string", "format": "email" },
          "telefono": { "type": "string" },
          "profesion": { "type": "string" },
          "geo": { "$ref": "#/components/schemas/GeoPoint" },
          "disponibilidad": { "type": "string", "enum": ["inmediata", "guardia", "ocasional"] }
        }
      },
      "Resource": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "tipo": { "type": "string", "enum": ["agua", "medicinas", "alimentos", "equipos"] },
          "cantidad": { "type": "number" },
          "unidad": { "type": "string" },
          "ubicacion": { "type": "string" }
        }
      },
      "Shelter": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "nombre": { "type": "string" },
          "capacidad": { "type": "integer" },
          "ocupacion": { "type": "integer" },
          "contacto": { "type": "string" },
          "geo": { "$ref": "#/components/schemas/GeoPoint" }
        }
      },
      "Familia": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "responsable": { "type": "string" },
          "miembros": { "type": "integer" },
          "sector": { "type": "string" },
          "estado": { "type": "string", "enum": ["nuevo", "en_seguimiento", "atendido", "archivado"] },
          "geo": { "$ref": "#/components/schemas/GeoPoint" }
        }
      },
      "AuditEntry": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "actor": { "type": "string" },
          "accion": { "type": "string" },
          "recurso": { "type": "string" },
          "hash": { "type": "string" },
          "prevHash": { "type": "string" },
          "at": { "type": "string", "format": "date-time" }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "code": { "type": "string" },
          "message": { "type": "string" }
        }
      }
    }
  },
  "paths": {
    "/api/v1/denuncias": {
      "post": {
        "operationId": "post-denuncias",
        "tags": ["denuncias"],
        "summary": "Crear denuncia ciudadana",
        "description": "Recibe denuncias anónimas o atribuidas con evidencia subida vía S3 presigned URL.",
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Denuncia" } } }
        },
        "responses": {
          "201": { "description": "Creada", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Denuncia" } } } },
          "400": { "description": "Validación fallida", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/api/v1/structural-reports": {
      "post": {
        "operationId": "post-structural-reports",
        "tags": ["estructuras"],
        "summary": "Reportar daño estructural",
        "security": [{ "bearerAuth": [] }],
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/StructuralReport" } } }
        },
        "responses": {
          "201": { "description": "Creado", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/StructuralReport" } } } },
          "401": { "description": "No autenticado" }
        }
      }
    },
    "/api/v1/alerts": {
      "get": {
        "operationId": "get-alerts",
        "tags": ["alerts"],
        "summary": "Listar alertas activas",
        "parameters": [
          { "name": "severidad", "in": "query", "schema": { "type": "string", "enum": ["info", "warning", "critical"] } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 50, "maximum": 200 } }
        ],
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Alert" } } } } }
        }
      }
    },
    "/api/v1/incidents": {
      "get": {
        "operationId": "get-incidents",
        "tags": ["incidents"],
        "summary": "Listar incidentes",
        "security": [{ "bearerAuth": [] }],
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Incident" } } } } },
          "401": { "description": "No autenticado" }
        }
      }
    },
    "/api/v1/incidents/{id}": {
      "patch": {
        "operationId": "patch-incidents",
        "tags": ["internal", "incidents"],
        "summary": "Mutar estado/prioridad/responsable",
        "security": [{ "bearerAuth": [] }],
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Incident" } } }
        },
        "responses": {
          "200": { "description": "Actualizado", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Incident" } } } },
          "403": { "description": "Sin permisos" }
        }
      }
    },
    "/api/v1/eoc/dashboard": {
      "get": {
        "operationId": "get-eoc-dashboard",
        "tags": ["eoc"],
        "summary": "KPIs agregados",
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DashboardKpis" } } } }
        }
      }
    },
    "/api/v1/eoc/map": {
      "get": {
        "operationId": "get-eoc-map",
        "tags": ["eoc"],
        "summary": "Capa de mapa unificada (GeoJSON)",
        "responses": {
          "200": { "description": "OK", "content": { "application/geo+json": { "schema": { "$ref": "#/components/schemas/MapFeatureCollection" } } } }
        }
      }
    },
    "/api/v1/eoc/analytics": {
      "get": {
        "operationId": "get-eoc-analytics",
        "tags": ["eoc"],
        "summary": "Analítica histórica (planned)",
        "description": "Gated por `VITE_EOC_ANALYTICS_ENABLED`. Cuando está apagado devuelve 503 con `Retry-After`.",
        "security": [{ "bearerAuth": [] }],
        "responses": {
          "200": { "description": "OK" },
          "503": { "description": "Endpoint deshabilitado", "headers": { "Retry-After": { "schema": { "type": "string" } } } }
        }
      }
    },
    "/api/v1/voluntarios": {
      "post": {
        "operationId": "post-voluntarios",
        "tags": ["voluntarios"],
        "summary": "Registrar voluntario",
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Voluntario" } } }
        },
        "responses": {
          "201": { "description": "Creado", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Voluntario" } } } }
        }
      }
    },
    "/api/v1/resources": {
      "get": {
        "operationId": "get-resources",
        "tags": ["recursos"],
        "summary": "Listar recursos disponibles",
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Resource" } } } } }
        }
      }
    },
    "/api/v1/shelters": {
      "get": {
        "operationId": "get-shelters",
        "tags": ["recursos"],
        "summary": "Listar refugios y acopio",
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Shelter" } } } } }
        }
      }
    },
    "/api/v1/eoc/familias": {
      "get": {
        "operationId": "get-eoc-familias",
        "tags": ["internal"],
        "summary": "Listar familias / casos (offline-first)",
        "security": [{ "bearerAuth": [] }],
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Familia" } } } } },
          "401": { "description": "No autenticado" },
          "409": { "description": "Conflicto de sincronización" }
        }
      }
    },
    "/api/v1/audit": {
      "get": {
        "operationId": "get-audit",
        "tags": ["internal"],
        "summary": "Bitácora de auditoría (append-only)",
        "security": [{ "bearerAuth": [] }],
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/AuditEntry" } } } } }
        }
      }
    },
    "/api/v1/admin/rate-limits": {
      "post": {
        "operationId": "post-admin-rate-limits",
        "tags": ["internal"],
        "summary": "Configurar cuotas por tenant",
        "security": [{ "bearerAuth": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "tenant": { "type": "string" },
                  "requestsPerMinute": { "type": "integer", "minimum": 1 },
                  "burst": { "type": "integer", "minimum": 1 }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Actualizado" },
          "403": { "description": "Sólo admin" }
        }
      }
    }
  }
}
