Initial commit: MSP Monitor Dashboard
- Next.js 14 frontend with dark cyan/navy theme - tRPC API with Prisma ORM - MeshCentral, LibreNMS, Headwind MDM integrations - Multi-tenant architecture - Alert system with email/SMS/webhook notifications - Docker Compose deployment - Complete documentation
This commit is contained in:
516
docs/api/README.md
Normal file
516
docs/api/README.md
Normal file
@@ -0,0 +1,516 @@
|
||||
# API Reference
|
||||
|
||||
## Vision General
|
||||
|
||||
La API de MSP Monitor Dashboard utiliza [tRPC](https://trpc.io/) para comunicacion type-safe entre frontend y backend. Todos los endpoints estan disponibles bajo `/api/trpc`.
|
||||
|
||||
## Autenticacion
|
||||
|
||||
### Login con Email/Password
|
||||
|
||||
```typescript
|
||||
// POST /api/trpc/auth.login
|
||||
const result = await trpc.auth.login.mutate({
|
||||
email: "usuario@example.com",
|
||||
password: "password123"
|
||||
})
|
||||
// Returns: { success: true, user: { id, email, nombre, rol } }
|
||||
```
|
||||
|
||||
### Login con MeshCentral SSO
|
||||
|
||||
```typescript
|
||||
// POST /api/trpc/auth.loginMeshCentral
|
||||
const result = await trpc.auth.loginMeshCentral.mutate({
|
||||
username: "meshuser",
|
||||
token: "mesh-auth-token"
|
||||
})
|
||||
```
|
||||
|
||||
### Logout
|
||||
|
||||
```typescript
|
||||
// POST /api/trpc/auth.logout
|
||||
await trpc.auth.logout.mutate()
|
||||
```
|
||||
|
||||
### Usuario Actual
|
||||
|
||||
```typescript
|
||||
// GET /api/trpc/auth.me
|
||||
const user = await trpc.auth.me.query()
|
||||
// Returns: { id, email, nombre, rol, cliente, permisos }
|
||||
```
|
||||
|
||||
## Clientes (Tenants)
|
||||
|
||||
### Listar Clientes
|
||||
|
||||
```typescript
|
||||
// GET /api/trpc/clientes.list
|
||||
const { clientes, pagination } = await trpc.clientes.list.query({
|
||||
search: "term",
|
||||
activo: true,
|
||||
page: 1,
|
||||
limit: 20
|
||||
})
|
||||
```
|
||||
|
||||
### Obtener Cliente
|
||||
|
||||
```typescript
|
||||
// GET /api/trpc/clientes.byId
|
||||
const cliente = await trpc.clientes.byId.query({ id: "client-id" })
|
||||
```
|
||||
|
||||
### Crear Cliente
|
||||
|
||||
```typescript
|
||||
// POST /api/trpc/clientes.create
|
||||
const cliente = await trpc.clientes.create.mutate({
|
||||
nombre: "Empresa XYZ",
|
||||
codigo: "XYZ",
|
||||
email: "contacto@xyz.com",
|
||||
meshcentralGrupo: "mesh-group-id"
|
||||
})
|
||||
```
|
||||
|
||||
### Estadisticas del Dashboard
|
||||
|
||||
```typescript
|
||||
// GET /api/trpc/clientes.dashboardStats
|
||||
const stats = await trpc.clientes.dashboardStats.query({
|
||||
clienteId: "optional-client-id"
|
||||
})
|
||||
// Returns: {
|
||||
// totalDispositivos, dispositivosOnline, dispositivosOffline,
|
||||
// dispositivosAlerta, alertasActivas, alertasCriticas
|
||||
// }
|
||||
```
|
||||
|
||||
## Equipos (PC/Laptop/Servidor)
|
||||
|
||||
### Listar Equipos
|
||||
|
||||
```typescript
|
||||
// GET /api/trpc/equipos.list
|
||||
const { dispositivos, pagination } = await trpc.equipos.list.query({
|
||||
clienteId: "client-id",
|
||||
tipo: "SERVIDOR", // PC | LAPTOP | SERVIDOR
|
||||
estado: "ONLINE", // ONLINE | OFFLINE | ALERTA | MANTENIMIENTO
|
||||
search: "term",
|
||||
page: 1,
|
||||
limit: 20
|
||||
})
|
||||
```
|
||||
|
||||
### Obtener Equipo
|
||||
|
||||
```typescript
|
||||
// GET /api/trpc/equipos.byId
|
||||
const equipo = await trpc.equipos.byId.query({ id: "device-id" })
|
||||
// Incluye: cliente, ubicacion, software, alertas activas
|
||||
```
|
||||
|
||||
### Obtener Metricas
|
||||
|
||||
```typescript
|
||||
// GET /api/trpc/equipos.metricas
|
||||
const metricas = await trpc.equipos.metricas.query({
|
||||
dispositivoId: "device-id",
|
||||
periodo: "24h" // 1h | 6h | 24h | 7d | 30d
|
||||
})
|
||||
```
|
||||
|
||||
### Iniciar Sesion Remota
|
||||
|
||||
```typescript
|
||||
// POST /api/trpc/equipos.iniciarSesion
|
||||
const { sesionId, url } = await trpc.equipos.iniciarSesion.mutate({
|
||||
dispositivoId: "device-id",
|
||||
tipo: "desktop" // desktop | terminal | files
|
||||
})
|
||||
// Redirigir a `url` para abrir conexion
|
||||
```
|
||||
|
||||
### Ejecutar Comando
|
||||
|
||||
```typescript
|
||||
// POST /api/trpc/equipos.ejecutarComando
|
||||
const resultado = await trpc.equipos.ejecutarComando.mutate({
|
||||
dispositivoId: "device-id",
|
||||
comando: "Get-Process",
|
||||
tipo: "powershell" // powershell | cmd | bash
|
||||
})
|
||||
// Returns: { success: true, output: "..." }
|
||||
```
|
||||
|
||||
### Reiniciar/Apagar
|
||||
|
||||
```typescript
|
||||
// POST /api/trpc/equipos.reiniciar
|
||||
await trpc.equipos.reiniciar.mutate({ dispositivoId: "device-id" })
|
||||
|
||||
// POST /api/trpc/equipos.apagar
|
||||
await trpc.equipos.apagar.mutate({ dispositivoId: "device-id" })
|
||||
```
|
||||
|
||||
## Celulares (MDM)
|
||||
|
||||
### Listar Celulares
|
||||
|
||||
```typescript
|
||||
// GET /api/trpc/celulares.list
|
||||
const { dispositivos, pagination } = await trpc.celulares.list.query({
|
||||
clienteId: "client-id",
|
||||
estado: "ONLINE",
|
||||
search: "term"
|
||||
})
|
||||
```
|
||||
|
||||
### Obtener Ubicacion
|
||||
|
||||
```typescript
|
||||
// GET /api/trpc/celulares.ubicacion
|
||||
const { lat, lng, updatedAt } = await trpc.celulares.ubicacion.query({
|
||||
dispositivoId: "device-id"
|
||||
})
|
||||
```
|
||||
|
||||
### Solicitar Ubicacion
|
||||
|
||||
```typescript
|
||||
// POST /api/trpc/celulares.solicitarUbicacion
|
||||
await trpc.celulares.solicitarUbicacion.mutate({
|
||||
dispositivoId: "device-id"
|
||||
})
|
||||
```
|
||||
|
||||
### Bloquear/Desbloquear
|
||||
|
||||
```typescript
|
||||
// POST /api/trpc/celulares.bloquear
|
||||
await trpc.celulares.bloquear.mutate({
|
||||
dispositivoId: "device-id",
|
||||
mensaje: "Dispositivo bloqueado por seguridad"
|
||||
})
|
||||
|
||||
// POST /api/trpc/celulares.desbloquear
|
||||
await trpc.celulares.desbloquear.mutate({
|
||||
dispositivoId: "device-id"
|
||||
})
|
||||
```
|
||||
|
||||
### Hacer Sonar
|
||||
|
||||
```typescript
|
||||
// POST /api/trpc/celulares.sonar
|
||||
await trpc.celulares.sonar.mutate({
|
||||
dispositivoId: "device-id"
|
||||
})
|
||||
```
|
||||
|
||||
### Enviar Mensaje
|
||||
|
||||
```typescript
|
||||
// POST /api/trpc/celulares.enviarMensaje
|
||||
await trpc.celulares.enviarMensaje.mutate({
|
||||
dispositivoId: "device-id",
|
||||
mensaje: "Mensaje para el usuario"
|
||||
})
|
||||
```
|
||||
|
||||
### Borrar Datos (Factory Reset)
|
||||
|
||||
```typescript
|
||||
// POST /api/trpc/celulares.borrarDatos
|
||||
// CUIDADO: Esta accion es irreversible
|
||||
await trpc.celulares.borrarDatos.mutate({
|
||||
dispositivoId: "device-id"
|
||||
})
|
||||
```
|
||||
|
||||
### Instalar/Desinstalar App
|
||||
|
||||
```typescript
|
||||
// POST /api/trpc/celulares.instalarApp
|
||||
await trpc.celulares.instalarApp.mutate({
|
||||
dispositivoId: "device-id",
|
||||
packageName: "com.example.app"
|
||||
})
|
||||
|
||||
// POST /api/trpc/celulares.desinstalarApp
|
||||
await trpc.celulares.desinstalarApp.mutate({
|
||||
dispositivoId: "device-id",
|
||||
packageName: "com.example.app"
|
||||
})
|
||||
```
|
||||
|
||||
## Red (SNMP/NetFlow)
|
||||
|
||||
### Listar Dispositivos de Red
|
||||
|
||||
```typescript
|
||||
// GET /api/trpc/red.list
|
||||
const { dispositivos, pagination } = await trpc.red.list.query({
|
||||
clienteId: "client-id",
|
||||
tipo: "ROUTER", // ROUTER | SWITCH | FIREWALL | AP | IMPRESORA | OTRO
|
||||
estado: "ONLINE"
|
||||
})
|
||||
```
|
||||
|
||||
### Obtener Interfaces
|
||||
|
||||
```typescript
|
||||
// GET /api/trpc/red.interfaces
|
||||
const interfaces = await trpc.red.interfaces.query({
|
||||
dispositivoId: "device-id"
|
||||
})
|
||||
// Returns: [{ ifName, ifAlias, ifSpeed, ifOperStatus, ifInOctets_rate, ifOutOctets_rate }]
|
||||
```
|
||||
|
||||
### Obtener Trafico
|
||||
|
||||
```typescript
|
||||
// GET /api/trpc/red.trafico
|
||||
const datos = await trpc.red.trafico.query({
|
||||
dispositivoId: "device-id",
|
||||
portId: 123,
|
||||
periodo: "24h"
|
||||
})
|
||||
// Returns: [{ timestamp, in, out }]
|
||||
```
|
||||
|
||||
### Obtener Topologia
|
||||
|
||||
```typescript
|
||||
// GET /api/trpc/red.topologia
|
||||
const { nodes, links } = await trpc.red.topologia.query({
|
||||
clienteId: "client-id"
|
||||
})
|
||||
// Para visualizacion con D3.js o similar
|
||||
```
|
||||
|
||||
## Alertas
|
||||
|
||||
### Listar Alertas
|
||||
|
||||
```typescript
|
||||
// GET /api/trpc/alertas.list
|
||||
const { alertas, pagination } = await trpc.alertas.list.query({
|
||||
clienteId: "client-id",
|
||||
estado: "ACTIVA", // ACTIVA | RECONOCIDA | RESUELTA
|
||||
severidad: "CRITICAL", // INFO | WARNING | CRITICAL
|
||||
dispositivoId: "device-id",
|
||||
desde: new Date("2024-01-01"),
|
||||
hasta: new Date("2024-01-31")
|
||||
})
|
||||
```
|
||||
|
||||
### Reconocer Alerta
|
||||
|
||||
```typescript
|
||||
// POST /api/trpc/alertas.reconocer
|
||||
await trpc.alertas.reconocer.mutate({ id: "alert-id" })
|
||||
```
|
||||
|
||||
### Resolver Alerta
|
||||
|
||||
```typescript
|
||||
// POST /api/trpc/alertas.resolver
|
||||
await trpc.alertas.resolver.mutate({ id: "alert-id" })
|
||||
```
|
||||
|
||||
### Conteo de Alertas Activas
|
||||
|
||||
```typescript
|
||||
// GET /api/trpc/alertas.conteoActivas
|
||||
const { total, critical, warning, info } = await trpc.alertas.conteoActivas.query({
|
||||
clienteId: "client-id"
|
||||
})
|
||||
```
|
||||
|
||||
## Reglas de Alerta
|
||||
|
||||
### Listar Reglas
|
||||
|
||||
```typescript
|
||||
// GET /api/trpc/alertas.reglas.list
|
||||
const reglas = await trpc.alertas.reglas.list.query({
|
||||
clienteId: "client-id"
|
||||
})
|
||||
```
|
||||
|
||||
### Crear Regla
|
||||
|
||||
```typescript
|
||||
// POST /api/trpc/alertas.reglas.create
|
||||
const regla = await trpc.alertas.reglas.create.mutate({
|
||||
clienteId: "client-id", // null para regla global
|
||||
nombre: "CPU Alta",
|
||||
metrica: "cpu",
|
||||
operador: ">",
|
||||
umbral: 90,
|
||||
duracionMinutos: 5,
|
||||
severidad: "WARNING",
|
||||
notificarEmail: true,
|
||||
notificarSms: false
|
||||
})
|
||||
```
|
||||
|
||||
## Reportes
|
||||
|
||||
### Reporte de Inventario
|
||||
|
||||
```typescript
|
||||
// GET /api/trpc/reportes.inventario
|
||||
const { dispositivos, resumen } = await trpc.reportes.inventario.query({
|
||||
clienteId: "client-id",
|
||||
tipo: "SERVIDOR"
|
||||
})
|
||||
```
|
||||
|
||||
### Reporte de Uptime
|
||||
|
||||
```typescript
|
||||
// GET /api/trpc/reportes.uptime
|
||||
const { dispositivos, promedioGeneral } = await trpc.reportes.uptime.query({
|
||||
clienteId: "client-id",
|
||||
desde: new Date("2024-01-01"),
|
||||
hasta: new Date("2024-01-31")
|
||||
})
|
||||
```
|
||||
|
||||
### Reporte de Alertas
|
||||
|
||||
```typescript
|
||||
// GET /api/trpc/reportes.alertas
|
||||
const { alertas, resumen } = await trpc.reportes.alertas.query({
|
||||
clienteId: "client-id",
|
||||
desde: new Date("2024-01-01"),
|
||||
hasta: new Date("2024-01-31")
|
||||
})
|
||||
```
|
||||
|
||||
### Exportar a CSV
|
||||
|
||||
```typescript
|
||||
// POST /api/trpc/reportes.exportarCSV
|
||||
const { filename, content, contentType } = await trpc.reportes.exportarCSV.mutate({
|
||||
tipo: "inventario", // inventario | alertas | actividad
|
||||
clienteId: "client-id"
|
||||
})
|
||||
// Descargar el contenido como archivo CSV
|
||||
```
|
||||
|
||||
## Usuarios
|
||||
|
||||
### Listar Usuarios
|
||||
|
||||
```typescript
|
||||
// GET /api/trpc/usuarios.list
|
||||
const { usuarios, pagination } = await trpc.usuarios.list.query({
|
||||
clienteId: "client-id",
|
||||
rol: "TECNICO",
|
||||
activo: true
|
||||
})
|
||||
```
|
||||
|
||||
### Crear Usuario
|
||||
|
||||
```typescript
|
||||
// POST /api/trpc/usuarios.create
|
||||
const usuario = await trpc.usuarios.create.mutate({
|
||||
email: "nuevo@example.com",
|
||||
nombre: "Nuevo Usuario",
|
||||
password: "password123",
|
||||
clienteId: "client-id",
|
||||
rol: "TECNICO"
|
||||
})
|
||||
```
|
||||
|
||||
### Resetear Password
|
||||
|
||||
```typescript
|
||||
// POST /api/trpc/usuarios.resetPassword
|
||||
await trpc.usuarios.resetPassword.mutate({
|
||||
id: "user-id",
|
||||
newPassword: "newpassword123"
|
||||
})
|
||||
```
|
||||
|
||||
## Configuracion
|
||||
|
||||
### Obtener Configuracion
|
||||
|
||||
```typescript
|
||||
// GET /api/trpc/configuracion.get
|
||||
const config = await trpc.configuracion.get.query({
|
||||
clave: "smtp_host"
|
||||
})
|
||||
```
|
||||
|
||||
### Establecer Configuracion
|
||||
|
||||
```typescript
|
||||
// POST /api/trpc/configuracion.set
|
||||
await trpc.configuracion.set.mutate({
|
||||
clave: "smtp_host",
|
||||
valor: "smtp.gmail.com",
|
||||
tipo: "string",
|
||||
categoria: "notificacion"
|
||||
})
|
||||
```
|
||||
|
||||
### Estado de Integraciones
|
||||
|
||||
```typescript
|
||||
// GET /api/trpc/configuracion.integraciones.status
|
||||
const { meshcentral, librenms, headwind } = await trpc.configuracion.integraciones.status.query()
|
||||
// Returns: { configurado: boolean, url?: string }
|
||||
```
|
||||
|
||||
### Configurar MeshCentral
|
||||
|
||||
```typescript
|
||||
// POST /api/trpc/configuracion.integraciones.setMeshCentral
|
||||
await trpc.configuracion.integraciones.setMeshCentral.mutate({
|
||||
url: "https://mesh.tudominio.com",
|
||||
user: "admin",
|
||||
password: "password",
|
||||
domain: "default"
|
||||
})
|
||||
```
|
||||
|
||||
## Codigos de Error
|
||||
|
||||
| Codigo | Descripcion |
|
||||
|--------|-------------|
|
||||
| UNAUTHORIZED | No autenticado |
|
||||
| FORBIDDEN | Sin permisos |
|
||||
| NOT_FOUND | Recurso no encontrado |
|
||||
| CONFLICT | Conflicto (ej: email duplicado) |
|
||||
| BAD_REQUEST | Request invalido |
|
||||
| INTERNAL_SERVER_ERROR | Error del servidor |
|
||||
|
||||
## Rate Limiting
|
||||
|
||||
- API general: 100 requests/minuto
|
||||
- Autenticacion: 10 requests/minuto
|
||||
- Acciones sensibles (wipe, commands): 5 requests/minuto
|
||||
|
||||
## Webhooks
|
||||
|
||||
Las alertas pueden enviar webhooks a URLs configuradas:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "alert-id",
|
||||
"severidad": "CRITICAL",
|
||||
"titulo": "Servidor offline",
|
||||
"mensaje": "El servidor SRV-01 no responde",
|
||||
"dispositivo": "SRV-01",
|
||||
"cliente": "Cliente A",
|
||||
"timestamp": "2024-01-15T10:30:00Z"
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user