- Añadir campos al modelo MonitoredApp: * service_name: Nombre del servicio systemd * path: WorkingDirectory de la aplicación * entry_point: Archivo de entrada (server.js, app.js, etc.) * node_bin: Ruta completa al binario de node/python * mode: Modo de ejecución (production, development, test) * service_file_path: Ruta al archivo .service de systemd * registered_at: Timestamp de registro (ISO 8601) - Actualizar discovery.rs para extraer toda la información: * Parsear ExecStart para obtener node_bin y entry_point * Extraer NODE_ENV para determinar el modo * Guardar ruta completa al archivo .service * Usar add_app_full() con información completa - Integrar ConfigManager en AppManager: * Guardar automáticamente en monitored_apps.json al registrar apps * Eliminar del JSON al desregistrar apps * Extraer metadata desde ServiceConfig (puerto, entry_point, mode, etc.) - Mantener retrocompatibilidad con JSON antiguo mediante campos deprecated - Todos los nuevos campos usan #[serde(default)] para evitar errores de deserialización
912 lines
39 KiB
HTML
912 lines
39 KiB
HTML
<!doctype html>
|
|
<html class="dark" lang="es" dir="ltr">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
|
|
<title>Documentación API - SIAX Monitor</title>
|
|
<link rel="icon" type="image/svg+xml" href="/static/icon/favicon.svg" />
|
|
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
|
<link
|
|
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
|
|
rel="stylesheet"
|
|
/>
|
|
<link
|
|
href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&display=swap"
|
|
rel="stylesheet"
|
|
/>
|
|
<link
|
|
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap"
|
|
rel="stylesheet"
|
|
/>
|
|
<script>
|
|
tailwind.config = {
|
|
darkMode: "class",
|
|
theme: {
|
|
extend: {
|
|
colors: {
|
|
primary: "#137fec",
|
|
"background-light": "#f6f7f8",
|
|
"background-dark": "#101922",
|
|
},
|
|
fontFamily: {
|
|
display: ["Inter", "sans-serif"],
|
|
mono: ["JetBrains Mono", "monospace"],
|
|
},
|
|
borderRadius: {
|
|
DEFAULT: "0.25rem",
|
|
lg: "0.5rem",
|
|
xl: "0.75rem",
|
|
full: "9999px",
|
|
},
|
|
},
|
|
},
|
|
};
|
|
</script>
|
|
<style>
|
|
body {
|
|
font-family: "Inter", sans-serif;
|
|
}
|
|
.material-symbols-outlined {
|
|
font-variation-settings:
|
|
"FILL" 0,
|
|
"wght" 400,
|
|
"GRAD" 0,
|
|
"opsz" 24;
|
|
}
|
|
.code-block {
|
|
font-family: "JetBrains Mono", monospace;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body
|
|
class="bg-background-light dark:bg-background-dark font-display text-white min-h-screen flex flex-col"
|
|
>
|
|
<!-- Sticky Top Navigation -->
|
|
<header
|
|
class="sticky top-0 z-50 w-full border-b border-solid border-[#283039] bg-background-dark/80 backdrop-blur-md px-4 md:px-10 py-3"
|
|
>
|
|
<div
|
|
class="max-w-[1400px] mx-auto flex items-center justify-between whitespace-nowrap"
|
|
>
|
|
<div class="flex items-center gap-8">
|
|
<div class="flex items-center gap-4 text-white">
|
|
<div
|
|
class="size-8 bg-primary rounded-lg flex items-center justify-center"
|
|
>
|
|
<span class="material-symbols-outlined text-white"
|
|
>monitoring</span
|
|
>
|
|
</div>
|
|
<h2
|
|
class="text-white text-lg font-bold leading-tight tracking-[-0.015em]"
|
|
>
|
|
SIAX Monitor
|
|
</h2>
|
|
</div>
|
|
</div>
|
|
<div class="flex flex-1 justify-end gap-6 items-center">
|
|
<nav class="hidden md:flex items-center gap-6">
|
|
<a
|
|
class="text-[#9dabb9] text-sm font-medium hover:text-white transition-colors"
|
|
href="/"
|
|
>Panel</a
|
|
>
|
|
<a
|
|
class="text-[#9dabb9] text-sm font-medium hover:text-white transition-colors"
|
|
href="/scan"
|
|
>Escanear</a
|
|
>
|
|
<a
|
|
class="text-[#9dabb9] text-sm font-medium hover:text-white transition-colors"
|
|
href="/register"
|
|
>Registrar Nueva</a
|
|
>
|
|
<a
|
|
class="text-primary text-sm font-medium border-b-2 border-primary pb-1"
|
|
href="/api-docs"
|
|
>Documentación API</a
|
|
>
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
<div class="flex-1 flex max-w-[1400px] mx-auto w-full">
|
|
<!-- Sidebar - Table of Contents -->
|
|
<aside
|
|
class="w-64 border-r border-[#283039] bg-[#161f2a] p-6 space-y-6 overflow-y-auto"
|
|
>
|
|
<div>
|
|
<h3 class="text-white font-bold text-sm mb-3">CONTENIDO</h3>
|
|
<nav class="space-y-2">
|
|
<a
|
|
href="#intro"
|
|
class="block text-[#9dabb9] text-sm hover:text-primary transition-colors"
|
|
>Introducción</a
|
|
>
|
|
<a
|
|
href="#auth"
|
|
class="block text-[#9dabb9] text-sm hover:text-primary transition-colors"
|
|
>Autenticación</a
|
|
>
|
|
<a
|
|
href="#apps"
|
|
class="block text-[#9dabb9] text-sm hover:text-primary transition-colors"
|
|
>Gestión de Apps</a
|
|
>
|
|
<a
|
|
href="#scan"
|
|
class="block text-[#9dabb9] text-sm hover:text-primary transition-colors"
|
|
>Escaneo</a
|
|
>
|
|
<a
|
|
href="#lifecycle"
|
|
class="block text-[#9dabb9] text-sm hover:text-primary transition-colors"
|
|
>Ciclo de Vida</a
|
|
>
|
|
<a
|
|
href="#websocket"
|
|
class="block text-[#9dabb9] text-sm hover:text-primary transition-colors"
|
|
>WebSocket</a
|
|
>
|
|
<a
|
|
href="#errors"
|
|
class="block text-[#9dabb9] text-sm hover:text-primary transition-colors"
|
|
>Códigos de Error</a
|
|
>
|
|
</nav>
|
|
</div>
|
|
|
|
<div class="pt-6 border-t border-[#283039]">
|
|
<h3 class="text-white font-bold text-sm mb-3">INFO</h3>
|
|
<div class="space-y-2 text-xs">
|
|
<div>
|
|
<span class="text-[#9dabb9]">Versión:</span>
|
|
<span class="text-white font-mono">v1.0.0</span>
|
|
</div>
|
|
<div>
|
|
<span class="text-[#9dabb9]">Base URL:</span>
|
|
<span class="text-white font-mono"
|
|
>localhost:8080</span
|
|
>
|
|
</div>
|
|
<div>
|
|
<span class="text-[#9dabb9]">Protocolo:</span>
|
|
<span class="text-white font-mono">HTTP/WS</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</aside>
|
|
|
|
<!-- Main Content - API Documentation -->
|
|
<main class="flex-1 p-8 overflow-y-auto">
|
|
<!-- Introduction -->
|
|
<section id="intro" class="mb-12">
|
|
<h1 class="text-white text-4xl font-black mb-4">
|
|
Documentación API REST
|
|
</h1>
|
|
<p class="text-[#9dabb9] text-lg mb-6">
|
|
API para gestión y monitoreo de aplicaciones Node.js y
|
|
Python con systemd.
|
|
</p>
|
|
|
|
<div
|
|
class="rounded-xl border border-primary/30 bg-primary/10 p-4 mb-6"
|
|
>
|
|
<div class="flex items-start gap-3">
|
|
<span
|
|
class="material-symbols-outlined text-primary mt-0.5"
|
|
>info</span
|
|
>
|
|
<div>
|
|
<p class="text-white font-semibold mb-1">
|
|
Endpoint Base
|
|
</p>
|
|
<code class="text-primary font-mono text-sm"
|
|
>/api</code
|
|
>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
|
<div
|
|
class="rounded-xl border border-[#283039] bg-[#161f2a] p-4"
|
|
>
|
|
<span
|
|
class="material-symbols-outlined text-green-400 mb-2"
|
|
>check_circle</span
|
|
>
|
|
<p class="text-white font-semibold text-sm">
|
|
REST API
|
|
</p>
|
|
<p class="text-[#9dabb9] text-xs">JSON responses</p>
|
|
</div>
|
|
<div
|
|
class="rounded-xl border border-[#283039] bg-[#161f2a] p-4"
|
|
>
|
|
<span
|
|
class="material-symbols-outlined text-blue-400 mb-2"
|
|
>bolt</span
|
|
>
|
|
<p class="text-white font-semibold text-sm">
|
|
WebSocket
|
|
</p>
|
|
<p class="text-[#9dabb9] text-xs">
|
|
Logs en tiempo real
|
|
</p>
|
|
</div>
|
|
<div
|
|
class="rounded-xl border border-[#283039] bg-[#161f2a] p-4"
|
|
>
|
|
<span
|
|
class="material-symbols-outlined text-purple-400 mb-2"
|
|
>schedule</span
|
|
>
|
|
<p class="text-white font-semibold text-sm">
|
|
Rate Limiting
|
|
</p>
|
|
<p class="text-[#9dabb9] text-xs">1 op/segundo</p>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Authentication -->
|
|
<section id="auth" class="mb-12">
|
|
<h2
|
|
class="text-white text-2xl font-bold mb-4 flex items-center gap-2"
|
|
>
|
|
<span class="material-symbols-outlined text-primary"
|
|
>lock</span
|
|
>
|
|
Autenticación
|
|
</h2>
|
|
<p class="text-[#9dabb9] mb-4">
|
|
Actualmente la API no requiere autenticación ya que está
|
|
diseñada para acceso local vía VPN.
|
|
</p>
|
|
<div
|
|
class="rounded-xl border border-yellow-500/30 bg-yellow-500/10 p-4"
|
|
>
|
|
<div class="flex items-start gap-3">
|
|
<span
|
|
class="material-symbols-outlined text-yellow-400"
|
|
>warning</span
|
|
>
|
|
<div>
|
|
<p class="text-yellow-400 font-semibold">
|
|
Nota de Seguridad
|
|
</p>
|
|
<p class="text-[#9dabb9] text-sm">
|
|
Esta API debe ser accesible solo desde redes
|
|
privadas o VPN.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Apps Management -->
|
|
<section id="apps" class="mb-12">
|
|
<h2
|
|
class="text-white text-2xl font-bold mb-6 flex items-center gap-2"
|
|
>
|
|
<span class="material-symbols-outlined text-primary"
|
|
>apps</span
|
|
>
|
|
Gestión de Aplicaciones
|
|
</h2>
|
|
|
|
<!-- List Apps -->
|
|
<div
|
|
class="mb-8 rounded-xl border border-[#283039] bg-[#161f2a] overflow-hidden"
|
|
>
|
|
<div
|
|
class="bg-[#1c2730] px-6 py-4 border-b border-[#283039]"
|
|
>
|
|
<div class="flex items-center gap-3">
|
|
<span
|
|
class="px-2 py-1 rounded bg-green-500/20 text-green-400 text-xs font-bold font-mono"
|
|
>GET</span
|
|
>
|
|
<code class="text-white font-mono text-sm"
|
|
>/api/apps</code
|
|
>
|
|
</div>
|
|
<p class="text-[#9dabb9] text-sm mt-2">
|
|
Listar todas las aplicaciones registradas
|
|
</p>
|
|
</div>
|
|
<div class="p-6 space-y-4">
|
|
<div>
|
|
<p
|
|
class="text-white font-semibold text-sm mb-2"
|
|
>
|
|
Respuesta exitosa (200)
|
|
</p>
|
|
<pre
|
|
class="code-block bg-[#0a0f16] p-4 rounded-lg text-sm text-green-400 overflow-x-auto"
|
|
>
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"apps": ["app_tareas", "fidelizacion"],
|
|
"total": 2
|
|
},
|
|
"error": null
|
|
}</pre
|
|
>
|
|
</div>
|
|
<button
|
|
onclick="tryEndpoint('GET', '/api/apps')"
|
|
class="flex items-center gap-2 px-4 py-2 bg-primary hover:brightness-110 rounded-lg text-white text-sm font-medium transition-all"
|
|
>
|
|
<span class="material-symbols-outlined text-sm"
|
|
>play_arrow</span
|
|
>
|
|
Probar endpoint
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Register App -->
|
|
<div
|
|
class="mb-8 rounded-xl border border-[#283039] bg-[#161f2a] overflow-hidden"
|
|
>
|
|
<div
|
|
class="bg-[#1c2730] px-6 py-4 border-b border-[#283039]"
|
|
>
|
|
<div class="flex items-center gap-3">
|
|
<span
|
|
class="px-2 py-1 rounded bg-blue-500/20 text-blue-400 text-xs font-bold font-mono"
|
|
>POST</span
|
|
>
|
|
<code class="text-white font-mono text-sm"
|
|
>/api/apps</code
|
|
>
|
|
</div>
|
|
<p class="text-[#9dabb9] text-sm mt-2">
|
|
Registrar una nueva aplicación
|
|
</p>
|
|
</div>
|
|
<div class="p-6 space-y-4">
|
|
<div>
|
|
<p
|
|
class="text-white font-semibold text-sm mb-2"
|
|
>
|
|
Body (JSON)
|
|
</p>
|
|
<pre
|
|
class="code-block bg-[#0a0f16] p-4 rounded-lg text-sm text-blue-400 overflow-x-auto"
|
|
>
|
|
{
|
|
"app_name": "mi-app",
|
|
"script_path": "/opt/apps/mi-app/index.js",
|
|
"working_directory": "/opt/apps/mi-app",
|
|
"user": "nodejs",
|
|
"environment": {
|
|
"NODE_ENV": "production",
|
|
"PORT": "3000"
|
|
},
|
|
"restart_policy": "always",
|
|
"app_type": "nodejs",
|
|
"description": "Mi aplicación Node.js"
|
|
}</pre
|
|
>
|
|
</div>
|
|
<div>
|
|
<p
|
|
class="text-white font-semibold text-sm mb-2"
|
|
>
|
|
Respuesta exitosa (200)
|
|
</p>
|
|
<pre
|
|
class="code-block bg-[#0a0f16] p-4 rounded-lg text-sm text-green-400 overflow-x-auto"
|
|
>
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"app_name": "mi-app",
|
|
"operation": "register",
|
|
"success": true,
|
|
"message": "Aplicación registrada exitosamente"
|
|
},
|
|
"error": null
|
|
}</pre
|
|
>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Delete App -->
|
|
<div
|
|
class="mb-8 rounded-xl border border-[#283039] bg-[#161f2a] overflow-hidden"
|
|
>
|
|
<div
|
|
class="bg-[#1c2730] px-6 py-4 border-b border-[#283039]"
|
|
>
|
|
<div class="flex items-center gap-3">
|
|
<span
|
|
class="px-2 py-1 rounded bg-red-500/20 text-red-400 text-xs font-bold font-mono"
|
|
>DELETE</span
|
|
>
|
|
<code class="text-white font-mono text-sm"
|
|
>/api/apps/:name</code
|
|
>
|
|
</div>
|
|
<p class="text-[#9dabb9] text-sm mt-2">
|
|
Eliminar una aplicación registrada
|
|
</p>
|
|
</div>
|
|
<div class="p-6 space-y-4">
|
|
<div>
|
|
<p
|
|
class="text-white font-semibold text-sm mb-2"
|
|
>
|
|
Parámetros
|
|
</p>
|
|
<ul class="space-y-2">
|
|
<li class="flex items-start gap-2">
|
|
<code
|
|
class="text-primary font-mono text-sm"
|
|
>name</code
|
|
>
|
|
<span class="text-[#9dabb9] text-sm"
|
|
>- Nombre de la aplicación</span
|
|
>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Get Status -->
|
|
<div
|
|
class="mb-8 rounded-xl border border-[#283039] bg-[#161f2a] overflow-hidden"
|
|
>
|
|
<div
|
|
class="bg-[#1c2730] px-6 py-4 border-b border-[#283039]"
|
|
>
|
|
<div class="flex items-center gap-3">
|
|
<span
|
|
class="px-2 py-1 rounded bg-green-500/20 text-green-400 text-xs font-bold font-mono"
|
|
>GET</span
|
|
>
|
|
<code class="text-white font-mono text-sm"
|
|
>/api/apps/:name/status</code
|
|
>
|
|
</div>
|
|
<p class="text-[#9dabb9] text-sm mt-2">
|
|
Obtener estado de una aplicación
|
|
</p>
|
|
</div>
|
|
<div class="p-6 space-y-4">
|
|
<div>
|
|
<p
|
|
class="text-white font-semibold text-sm mb-2"
|
|
>
|
|
Respuesta exitosa (200)
|
|
</p>
|
|
<pre
|
|
class="code-block bg-[#0a0f16] p-4 rounded-lg text-sm text-green-400 overflow-x-auto"
|
|
>
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"name": "mi-app",
|
|
"status": "Running",
|
|
"pid": 12345,
|
|
"cpu_usage": 2.5,
|
|
"memory_usage": "128.50 MB",
|
|
"systemd_status": "active",
|
|
"last_updated": "2026-01-13T12:34:56"
|
|
}
|
|
}</pre
|
|
>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Scan -->
|
|
<section id="scan" class="mb-12">
|
|
<h2
|
|
class="text-white text-2xl font-bold mb-6 flex items-center gap-2"
|
|
>
|
|
<span class="material-symbols-outlined text-primary"
|
|
>search</span
|
|
>
|
|
Escaneo de Procesos
|
|
</h2>
|
|
|
|
<div
|
|
class="mb-8 rounded-xl border border-[#283039] bg-[#161f2a] overflow-hidden"
|
|
>
|
|
<div
|
|
class="bg-[#1c2730] px-6 py-4 border-b border-[#283039]"
|
|
>
|
|
<div class="flex items-center gap-3">
|
|
<span
|
|
class="px-2 py-1 rounded bg-green-500/20 text-green-400 text-xs font-bold font-mono"
|
|
>GET</span
|
|
>
|
|
<code class="text-white font-mono text-sm"
|
|
>/api/scan</code
|
|
>
|
|
</div>
|
|
<p class="text-[#9dabb9] text-sm mt-2">
|
|
Escanear procesos Node.js y Python en ejecución
|
|
</p>
|
|
</div>
|
|
<div class="p-6 space-y-4">
|
|
<div>
|
|
<p
|
|
class="text-white font-semibold text-sm mb-2"
|
|
>
|
|
Respuesta exitosa (200)
|
|
</p>
|
|
<pre
|
|
class="code-block bg-[#0a0f16] p-4 rounded-lg text-sm text-green-400 overflow-x-auto"
|
|
>
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"processes": [
|
|
{
|
|
"pid": 5769,
|
|
"name": "node",
|
|
"user": "1000",
|
|
"cpu_usage": 2.5,
|
|
"memory_mb": 112.54,
|
|
"process_type": "nodejs"
|
|
}
|
|
],
|
|
"total": 1
|
|
}
|
|
}</pre
|
|
>
|
|
</div>
|
|
<button
|
|
onclick="tryEndpoint('GET', '/api/scan')"
|
|
class="flex items-center gap-2 px-4 py-2 bg-primary hover:brightness-110 rounded-lg text-white text-sm font-medium transition-all"
|
|
>
|
|
<span class="material-symbols-outlined text-sm"
|
|
>play_arrow</span
|
|
>
|
|
Probar endpoint
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Lifecycle -->
|
|
<section id="lifecycle" class="mb-12">
|
|
<h2
|
|
class="text-white text-2xl font-bold mb-6 flex items-center gap-2"
|
|
>
|
|
<span class="material-symbols-outlined text-primary"
|
|
>settings_power</span
|
|
>
|
|
Ciclo de Vida
|
|
</h2>
|
|
|
|
<!-- Start -->
|
|
<div
|
|
class="mb-8 rounded-xl border border-[#283039] bg-[#161f2a] overflow-hidden"
|
|
>
|
|
<div
|
|
class="bg-[#1c2730] px-6 py-4 border-b border-[#283039]"
|
|
>
|
|
<div class="flex items-center gap-3">
|
|
<span
|
|
class="px-2 py-1 rounded bg-blue-500/20 text-blue-400 text-xs font-bold font-mono"
|
|
>POST</span
|
|
>
|
|
<code class="text-white font-mono text-sm"
|
|
>/api/apps/:name/start</code
|
|
>
|
|
</div>
|
|
<p class="text-[#9dabb9] text-sm mt-2">
|
|
Iniciar una aplicación
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Stop -->
|
|
<div
|
|
class="mb-8 rounded-xl border border-[#283039] bg-[#161f2a] overflow-hidden"
|
|
>
|
|
<div
|
|
class="bg-[#1c2730] px-6 py-4 border-b border-[#283039]"
|
|
>
|
|
<div class="flex items-center gap-3">
|
|
<span
|
|
class="px-2 py-1 rounded bg-blue-500/20 text-blue-400 text-xs font-bold font-mono"
|
|
>POST</span
|
|
>
|
|
<code class="text-white font-mono text-sm"
|
|
>/api/apps/:name/stop</code
|
|
>
|
|
</div>
|
|
<p class="text-[#9dabb9] text-sm mt-2">
|
|
Detener una aplicación
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Restart -->
|
|
<div
|
|
class="mb-8 rounded-xl border border-[#283039] bg-[#161f2a] overflow-hidden"
|
|
>
|
|
<div
|
|
class="bg-[#1c2730] px-6 py-4 border-b border-[#283039]"
|
|
>
|
|
<div class="flex items-center gap-3">
|
|
<span
|
|
class="px-2 py-1 rounded bg-blue-500/20 text-blue-400 text-xs font-bold font-mono"
|
|
>POST</span
|
|
>
|
|
<code class="text-white font-mono text-sm"
|
|
>/api/apps/:name/restart</code
|
|
>
|
|
</div>
|
|
<p class="text-[#9dabb9] text-sm mt-2">
|
|
Reiniciar una aplicación
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div
|
|
class="rounded-xl border border-yellow-500/30 bg-yellow-500/10 p-4"
|
|
>
|
|
<div class="flex items-start gap-3">
|
|
<span
|
|
class="material-symbols-outlined text-yellow-400"
|
|
>schedule</span
|
|
>
|
|
<div>
|
|
<p class="text-yellow-400 font-semibold">
|
|
Rate Limiting
|
|
</p>
|
|
<p class="text-[#9dabb9] text-sm">
|
|
Las operaciones están limitadas a 1 por
|
|
segundo por aplicación.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- WebSocket -->
|
|
<section id="websocket" class="mb-12">
|
|
<h2
|
|
class="text-white text-2xl font-bold mb-6 flex items-center gap-2"
|
|
>
|
|
<span class="material-symbols-outlined text-primary"
|
|
>cable</span
|
|
>
|
|
WebSocket (Logs en tiempo real)
|
|
</h2>
|
|
|
|
<div
|
|
class="mb-8 rounded-xl border border-[#283039] bg-[#161f2a] overflow-hidden"
|
|
>
|
|
<div
|
|
class="bg-[#1c2730] px-6 py-4 border-b border-[#283039]"
|
|
>
|
|
<div class="flex items-center gap-3">
|
|
<span
|
|
class="px-2 py-1 rounded bg-purple-500/20 text-purple-400 text-xs font-bold font-mono"
|
|
>WS</span
|
|
>
|
|
<code class="text-white font-mono text-sm"
|
|
>ws://localhost:8080/api/apps/:name/logs</code
|
|
>
|
|
</div>
|
|
<p class="text-[#9dabb9] text-sm mt-2">
|
|
Stream de logs en tiempo real desde journalctl
|
|
</p>
|
|
</div>
|
|
<div class="p-6 space-y-4">
|
|
<div>
|
|
<p
|
|
class="text-white font-semibold text-sm mb-2"
|
|
>
|
|
Ejemplo JavaScript
|
|
</p>
|
|
<pre
|
|
class="code-block bg-[#0a0f16] p-4 rounded-lg text-sm text-purple-400 overflow-x-auto"
|
|
>
|
|
const ws = new WebSocket('ws://localhost:8080/api/apps/mi-app/logs');
|
|
|
|
ws.onopen = () => {
|
|
console.log('Conectado a logs');
|
|
};
|
|
|
|
ws.onmessage = (event) => {
|
|
const log = JSON.parse(event.data);
|
|
console.log(log.MESSAGE);
|
|
};
|
|
|
|
ws.onerror = (error) => {
|
|
console.error('Error:', error);
|
|
};
|
|
|
|
ws.onclose = () => {
|
|
console.log('Desconectado');
|
|
};</pre
|
|
>
|
|
</div>
|
|
<div>
|
|
<p
|
|
class="text-white font-semibold text-sm mb-2"
|
|
>
|
|
Límites
|
|
</p>
|
|
<ul class="space-y-2">
|
|
<li class="flex items-start gap-2">
|
|
<span
|
|
class="material-symbols-outlined text-primary text-sm"
|
|
>check</span
|
|
>
|
|
<span class="text-[#9dabb9] text-sm"
|
|
>Máximo 5 conexiones concurrentes
|
|
por aplicación</span
|
|
>
|
|
</li>
|
|
<li class="flex items-start gap-2">
|
|
<span
|
|
class="material-symbols-outlined text-primary text-sm"
|
|
>check</span
|
|
>
|
|
<span class="text-[#9dabb9] text-sm"
|
|
>Formato JSON desde systemd
|
|
journalctl</span
|
|
>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Error Codes -->
|
|
<section id="errors" class="mb-12">
|
|
<h2
|
|
class="text-white text-2xl font-bold mb-6 flex items-center gap-2"
|
|
>
|
|
<span class="material-symbols-outlined text-primary"
|
|
>error</span
|
|
>
|
|
Códigos de Error
|
|
</h2>
|
|
|
|
<div class="space-y-4">
|
|
<div
|
|
class="rounded-xl border border-[#283039] bg-[#161f2a] p-4"
|
|
>
|
|
<div class="flex items-center gap-3 mb-2">
|
|
<span
|
|
class="px-2 py-1 rounded bg-red-500/20 text-red-400 text-xs font-bold font-mono"
|
|
>400</span
|
|
>
|
|
<p class="text-white font-semibold">
|
|
Bad Request
|
|
</p>
|
|
</div>
|
|
<p class="text-[#9dabb9] text-sm">
|
|
Datos de entrada inválidos o faltantes
|
|
</p>
|
|
</div>
|
|
|
|
<div
|
|
class="rounded-xl border border-[#283039] bg-[#161f2a] p-4"
|
|
>
|
|
<div class="flex items-center gap-3 mb-2">
|
|
<span
|
|
class="px-2 py-1 rounded bg-red-500/20 text-red-400 text-xs font-bold font-mono"
|
|
>404</span
|
|
>
|
|
<p class="text-white font-semibold">
|
|
Not Found
|
|
</p>
|
|
</div>
|
|
<p class="text-[#9dabb9] text-sm">
|
|
Aplicación no encontrada
|
|
</p>
|
|
</div>
|
|
|
|
<div
|
|
class="rounded-xl border border-[#283039] bg-[#161f2a] p-4"
|
|
>
|
|
<div class="flex items-center gap-3 mb-2">
|
|
<span
|
|
class="px-2 py-1 rounded bg-red-500/20 text-red-400 text-xs font-bold font-mono"
|
|
>429</span
|
|
>
|
|
<p class="text-white font-semibold">
|
|
Too Many Requests
|
|
</p>
|
|
</div>
|
|
<p class="text-[#9dabb9] text-sm">
|
|
Rate limit excedido (1 operación/segundo)
|
|
</p>
|
|
</div>
|
|
|
|
<div
|
|
class="rounded-xl border border-[#283039] bg-[#161f2a] p-4"
|
|
>
|
|
<div class="flex items-center gap-3 mb-2">
|
|
<span
|
|
class="px-2 py-1 rounded bg-red-500/20 text-red-400 text-xs font-bold font-mono"
|
|
>500</span
|
|
>
|
|
<p class="text-white font-semibold">
|
|
Internal Server Error
|
|
</p>
|
|
</div>
|
|
<p class="text-[#9dabb9] text-sm">
|
|
Error interno del servidor
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-6">
|
|
<p class="text-white font-semibold text-sm mb-2">
|
|
Estructura de error
|
|
</p>
|
|
<pre
|
|
class="code-block bg-[#0a0f16] p-4 rounded-lg text-sm text-red-400 overflow-x-auto"
|
|
>
|
|
{
|
|
"success": false,
|
|
"data": null,
|
|
"error": "Descripción del error"
|
|
}</pre
|
|
>
|
|
</div>
|
|
</section>
|
|
</main>
|
|
</div>
|
|
|
|
<script>
|
|
async function tryEndpoint(method, path) {
|
|
const resultDiv =
|
|
event.target.parentElement.querySelector(".result") ||
|
|
event.target.parentElement.appendChild(
|
|
document.createElement("div"),
|
|
);
|
|
resultDiv.className =
|
|
"result mt-4 code-block bg-[#0a0f16] p-4 rounded-lg text-sm overflow-x-auto";
|
|
resultDiv.textContent = "Ejecutando...";
|
|
|
|
try {
|
|
const response = await fetch(path, {
|
|
method: method,
|
|
});
|
|
const data = await response.json();
|
|
resultDiv.innerHTML = `<pre class="text-green-400">${JSON.stringify(data, null, 2)}</pre>`;
|
|
} catch (error) {
|
|
resultDiv.innerHTML = `<pre class="text-red-400">Error: ${error.message}</pre>`;
|
|
}
|
|
}
|
|
|
|
// Smooth scroll for anchor links
|
|
document.querySelectorAll('a[href^="#"]').forEach((anchor) => {
|
|
anchor.addEventListener("click", function (e) {
|
|
e.preventDefault();
|
|
const target = document.querySelector(
|
|
this.getAttribute("href"),
|
|
);
|
|
if (target) {
|
|
target.scrollIntoView({
|
|
behavior: "smooth",
|
|
block: "start",
|
|
});
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|