- Add static OpenAPI 3.0.3 spec (services/backend-api/static/openapi.yaml) covering all ~70 endpoints with schemas, security, tags and responses - Serve Swagger UI at GET /docs (embedded HTML, dark OmniOil theme) - Serve raw YAML at GET /docs/openapi.yaml (include_str! at compile time) - Add Tower middleware (api_version.rs) injecting X-API-Version: 1 and X-Powered-By: OmniOil/1.0 on every response - Replace static /health handler with enhanced health_check that probes DB latency, tracks uptime via OnceLock, returns structured HealthResponse - Expand API Explorer frontend: 70+ endpoints in 10 groups, PATCH color coding (purple), group filter pills, count badge, Swagger UI links Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2390 lines
63 KiB
YAML
2390 lines
63 KiB
YAML
openapi: 3.0.3
|
|
info:
|
|
title: OmniOil SCADA API
|
|
description: |
|
|
API de la plataforma OmniOil para telemetría IoT/SCADA en el sector de hidrocarburos.
|
|
Cumple con la Resolución 0651 de la ANH (Agencia Nacional de Hidrocarburos, Colombia).
|
|
|
|
## Autenticación
|
|
La mayoría de endpoints requieren un Bearer JWT token en el header `Authorization`.
|
|
Obtén tu token con `POST /api/auth/login`.
|
|
|
|
## Versionado
|
|
La API actual es la versión 1. Todos los endpoints incluyen el header `X-API-Version: 1` en las respuestas.
|
|
|
|
## Cumplimiento ANH
|
|
Los endpoints de telemetría e informes cumplen con la normativa colombiana de
|
|
reporte de producción de hidrocarburos (Resolución ANH 0651).
|
|
version: "1.0.0"
|
|
contact:
|
|
name: OmniOil Support
|
|
email: soporte@omnioil.app
|
|
license:
|
|
name: Propietario
|
|
|
|
servers:
|
|
- url: /api
|
|
description: API Server (via proxy)
|
|
- url: http://localhost:8000/api
|
|
description: Desarrollo local
|
|
|
|
components:
|
|
securitySchemes:
|
|
BearerAuth:
|
|
type: http
|
|
scheme: bearer
|
|
bearerFormat: JWT
|
|
|
|
schemas:
|
|
LoginRequest:
|
|
type: object
|
|
required: [email, password]
|
|
properties:
|
|
email:
|
|
type: string
|
|
format: email
|
|
example: admin@omnioil.app
|
|
password:
|
|
type: string
|
|
format: password
|
|
example: "••••••••"
|
|
|
|
LoginResponse:
|
|
type: object
|
|
properties:
|
|
token:
|
|
type: string
|
|
description: JWT access token
|
|
role:
|
|
type: string
|
|
enum: [superadmin, admin, supervisor, operador, anh_reader]
|
|
projects:
|
|
type: array
|
|
items:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
name:
|
|
type: string
|
|
|
|
User:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
email:
|
|
type: string
|
|
format: email
|
|
name:
|
|
type: string
|
|
role:
|
|
type: string
|
|
enum: [superadmin, admin, supervisor, operador, anh_reader]
|
|
is_active:
|
|
type: boolean
|
|
projects:
|
|
type: array
|
|
items:
|
|
type: string
|
|
format: uuid
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
|
|
CreateUserRequest:
|
|
type: object
|
|
required: [email, name, role, password]
|
|
properties:
|
|
email:
|
|
type: string
|
|
format: email
|
|
name:
|
|
type: string
|
|
role:
|
|
type: string
|
|
enum: [superadmin, admin, supervisor, operador, anh_reader]
|
|
password:
|
|
type: string
|
|
minLength: 8
|
|
|
|
EdgeProject:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
name:
|
|
type: string
|
|
description:
|
|
type: string
|
|
location:
|
|
type: string
|
|
is_active:
|
|
type: boolean
|
|
last_health_report:
|
|
type: object
|
|
nullable: true
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
|
|
CreateProjectRequest:
|
|
type: object
|
|
required: [name]
|
|
properties:
|
|
name:
|
|
type: string
|
|
example: "Campo Norte - Pozo 01"
|
|
description:
|
|
type: string
|
|
location:
|
|
type: string
|
|
|
|
EdgeAsset:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
project_id:
|
|
type: string
|
|
format: uuid
|
|
name:
|
|
type: string
|
|
asset_type:
|
|
type: string
|
|
enum: [well, tank, pipeline, station, meter]
|
|
latitude:
|
|
type: number
|
|
format: double
|
|
nullable: true
|
|
longitude:
|
|
type: number
|
|
format: double
|
|
nullable: true
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
|
|
CreateAssetRequest:
|
|
type: object
|
|
required: [project_id, name, asset_type]
|
|
properties:
|
|
project_id:
|
|
type: string
|
|
format: uuid
|
|
name:
|
|
type: string
|
|
example: "Pozo P-01"
|
|
asset_type:
|
|
type: string
|
|
enum: [well, tank, pipeline, station, meter]
|
|
latitude:
|
|
type: number
|
|
format: double
|
|
longitude:
|
|
type: number
|
|
format: double
|
|
|
|
EdgeDevice:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
asset_id:
|
|
type: string
|
|
format: uuid
|
|
name:
|
|
type: string
|
|
protocol:
|
|
type: string
|
|
enum: [modbus_tcp, modbus_rtu, opc_ua, s7, dnp3]
|
|
host:
|
|
type: string
|
|
nullable: true
|
|
port:
|
|
type: integer
|
|
nullable: true
|
|
slave_id:
|
|
type: integer
|
|
nullable: true
|
|
enabled:
|
|
type: boolean
|
|
|
|
CreateDeviceRequest:
|
|
type: object
|
|
required: [name, protocol]
|
|
properties:
|
|
name:
|
|
type: string
|
|
protocol:
|
|
type: string
|
|
enum: [modbus_tcp, modbus_rtu, opc_ua, s7, dnp3]
|
|
host:
|
|
type: string
|
|
port:
|
|
type: integer
|
|
slave_id:
|
|
type: integer
|
|
enabled:
|
|
type: boolean
|
|
default: true
|
|
|
|
EdgeVariable:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
device_id:
|
|
type: string
|
|
format: uuid
|
|
alias:
|
|
type: string
|
|
data_type:
|
|
type: string
|
|
enum: [float, int, bool, string]
|
|
register_address:
|
|
type: integer
|
|
nullable: true
|
|
unit:
|
|
type: string
|
|
nullable: true
|
|
scale_factor:
|
|
type: number
|
|
nullable: true
|
|
enabled:
|
|
type: boolean
|
|
|
|
CreateVariableRequest:
|
|
type: object
|
|
required: [alias, data_type]
|
|
properties:
|
|
alias:
|
|
type: string
|
|
example: "temperatura_cabezal"
|
|
data_type:
|
|
type: string
|
|
enum: [float, int, bool, string]
|
|
register_address:
|
|
type: integer
|
|
unit:
|
|
type: string
|
|
example: "°C"
|
|
scale_factor:
|
|
type: number
|
|
enabled:
|
|
type: boolean
|
|
default: true
|
|
|
|
TelemetryPayload:
|
|
type: object
|
|
required: [asset_id, readings]
|
|
properties:
|
|
asset_id:
|
|
type: string
|
|
format: uuid
|
|
timestamp:
|
|
type: string
|
|
format: date-time
|
|
readings:
|
|
type: array
|
|
items:
|
|
type: object
|
|
required: [variable, value]
|
|
properties:
|
|
variable:
|
|
type: string
|
|
example: "presion_cabezal"
|
|
value:
|
|
type: number
|
|
unit:
|
|
type: string
|
|
|
|
AlarmEvent:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
project_id:
|
|
type: string
|
|
format: uuid
|
|
asset_id:
|
|
type: string
|
|
format: uuid
|
|
nullable: true
|
|
variable:
|
|
type: string
|
|
value:
|
|
type: number
|
|
alarm_type:
|
|
type: string
|
|
enum: [high, low, critical_high, critical_low, comm_loss]
|
|
message:
|
|
type: string
|
|
acknowledged:
|
|
type: boolean
|
|
timestamp:
|
|
type: string
|
|
format: date-time
|
|
|
|
AlertRule:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
project_id:
|
|
type: string
|
|
format: uuid
|
|
name:
|
|
type: string
|
|
variable_alias:
|
|
type: string
|
|
condition:
|
|
type: string
|
|
enum: [gt, lt, gte, lte, eq]
|
|
threshold:
|
|
type: number
|
|
severity:
|
|
type: string
|
|
enum: [info, warning, critical]
|
|
is_enabled:
|
|
type: boolean
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
|
|
CreateAlertRuleRequest:
|
|
type: object
|
|
required: [project_id, name, variable_alias, condition, threshold, severity]
|
|
properties:
|
|
project_id:
|
|
type: string
|
|
format: uuid
|
|
name:
|
|
type: string
|
|
variable_alias:
|
|
type: string
|
|
example: "presion_cabezal"
|
|
condition:
|
|
type: string
|
|
enum: [gt, lt, gte, lte, eq]
|
|
threshold:
|
|
type: number
|
|
example: 150.0
|
|
severity:
|
|
type: string
|
|
enum: [info, warning, critical]
|
|
|
|
BillingUsage:
|
|
type: object
|
|
properties:
|
|
project_id:
|
|
type: string
|
|
format: uuid
|
|
period_start:
|
|
type: string
|
|
format: date-time
|
|
period_end:
|
|
type: string
|
|
format: date-time
|
|
telemetry_points:
|
|
type: integer
|
|
active_devices:
|
|
type: integer
|
|
plan:
|
|
type: string
|
|
enum: [starter, professional, enterprise]
|
|
estimated_cost_usd:
|
|
type: number
|
|
format: double
|
|
|
|
Invoice:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
project_id:
|
|
type: string
|
|
format: uuid
|
|
period:
|
|
type: string
|
|
example: "2024-01"
|
|
amount_usd:
|
|
type: number
|
|
format: double
|
|
status:
|
|
type: string
|
|
enum: [pending, paid, overdue, cancelled]
|
|
issued_at:
|
|
type: string
|
|
format: date-time
|
|
paid_at:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
|
|
ANHReport:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
project_id:
|
|
type: string
|
|
format: uuid
|
|
report_date:
|
|
type: string
|
|
format: date
|
|
period_start:
|
|
type: string
|
|
format: date-time
|
|
period_end:
|
|
type: string
|
|
format: date-time
|
|
status:
|
|
type: string
|
|
enum: [pending, generated, submitted]
|
|
hash_sha384:
|
|
type: string
|
|
nullable: true
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
|
|
HealthResponse:
|
|
type: object
|
|
properties:
|
|
status:
|
|
type: string
|
|
enum: [ok, degraded, error]
|
|
version:
|
|
type: string
|
|
example: "1.0.0"
|
|
timestamp:
|
|
type: string
|
|
format: date-time
|
|
uptime_seconds:
|
|
type: integer
|
|
services:
|
|
type: object
|
|
properties:
|
|
database:
|
|
$ref: '#/components/schemas/ServiceStatus'
|
|
api:
|
|
$ref: '#/components/schemas/ServiceStatus'
|
|
|
|
ServiceStatus:
|
|
type: object
|
|
properties:
|
|
status:
|
|
type: string
|
|
enum: [ok, error]
|
|
latency_ms:
|
|
type: integer
|
|
nullable: true
|
|
message:
|
|
type: string
|
|
nullable: true
|
|
|
|
ErrorResponse:
|
|
type: object
|
|
properties:
|
|
error:
|
|
type: string
|
|
example: "No autorizado"
|
|
|
|
security:
|
|
- BearerAuth: []
|
|
|
|
tags:
|
|
- name: Auth
|
|
description: Autenticación y gestión de sesiones
|
|
- name: Users
|
|
description: Gestión de usuarios (admin)
|
|
- name: Dashboard
|
|
description: Datos del dashboard principal
|
|
- name: Telemetry
|
|
description: Ingesta y consulta de telemetría
|
|
- name: ANH Reports
|
|
description: Reportes de cumplimiento ANH Resolución 0651
|
|
- name: Alerts
|
|
description: Reglas de alerta y alarmas activas
|
|
- name: Operations
|
|
description: Operaciones, pruebas y registros ANH 0651
|
|
- name: Billing
|
|
description: Facturación y suscripciones
|
|
- name: Edge Projects
|
|
description: Proyectos de telemetría edge
|
|
- name: Edge Assets
|
|
description: Activos (pozos, tanques, estaciones)
|
|
- name: Edge Devices
|
|
description: Dispositivos de campo (PLCs, RTUs, Modbus)
|
|
- name: Edge Variables
|
|
description: Variables y tags de los dispositivos
|
|
- name: System
|
|
description: Estado del sistema y métricas
|
|
|
|
paths:
|
|
|
|
# ── Auth ──────────────────────────────────────────────────────────────────
|
|
|
|
/auth/login:
|
|
post:
|
|
tags: [Auth]
|
|
summary: Iniciar sesión
|
|
security: []
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/LoginRequest'
|
|
responses:
|
|
'200':
|
|
description: Login exitoso
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/LoginResponse'
|
|
'401':
|
|
description: Credenciales inválidas
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
'429':
|
|
description: Demasiados intentos (rate limited)
|
|
|
|
/auth/register:
|
|
post:
|
|
tags: [Auth]
|
|
summary: Registrar nuevo usuario (deshabilitado en producción)
|
|
security: []
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/CreateUserRequest'
|
|
responses:
|
|
'201':
|
|
description: Usuario creado
|
|
'403':
|
|
description: Registro deshabilitado en producción
|
|
'429':
|
|
description: Rate limited
|
|
|
|
/auth/refresh:
|
|
post:
|
|
tags: [Auth]
|
|
summary: Renovar access token usando refresh token
|
|
security: []
|
|
responses:
|
|
'200':
|
|
description: Token renovado
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/LoginResponse'
|
|
'401':
|
|
description: Refresh token inválido o expirado
|
|
|
|
/auth/logout:
|
|
post:
|
|
tags: [Auth]
|
|
summary: Cerrar sesión e invalidar tokens
|
|
responses:
|
|
'200':
|
|
description: Sesión cerrada exitosamente
|
|
|
|
/auth/setup/status:
|
|
get:
|
|
tags: [Auth]
|
|
summary: Verificar si el sistema requiere configuración inicial
|
|
security: []
|
|
responses:
|
|
'200':
|
|
description: Estado de setup
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
requires_setup:
|
|
type: boolean
|
|
has_users:
|
|
type: boolean
|
|
|
|
/auth/setup/register:
|
|
post:
|
|
tags: [Auth]
|
|
summary: Crear primer administrador (solo cuando no hay usuarios)
|
|
security: []
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/CreateUserRequest'
|
|
responses:
|
|
'201':
|
|
description: Administrador inicial creado
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/LoginResponse'
|
|
'409':
|
|
description: El sistema ya fue configurado
|
|
|
|
# ── Users (Admin) ─────────────────────────────────────────────────────────
|
|
|
|
/admin/users:
|
|
get:
|
|
tags: [Users]
|
|
summary: Listar todos los usuarios del sistema
|
|
responses:
|
|
'200':
|
|
description: Lista de usuarios
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/User'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
post:
|
|
tags: [Users]
|
|
summary: Crear nuevo usuario
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/CreateUserRequest'
|
|
responses:
|
|
'201':
|
|
description: Usuario creado
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/User'
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
|
|
/admin/users/{id}:
|
|
get:
|
|
tags: [Users]
|
|
summary: Obtener usuario por ID
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
responses:
|
|
'200':
|
|
description: Datos del usuario
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/User'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
put:
|
|
tags: [Users]
|
|
summary: Actualizar datos de un usuario
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/CreateUserRequest'
|
|
responses:
|
|
'200':
|
|
description: Usuario actualizado
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/User'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
|
|
/admin/users/{id}/reset-password:
|
|
post:
|
|
tags: [Users]
|
|
summary: Resetear contraseña de un usuario
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [new_password]
|
|
properties:
|
|
new_password:
|
|
type: string
|
|
minLength: 8
|
|
responses:
|
|
'200':
|
|
description: Contraseña actualizada
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
|
|
/admin/users/{id}/projects:
|
|
put:
|
|
tags: [Users]
|
|
summary: Asignar proyectos edge al usuario
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [project_ids]
|
|
properties:
|
|
project_ids:
|
|
type: array
|
|
items:
|
|
type: string
|
|
format: uuid
|
|
responses:
|
|
'200':
|
|
description: Proyectos asignados
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
|
|
/admin/roles:
|
|
get:
|
|
tags: [Users]
|
|
summary: Listar roles disponibles en el sistema
|
|
responses:
|
|
'200':
|
|
description: Lista de roles
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: string
|
|
enum: [superadmin, admin, supervisor, operador, anh_reader]
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
|
|
# ── Dashboard ─────────────────────────────────────────────────────────────
|
|
|
|
/dashboard/summary:
|
|
get:
|
|
tags: [Dashboard]
|
|
summary: Resumen del dashboard con estadísticas del proyecto activo
|
|
responses:
|
|
'200':
|
|
description: Datos del dashboard
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
active_assets:
|
|
type: integer
|
|
total_alarms:
|
|
type: integer
|
|
recent_telemetry:
|
|
type: array
|
|
items:
|
|
type: object
|
|
compliance_status:
|
|
type: string
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
|
|
# ── Telemetry ─────────────────────────────────────────────────────────────
|
|
|
|
/telemetry:
|
|
post:
|
|
tags: [Telemetry]
|
|
summary: Enviar datos de telemetría desde campo hacia la plataforma
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/TelemetryPayload'
|
|
responses:
|
|
'201':
|
|
description: Telemetría ingresada correctamente
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
|
|
/telemetry/{asset_id}:
|
|
get:
|
|
tags: [Telemetry]
|
|
summary: Obtener telemetría reciente de un asset
|
|
parameters:
|
|
- name: asset_id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
- name: limit
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
default: 100
|
|
responses:
|
|
'200':
|
|
description: Lecturas de telemetría recientes
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/TelemetryPayload'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
|
|
/telemetry/{asset_id}/history:
|
|
get:
|
|
tags: [Telemetry]
|
|
summary: Historial agregado de telemetría en ventanas de 5 minutos (ANH)
|
|
parameters:
|
|
- name: asset_id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
- name: from
|
|
in: query
|
|
schema:
|
|
type: string
|
|
format: date-time
|
|
- name: to
|
|
in: query
|
|
schema:
|
|
type: string
|
|
format: date-time
|
|
responses:
|
|
'200':
|
|
description: Historial agregado de telemetría
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: object
|
|
properties:
|
|
bucket:
|
|
type: string
|
|
format: date-time
|
|
variable:
|
|
type: string
|
|
avg_value:
|
|
type: number
|
|
min_value:
|
|
type: number
|
|
max_value:
|
|
type: number
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
|
|
# ── ANH Reports ───────────────────────────────────────────────────────────
|
|
|
|
/anh/reports:
|
|
get:
|
|
tags: [ANH Reports]
|
|
summary: Listar historial de reportes ANH generados (Resolución 0651)
|
|
parameters:
|
|
- name: project_id
|
|
in: query
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
responses:
|
|
'200':
|
|
description: Lista de reportes ANH
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/ANHReport'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
|
|
/anh/reports/{id}:
|
|
get:
|
|
tags: [ANH Reports]
|
|
summary: Obtener detalle y contenido JSON de un reporte ANH
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
responses:
|
|
'200':
|
|
description: Detalle del reporte ANH
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ANHReport'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
|
|
/anh/reports/{id}/download:
|
|
get:
|
|
tags: [ANH Reports]
|
|
summary: Descargar JSON oficial del reporte ANH para validación externa
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
responses:
|
|
'200':
|
|
description: Archivo JSON del reporte
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
|
|
/anh/reports/{id}/hash:
|
|
get:
|
|
tags: [ANH Reports]
|
|
summary: Descargar hash SHA-384 del reporte para auditoría de integridad
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
responses:
|
|
'200':
|
|
description: Hash SHA-384 del reporte
|
|
content:
|
|
text/plain:
|
|
schema:
|
|
type: string
|
|
example: "384:abc123..."
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
|
|
# ── Alerts & Alarms ───────────────────────────────────────────────────────
|
|
|
|
/alert-rules:
|
|
get:
|
|
tags: [Alerts]
|
|
summary: Listar reglas de alerta del proyecto
|
|
parameters:
|
|
- name: project_id
|
|
in: query
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
responses:
|
|
'200':
|
|
description: Lista de reglas de alerta
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/AlertRule'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
post:
|
|
tags: [Alerts]
|
|
summary: Crear nueva regla de alerta
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/CreateAlertRuleRequest'
|
|
responses:
|
|
'201':
|
|
description: Regla creada
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/AlertRule'
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
|
|
/alert-rules/{id}:
|
|
put:
|
|
tags: [Alerts]
|
|
summary: Actualizar una regla de alerta existente
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/CreateAlertRuleRequest'
|
|
responses:
|
|
'200':
|
|
description: Regla actualizada
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/AlertRule'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
delete:
|
|
tags: [Alerts]
|
|
summary: Eliminar regla de alerta
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
responses:
|
|
'204':
|
|
description: Regla eliminada
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
|
|
/alert-rules/{id}/toggle:
|
|
patch:
|
|
tags: [Alerts]
|
|
summary: Activar o desactivar una regla de alerta
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
responses:
|
|
'200':
|
|
description: Estado de la regla actualizado
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
|
|
/alarms:
|
|
get:
|
|
tags: [Alerts]
|
|
summary: Listar alarmas activas del proyecto
|
|
parameters:
|
|
- name: project_id
|
|
in: query
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
responses:
|
|
'200':
|
|
description: Lista de alarmas activas
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/AlarmEvent'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
|
|
# ── Tanks ─────────────────────────────────────────────────────────────────
|
|
|
|
/tanks:
|
|
get:
|
|
tags: [Edge Assets]
|
|
summary: Listar tanques del proyecto activo
|
|
parameters:
|
|
- name: project_id
|
|
in: query
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
responses:
|
|
'200':
|
|
description: Lista de tanques
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/EdgeAsset'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
|
|
# ── Operations ANH 0651 ───────────────────────────────────────────────────
|
|
|
|
/movements:
|
|
get:
|
|
tags: [Operations]
|
|
summary: Listar movimientos operativos registrados
|
|
parameters:
|
|
- name: project_id
|
|
in: query
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
- name: from
|
|
in: query
|
|
schema:
|
|
type: string
|
|
format: date-time
|
|
- name: to
|
|
in: query
|
|
schema:
|
|
type: string
|
|
format: date-time
|
|
responses:
|
|
'200':
|
|
description: Lista de movimientos
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: object
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
post:
|
|
tags: [Operations]
|
|
summary: Registrar movimiento operativo (ANH 0651)
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [project_id, movement_type, volume_bbls, timestamp]
|
|
properties:
|
|
project_id:
|
|
type: string
|
|
format: uuid
|
|
movement_type:
|
|
type: string
|
|
enum: [production, transfer, injection, flare, loss]
|
|
volume_bbls:
|
|
type: number
|
|
format: double
|
|
timestamp:
|
|
type: string
|
|
format: date-time
|
|
notes:
|
|
type: string
|
|
responses:
|
|
'201':
|
|
description: Movimiento registrado
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
|
|
/downtime:
|
|
get:
|
|
tags: [Operations]
|
|
summary: Listar paros operativos registrados
|
|
parameters:
|
|
- name: project_id
|
|
in: query
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
responses:
|
|
'200':
|
|
description: Lista de paros operativos
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: object
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
post:
|
|
tags: [Operations]
|
|
summary: Registrar paro operativo
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [project_id, reason, started_at]
|
|
properties:
|
|
project_id:
|
|
type: string
|
|
format: uuid
|
|
reason:
|
|
type: string
|
|
started_at:
|
|
type: string
|
|
format: date-time
|
|
ended_at:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
responses:
|
|
'201':
|
|
description: Paro registrado
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
|
|
/well-tests:
|
|
get:
|
|
tags: [Operations]
|
|
summary: Listar pruebas de pozo registradas
|
|
parameters:
|
|
- name: project_id
|
|
in: query
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
responses:
|
|
'200':
|
|
description: Lista de pruebas de pozo
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: object
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
post:
|
|
tags: [Operations]
|
|
summary: Registrar prueba de pozo
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [project_id, asset_id, test_date]
|
|
properties:
|
|
project_id:
|
|
type: string
|
|
format: uuid
|
|
asset_id:
|
|
type: string
|
|
format: uuid
|
|
test_date:
|
|
type: string
|
|
format: date-time
|
|
oil_rate_bopd:
|
|
type: number
|
|
water_cut_pct:
|
|
type: number
|
|
gor_scf_bbl:
|
|
type: number
|
|
responses:
|
|
'201':
|
|
description: Prueba de pozo registrada
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
|
|
/lab-results:
|
|
get:
|
|
tags: [Operations]
|
|
summary: Listar resultados de laboratorio
|
|
parameters:
|
|
- name: project_id
|
|
in: query
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
responses:
|
|
'200':
|
|
description: Lista de resultados de laboratorio
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: object
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
post:
|
|
tags: [Operations]
|
|
summary: Registrar resultado de análisis de laboratorio
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [project_id, sample_date, api_gravity]
|
|
properties:
|
|
project_id:
|
|
type: string
|
|
format: uuid
|
|
sample_date:
|
|
type: string
|
|
format: date-time
|
|
api_gravity:
|
|
type: number
|
|
bsw_pct:
|
|
type: number
|
|
viscosity_cp:
|
|
type: number
|
|
responses:
|
|
'201':
|
|
description: Resultado registrado
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
|
|
/meters/readings:
|
|
get:
|
|
tags: [Operations]
|
|
summary: Listar lecturas de medidores de flujo
|
|
parameters:
|
|
- name: project_id
|
|
in: query
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
responses:
|
|
'200':
|
|
description: Lista de lecturas de medidores
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: object
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
post:
|
|
tags: [Operations]
|
|
summary: Registrar lectura de medidor de flujo
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [project_id, meter_id, reading_value, read_at]
|
|
properties:
|
|
project_id:
|
|
type: string
|
|
format: uuid
|
|
meter_id:
|
|
type: string
|
|
format: uuid
|
|
reading_value:
|
|
type: number
|
|
read_at:
|
|
type: string
|
|
format: date-time
|
|
unit:
|
|
type: string
|
|
example: "BBL"
|
|
responses:
|
|
'201':
|
|
description: Lectura registrada
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
|
|
# ── Billing ───────────────────────────────────────────────────────────────
|
|
|
|
/billing/usage:
|
|
get:
|
|
tags: [Billing]
|
|
summary: Consultar uso actual y costo estimado del proyecto
|
|
parameters:
|
|
- name: project_id
|
|
in: query
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
responses:
|
|
'200':
|
|
description: Datos de uso y facturación
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/BillingUsage'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
|
|
/billing/invoices:
|
|
get:
|
|
tags: [Billing]
|
|
summary: Listar historial de facturas del proyecto
|
|
parameters:
|
|
- name: project_id
|
|
in: query
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
responses:
|
|
'200':
|
|
description: Lista de facturas
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/Invoice'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
|
|
/billing/admin/summary:
|
|
get:
|
|
tags: [Billing]
|
|
summary: Resumen de revenue global (solo superadmin)
|
|
responses:
|
|
'200':
|
|
description: Resumen de facturación global
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
total_revenue_usd:
|
|
type: number
|
|
active_subscriptions:
|
|
type: integer
|
|
mrr_usd:
|
|
type: number
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
|
|
/billing/admin/subscriptions/{project_id}:
|
|
put:
|
|
tags: [Billing]
|
|
summary: Actualizar plan de suscripción de un proyecto
|
|
parameters:
|
|
- name: project_id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [plan]
|
|
properties:
|
|
plan:
|
|
type: string
|
|
enum: [starter, professional, enterprise]
|
|
responses:
|
|
'200':
|
|
description: Suscripción actualizada
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
|
|
/billing/invoices/{id}/status:
|
|
patch:
|
|
tags: [Billing]
|
|
summary: Actualizar estado de una factura
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [status]
|
|
properties:
|
|
status:
|
|
type: string
|
|
enum: [pending, paid, overdue, cancelled]
|
|
responses:
|
|
'200':
|
|
description: Estado actualizado
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
|
|
/billing/snapshots:
|
|
post:
|
|
tags: [Billing]
|
|
summary: Tomar snapshot manual del uso actual para facturación
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [project_id]
|
|
properties:
|
|
project_id:
|
|
type: string
|
|
format: uuid
|
|
responses:
|
|
'201':
|
|
description: Snapshot registrado
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
|
|
# ── Edge Projects ─────────────────────────────────────────────────────────
|
|
|
|
/edge/projects:
|
|
get:
|
|
tags: [Edge Projects]
|
|
summary: Listar proyectos edge del usuario autenticado
|
|
responses:
|
|
'200':
|
|
description: Lista de proyectos edge
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/EdgeProject'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
post:
|
|
tags: [Edge Projects]
|
|
summary: Crear nuevo proyecto edge
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/CreateProjectRequest'
|
|
responses:
|
|
'201':
|
|
description: Proyecto creado
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/EdgeProject'
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
|
|
/edge/projects/{id}:
|
|
get:
|
|
tags: [Edge Projects]
|
|
summary: Obtener detalles de un proyecto edge
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
responses:
|
|
'200':
|
|
description: Detalles del proyecto
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/EdgeProject'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
put:
|
|
tags: [Edge Projects]
|
|
summary: Actualizar proyecto edge
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/CreateProjectRequest'
|
|
responses:
|
|
'200':
|
|
description: Proyecto actualizado
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/EdgeProject'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
delete:
|
|
tags: [Edge Projects]
|
|
summary: Eliminar proyecto edge y todos sus recursos
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
responses:
|
|
'204':
|
|
description: Proyecto eliminado
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
|
|
/edge/projects/{id}/full:
|
|
get:
|
|
tags: [Edge Projects]
|
|
summary: Obtener configuración completa del proyecto (assets, devices, variables)
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
responses:
|
|
'200':
|
|
description: Configuración completa del proyecto
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
|
|
/edge/projects/{id}/installer:
|
|
get:
|
|
tags: [Edge Projects]
|
|
summary: Descargar instalador MSI del agente edge para Windows
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
responses:
|
|
'200':
|
|
description: Archivo MSI del instalador
|
|
content:
|
|
application/octet-stream:
|
|
schema:
|
|
type: string
|
|
format: binary
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
|
|
/edge/projects/{id}/deploy:
|
|
post:
|
|
tags: [Edge Projects]
|
|
summary: Desplegar configuración actualizada al agente edge via MQTT
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
responses:
|
|
'200':
|
|
description: Despliegue iniciado
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
|
|
/edge/projects/{id}/rebuild:
|
|
post:
|
|
tags: [Edge Projects]
|
|
summary: Reconstruir instalador MSI del agente edge
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
responses:
|
|
'202':
|
|
description: Rebuild encolado
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
|
|
/edge/projects/{id}/linux-install:
|
|
get:
|
|
tags: [Edge Projects]
|
|
summary: Obtener script de instalación del agente para Linux
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
responses:
|
|
'200':
|
|
description: Script bash de instalación
|
|
content:
|
|
text/x-shellscript:
|
|
schema:
|
|
type: string
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
|
|
/edge/agent/linux-binary/{arch}:
|
|
get:
|
|
tags: [Edge Projects]
|
|
summary: Descargar binario del agente edge para Linux
|
|
parameters:
|
|
- name: arch
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
enum: [x86_64, aarch64]
|
|
responses:
|
|
'200':
|
|
description: Binario compilado del agente
|
|
content:
|
|
application/octet-stream:
|
|
schema:
|
|
type: string
|
|
format: binary
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
|
|
/edge/projects/{project_id}/deployments:
|
|
get:
|
|
tags: [Edge Projects]
|
|
summary: Listar historial de deployments del proyecto
|
|
parameters:
|
|
- name: project_id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
responses:
|
|
'200':
|
|
description: Lista de deployments
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: object
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
|
|
/edge/projects/{project_id}/build:
|
|
post:
|
|
tags: [Edge Projects]
|
|
summary: Disparar build del instalador del proyecto
|
|
parameters:
|
|
- name: project_id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
responses:
|
|
'202':
|
|
description: Build encolado
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
|
|
# ── Edge Assets ───────────────────────────────────────────────────────────
|
|
|
|
/edge/projects/{project_id}/assets:
|
|
get:
|
|
tags: [Edge Assets]
|
|
summary: Listar assets (pozos, tanques) del proyecto
|
|
parameters:
|
|
- name: project_id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
responses:
|
|
'200':
|
|
description: Lista de assets del proyecto
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/EdgeAsset'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
|
|
/edge/assets:
|
|
post:
|
|
tags: [Edge Assets]
|
|
summary: Crear nuevo asset en un proyecto
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/CreateAssetRequest'
|
|
responses:
|
|
'201':
|
|
description: Asset creado
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/EdgeAsset'
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
|
|
/edge/assets/{id}:
|
|
get:
|
|
tags: [Edge Assets]
|
|
summary: Obtener detalles de un asset
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
responses:
|
|
'200':
|
|
description: Detalles del asset
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/EdgeAsset'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
put:
|
|
tags: [Edge Assets]
|
|
summary: Actualizar asset
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/CreateAssetRequest'
|
|
responses:
|
|
'200':
|
|
description: Asset actualizado
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/EdgeAsset'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
delete:
|
|
tags: [Edge Assets]
|
|
summary: Eliminar asset y sus dispositivos
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
responses:
|
|
'204':
|
|
description: Asset eliminado
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
|
|
# ── Edge Devices ──────────────────────────────────────────────────────────
|
|
|
|
/edge/assets/{asset_id}/devices:
|
|
get:
|
|
tags: [Edge Devices]
|
|
summary: Listar dispositivos de campo del asset (PLCs, RTUs, etc.)
|
|
parameters:
|
|
- name: asset_id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
responses:
|
|
'200':
|
|
description: Lista de dispositivos
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/EdgeDevice'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
post:
|
|
tags: [Edge Devices]
|
|
summary: Crear nuevo dispositivo de campo en el asset
|
|
parameters:
|
|
- name: asset_id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/CreateDeviceRequest'
|
|
responses:
|
|
'201':
|
|
description: Dispositivo creado
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/EdgeDevice'
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
|
|
/edge/devices/{id}:
|
|
put:
|
|
tags: [Edge Devices]
|
|
summary: Actualizar configuración de un dispositivo
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/CreateDeviceRequest'
|
|
responses:
|
|
'200':
|
|
description: Dispositivo actualizado
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/EdgeDevice'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
delete:
|
|
tags: [Edge Devices]
|
|
summary: Eliminar dispositivo y sus variables
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
responses:
|
|
'204':
|
|
description: Dispositivo eliminado
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
|
|
# ── Edge Variables ────────────────────────────────────────────────────────
|
|
|
|
/edge/devices/{device_id}/variables:
|
|
get:
|
|
tags: [Edge Variables]
|
|
summary: Listar variables/tags configuradas en el dispositivo
|
|
parameters:
|
|
- name: device_id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
responses:
|
|
'200':
|
|
description: Lista de variables
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/EdgeVariable'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
post:
|
|
tags: [Edge Variables]
|
|
summary: Crear variable/tag en el dispositivo
|
|
parameters:
|
|
- name: device_id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/CreateVariableRequest'
|
|
responses:
|
|
'201':
|
|
description: Variable creada
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/EdgeVariable'
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
|
|
/edge/variables/{id}:
|
|
put:
|
|
tags: [Edge Variables]
|
|
summary: Actualizar variable/tag del dispositivo
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/CreateVariableRequest'
|
|
responses:
|
|
'200':
|
|
description: Variable actualizada
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/EdgeVariable'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
delete:
|
|
tags: [Edge Variables]
|
|
summary: Eliminar variable/tag del dispositivo
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
responses:
|
|
'204':
|
|
description: Variable eliminada
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
|
|
# ── Edge Agents ───────────────────────────────────────────────────────────
|
|
|
|
/edge/agents/logs:
|
|
get:
|
|
tags: [Edge Projects]
|
|
summary: Consultar logs del agente edge (filtrado por proyecto)
|
|
parameters:
|
|
- name: project_id
|
|
in: query
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
- name: level
|
|
in: query
|
|
schema:
|
|
type: string
|
|
enum: [debug, info, warn, error]
|
|
- name: limit
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
default: 100
|
|
responses:
|
|
'200':
|
|
description: Lista de entradas de log
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
level:
|
|
type: string
|
|
category:
|
|
type: string
|
|
message:
|
|
type: string
|
|
timestamp:
|
|
type: string
|
|
format: date-time
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
post:
|
|
tags: [Edge Projects]
|
|
summary: Enviar entrada de log desde el agente edge (uso interno)
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [project_id, level, message]
|
|
properties:
|
|
project_id:
|
|
type: string
|
|
format: uuid
|
|
level:
|
|
type: string
|
|
enum: [debug, info, warn, error]
|
|
category:
|
|
type: string
|
|
message:
|
|
type: string
|
|
responses:
|
|
'201':
|
|
description: Log registrado
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
|
|
/edge/agents/{project_id}/health:
|
|
get:
|
|
tags: [Edge Projects]
|
|
summary: Obtener estado de salud del agente edge de un proyecto
|
|
parameters:
|
|
- name: project_id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
responses:
|
|
'200':
|
|
description: Estado de salud del agente
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
status:
|
|
type: string
|
|
enum: [online, offline, degraded]
|
|
last_seen:
|
|
type: string
|
|
format: date-time
|
|
uptime_seconds:
|
|
type: integer
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
|
|
# ── WebSocket ─────────────────────────────────────────────────────────────
|
|
|
|
/ws/telemetry:
|
|
get:
|
|
tags: [Telemetry]
|
|
summary: Stream WebSocket de telemetría en tiempo real
|
|
description: |
|
|
Conectar al stream de telemetría en tiempo real vía WebSocket.
|
|
Los browsers deben pasar el JWT como query param `token` ya que
|
|
no pueden enviar el header Authorization en conexiones WebSocket.
|
|
parameters:
|
|
- name: project_id
|
|
in: query
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
description: Filtrar eventos por proyecto
|
|
- name: token
|
|
in: query
|
|
required: true
|
|
schema:
|
|
type: string
|
|
description: JWT Bearer token para autenticación WebSocket
|
|
responses:
|
|
'101':
|
|
description: Switching Protocols — conexión WebSocket establecida
|
|
'401':
|
|
description: Token inválido o ausente
|
|
|
|
# ── System ────────────────────────────────────────────────────────────────
|
|
|
|
/health:
|
|
get:
|
|
tags: [System]
|
|
summary: Estado de salud detallado del sistema
|
|
security: []
|
|
servers:
|
|
- url: http://localhost:8000
|
|
description: Direct (no /api prefix)
|
|
responses:
|
|
'200':
|
|
description: Estado del sistema
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/HealthResponse'
|
|
|
|
/metrics:
|
|
get:
|
|
tags: [System]
|
|
summary: Métricas Prometheus (uso interno — no expuesto públicamente)
|
|
security: []
|
|
servers:
|
|
- url: http://localhost:8000
|
|
description: Direct (no /api prefix)
|
|
responses:
|
|
'200':
|
|
description: Métricas en formato Prometheus text
|
|
content:
|
|
text/plain:
|
|
schema:
|
|
type: string
|
|
|
|
components:
|
|
responses:
|
|
Unauthorized:
|
|
description: Token JWT ausente o inválido
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
Forbidden:
|
|
description: Permisos insuficientes para esta operación
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
NotFound:
|
|
description: Recurso no encontrado
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|
|
BadRequest:
|
|
description: Datos de entrada inválidos
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ErrorResponse'
|