Decisiones de Diseño Arquitectónico
Esta página explica el razonamiento detrás de las principales elecciones tecnológicas y de arquitectura en PgArachne. Estas decisiones se tomaron para priorizar el rendimiento, la seguridad y la productividad del desarrollador, asegurando al mismo tiempo una alta compatibilidad con agentes de IA y modelos LLM modernos.
1. JSON-RPC 2.0 frente a REST
PgArachne utiliza JSON-RPC 2.0 como su protocolo de comunicación principal en lugar del tradicional REST.
Por qué JSON-RPC 2.0:
- Endpoint Único: Toda la comunicación ocurre a través de
POST /{prefijo}/{base_de_datos}/jsonrpc. No es necesario diseñar estructuras de URL complejas ni debatir sobre la semántica de los verbos HTTP. - Llamadas Autocontenidas: Cada petición es un objeto JSON completo (método + parámetros + id). Este formato es trivial de generar y parsear para LLMs y agentes de IA con alta fiabilidad.
- Gestión de Errores Estandarizada: Los códigos y mensajes de error forman parte de la especificación, eliminando la necesidad de „inventar" convenciones de códigos de estado HTTP para errores de negocio.
- Loteado (Batching): El protocolo admite nativamente peticiones por lotes, lo que permite múltiples operaciones en un solo viaje de ida y vuelta HTTP sin trabajo extra.
- Descubrimiento (Discovery): El endpoint de capacidades proporciona una descripción completa de la API en un formato que los agentes de IA pueden consumir para entender las herramientas disponibles sin alucinaciones.
Por qué no REST:
- Complejidad para la IA: La semántica de REST está dispersa en varios lugares, lo que dificulta que los agentes de IA construyan llamadas de forma fiable.
- Fuga de Esquema: El CRUD sobre tablas a menudo filtra la estructura interna de la base de datos directamente a través de la API. PgArachne expone funciones deliberadamente, manteniendo la lógica de negocio encapsulada en SQL.
- Falta de Estándares: REST no ofrece un estándar universal para operaciones por lotes, envoltorios de errores multiplataforma o descubrimiento automático de API.
2. SSE (Server-Sent Events) frente a WebSockets
Para las notificaciones en tiempo real, PgArachne implementa Server-Sent Events (SSE).
Por qué SSE:
- HTTP Puro: SSE es HTTP estándar. Funciona a través de proxies, balanceadores de carga y CDNs sin configuraciones especiales.
- Soporte Nativo del Navegador: La API
EventSourceestá integrada en todos los navegadores modernos y gestiona la reconexión automática sin librerías externas. - Coincide con la Semántica de NOTIFY: El comando
NOTIFYde PostgreSQL es unidireccional (servidor a cliente), lo que encaja perfectamente con SSE. - Multiplexación: Sobre HTTP/2, cientos de flujos SSE pueden compartir una única conexión TCP, lo que lo hace extremadamente eficiente.
- Simplicidad Operativa: Las conexiones SSE aparecen como peticiones HTTP normales en los logs y herramientas de monitorización.
Por qué no WebSockets:
- Bidireccionalidad Innecesaria: El cliente nunca necesita enviar datos de vuelta por el canal de notificaciones, por lo que la complejidad de WebSockets no aporta ningún beneficio.
- Problemas de Conectividad: Los WebSockets a menudo son bloqueados por firewalls corporativos y algunos balanceadores de carga en la nube.
- Mayor Sobrecarga: Añade complejidad al protocolo que no es necesaria para el simple streaming de eventos.
3. Go frente a Alternativas
PgArachne está escrito en Go para ofrecer el mejor equilibrio entre rendimiento y simplicidad de despliegue.
Por qué Go:
- Binarios Estáticos: Se compila en un único archivo ejecutable sin dependencias externas.
- Concurrencia: Las goroutines de Go hacen que el manejo de miles de conexiones SSE y de base de datos simultáneas sea ligero y directo.
- Biblioteca Estándar Robusta: Las librerías integradas para HTTP, TLS y JSON son de grado de producción.
- Compilación Cruzada: Genera fácilmente binarios para Linux, macOS y Windows (amd64 y arm64).
Por qué no Node.js, PHP o Ruby:
- Entornos de Ejecución: Requieren instalar un entorno específico en cada máquina de destino.
- Eficiencia: Son menos eficientes para mantener miles de conexiones SSE inactivas.
- Huella de Memoria: Go utiliza significativamente menos memoria por conexión.
Por qué no Rust:
- Velocidad de Desarrollo: Su complejidad (borrow checker) ralentiza la iteración para una herramienta orientada a I/O donde el rendimiento de Go ya es más que suficiente.
Por qué no C/C++:
- Seguridad: El manejo manual de la memoria añade riesgos significativos sin una ganancia de rendimiento relevante en una aplicación de pasarela.
4. Funciones de PostgreSQL como Superficie de API
PgArachne expone deliberadamente funciones de base de datos en lugar de tablas puras.
Por qué funciones:
- Encapsulamiento: La lógica de negocio reside junto con los datos en la base de datos: un único lugar para auditar, versionar y asegurar.
- Seguridad Explícita: Solo las funciones a las que se les ha otorgado explícitamente permisos
EXECUTEpara un rol específico son accesibles a través de la API. - Abstracción: La validación de entradas, los campos calculados y las operaciones complejas están ocultos para el cliente, proporcionando una interfaz limpia.
Por qué no CRUD a nivel de tabla:
- Acoplamiento Estrecho: Exponer las tablas directamente vincula tu API a tu esquema interno de base de datos.
- Fragmentación de Reglas de Negocio: La lógica termina dividida entre las restricciones de la base de datos y cualquier middleware.
5. Estructura de URL: /{prefijo}/{base_de_datos}/{endpoint}
PgArachne enruta todos los endpoints bajo un segmento de prefijo configurable:
/db/{base_de_datos}/jsonrpc, /db/{base_de_datos}/sse, /db/{base_de_datos}/mcp.
El prefijo por defecto es db y puede cambiarse mediante API_PREFIX.
Por qué esta estructura:
- Enrutamiento por reverse proxy: Un único servidor PgArachne puede servir múltiples bases de datos. Un reverse proxy puede enrutar por prefijo o nombre de base de datos sin inspeccionar el cuerpo de la petición, lo que es clave para el balanceo de carga.
- Escalabilidad horizontal: Con el nombre de la base de datos en la ruta URL, se pueden ejecutar múltiples instancias de PgArachne y dirigir el tráfico a instancias específicas usando reglas de proxy estándar, sin sesiones persistentes.
- Multiplexado de protocolos por base de datos: Agrupar
/jsonrpc,/ssey/mcpbajo el mismo espacio de nombres permite aplicar autenticación, rate limiting y control de acceso por base de datos a nivel de proxy. - Prefijo configurable: Los despliegues que ya usan
/api/pueden configurarAPI_PREFIX=api. Los clientes legacy son compatibles mediante307 Temporary Redirect. - Observabilidad: Los sistemas de logs y métricas pueden agrupar y filtrar el tráfico por nombre de base de datos directamente desde la URL sin parsear cuerpos JSON.
Por qué no una estructura plana como /api/{base_de_datos}:
- Ambigüedad de protocolo: Un único endpoint plano no puede distinguir entre tráfico JSON-RPC, SSE y MCP a nivel de enrutamiento.
- Más difícil de extender: Añadir nuevos protocolos requeriría de todas formas nuevas rutas, por lo que el espacio de nombres estructurado prepara el diseño para el futuro.
6. MCP como Capa de Traducción, no como Protocolo de Base de Datos
PgArachne implementa el Model Context Protocol (MCP)
como una capa de traducción delgada en el servidor Go. Las funciones de PostgreSQL nunca saben de MCP —
siguen siendo simples funciones jsonb → json.
Por qué traducir MCP en el servidor:
- Sin cambios en funciones existentes: Cualquier función ya expuesta vía JSON-RPC está disponible instantáneamente como herramienta MCP. Sin cambios SQL ni redistribución de objetos de base de datos.
- MCP es más que solo herramientas: El protocolo incluye el handshake de inicialización, ping, notificaciones y posibles extensiones futuras. Estas son preocupaciones de nivel de protocolo que pertenecen a Go, no a funciones SQL.
- La seguridad permanece en un lugar: La autenticación, el cambio de rol y la validación de entradas ya están implementados en Go. El endpoint MCP reutiliza esta lógica sin cambios.
- Múltiples protocolos, un backend: La misma función PostgreSQL puede llamarse vía JSON-RPC, MCP o SSE. La base de datos es agnóstica al protocolo.
- SQL más simple: Procesar envoltorios MCP dentro de funciones PostgreSQL requeriría parsear estructuras JSON complejas en PL/pgSQL, haciendo las funciones más difíciles de escribir y mantener.
Por qué no llevar MCP a la base de datos:
- El handshake MCP no necesita base de datos:
initializeypingson mensajes de protocolo puros. Abrir una conexión de base de datos para ellos desperdicia recursos y aumenta la latencia. - SQL es la herramienta equivocada para la lógica de protocolo: Los códigos de error JSON-RPC 2.0, el enrutamiento de notificaciones y la gestión de claves de idempotencia son preocupaciones de middleware, no de datos.