Decisões de Design Arquitetônico
Esta página explica o raciocínio por trás das principais escolhas tecnológicas e arquiteturais do PgArachne. Estas decisões foram tomadas para priorizar performance, segurança e produtividade do desenvolvedor, garantindo ao mesmo tempo uma alta compatibilidade com agentes de IA e modelos LLM modernos.
1. JSON-RPC 2.0 vs. REST
O PgArachne utiliza JSON-RPC 2.0 como seu protocolo de comunicação primário em vez do tradicional REST.
Por que JSON-RPC 2.0:
- Endpoint Único: Toda a comunicação ocorre via
POST /{prefixo}/{banco_de_dados}/jsonrpc. Não há necessidade de projetar estruturas de URL complexas. - Chamadas Autocontidas: Cada requisição é um objeto JSON completo (método + parâmetros + id), fácil de gerar e processar para LLMs.
- Tratamento de Erros Padronizado: Códigos e mensagens de erro fazem parte da especificação.
- Loteamento (Batching): O protocolo suporta nativamente requisições em lote em uma única viagem de ida e volta HTTP.
- Descoberta (Discovery): O endpoint de capacidades fornece uma descrição completa da API para agentes de IA sem alucinações.
Por que não REST:
- Complexidade para IA: A semântica REST está dispersa em vários lugares, dificultando a construção de chamadas confiáveis para agentes de IA.
- Exposição do Esquema: O CRUD sobre tabelas muitas vezes expõe a estrutura interna. O PgArachne expõe funções deliberadamente.
- Ausência de Padrões: O REST não oferece padrão universal para lotes, envelopes de erro ou descoberta automatizada.
2. SSE (Server-Sent Events) vs. WebSockets
Para notificações em tempo real, o PgArachne implementa Server-Sent Events (SSE).
Por que SSE:
- HTTP Puro: O SSE é HTTP padrão, funcionando através de proxies e CDNs sem configurações especiais.
- Suporte Nativo do Navegador: A API
EventSourcegerencia a reconexão automática sem bibliotecas externas. - Corresponde à Semântica do NOTIFY:
NOTIFYdo PostgreSQL é unidirecional, ajustando-se perfeitamente ao SSE. - Multiplexação: Sobre o HTTP/2, centenas de fluxos SSE compartilham uma única conexão TCP.
- Simplicidade Operacional: As conexões SSE aparecem como requisições HTTP normais nos logs.
Por que não WebSockets:
- Bidirecionalidade Desnecessária: O cliente nunca precisa enviar dados pelo canal de notificação.
- Problemas de Conectividade: Frequentemente bloqueados por firewalls corporativos e alguns balanceadores de carga em nuvem.
- Maior Sobrecarga: Handshakes e frames de ping/pong desnecessários para o simples streaming de eventos.
3. Go vs. Alternativas
O PgArachne é escrito em Go para oferecer o melhor equilíbrio entre performance e simplicidade de implantação.
Por que Go:
- Binários Estáticos: Um único arquivo executável sem dependências externas.
- Concorrência: As goroutines gerenciam milhares de conexões simultâneas de forma leve.
- Biblioteca Padrão Robusta: HTTP, TLS e JSON integrados, de nível de produção.
- Compilação Cruzada: Linux, macOS e Windows (amd64 e arm64) a partir de qualquer máquina.
Por que não Node.js, PHP ou Ruby:
- Runtimes: Requerem a instalação de um ambiente específico em cada máquina de destino.
- Eficiência: Menos eficientes para manter milhares de conexões SSE inativas.
- Consumo de Memória: O Go utiliza significativamente menos memória por conexão.
Por que não Rust:
- Velocidade de Desenvolvimento: Sua complexidade retarda a iteração para uma ferramenta I/O onde o Go já é suficiente.
Por que não C/C++:
- Segurança: O gerenciamento manual de memória adiciona riscos sem ganhos relevantes em uma aplicação de gateway.
4. Funções PostgreSQL como Superfície da API
O PgArachne expõe deliberadamente funções do banco de dados em vez de tabelas puras.
Por que funções:
- Encapsulamento: A lógica de negócio reside com os dados no banco de dados — um único lugar para auditoria, versionamento e segurança.
- Segurança Explícita: Apenas as funções com permissões
EXECUTEpara um papel específico são acessíveis. - Abstração: Validação, campos calculados e operações complexas ficam ocultos para o cliente.
Por que não CRUD em nível de tabela:
- Acoplamento Forte: Expor tabelas vincula a API ao esquema interno, dificultando refatorações.
- Fragmentação de Regras de Negócio: A lógica se divide entre restrições do banco de dados e middleware.
5. Estrutura de URL: /{prefixo}/{banco_de_dados}/{endpoint}
O PgArachne roteia todos os endpoints sob um segmento de prefixo configurável:
/db/{banco_de_dados}/jsonrpc, /db/{banco_de_dados}/sse, /db/{banco_de_dados}/mcp.
O prefixo padrão é db e pode ser alterado via API_PREFIX.
Por que esta estrutura:
- Roteamento por reverse proxy: Uma única instância PgArachne pode servir múltiplos bancos de dados. Um reverse proxy pode rotear por prefixo ou nome do banco de dados sem inspecionar o corpo da requisição, essencial para balanceamento de carga.
- Escalabilidade horizontal: Com o nome do banco de dados no caminho URL, é possível executar múltiplas instâncias PgArachne e direcionar o tráfego por banco de dados usando regras de proxy padrão, sem sessões persistentes.
- Multiplexação de protocolos por banco de dados: Agrupar
/jsonrpc,/ssee/mcpsob o mesmo namespace permite aplicar autenticação, rate limiting e controle de acesso por banco de dados no nível do proxy. - Prefixo configurável: Deployments que já usam
/api/podem configurarAPI_PREFIX=api. Clientes legados são suportados via307 Temporary Redirect. - Observabilidade: Sistemas de log e métricas podem agrupar o tráfego por nome de banco de dados diretamente da URL sem analisar corpos JSON.
Por que não uma estrutura plana como /api/{banco_de_dados}:
- Ambiguidade de protocolo: Um único endpoint plano não consegue distinguir o tráfego JSON-RPC, SSE e MCP no nível de roteamento.
- Mais difícil de estender: Adicionar novos protocolos exigiria de qualquer forma novas rotas, portanto o namespace estruturado prepara o design para o futuro.
6. MCP como Camada de Tradução, não como Protocolo de Banco de Dados
O PgArachne implementa o Model Context Protocol (MCP)
como uma fina camada de tradução no servidor Go. As funções PostgreSQL nunca sabem do MCP —
permanecem simples funções jsonb → json.
Por que traduzir MCP no servidor:
- Sem alterações nas funções existentes: Qualquer função já exposta via JSON-RPC está instantaneamente disponível como tool MCP. Sem alterações SQL.
- MCP é mais do que apenas tools: O protocolo inclui o handshake de inicialização, ping, notificações e extensões futuras — preocupações de nível de protocolo que pertencem ao Go.
- A segurança permanece em um único lugar: Autenticação, troca de papel e validação já estão implementados em Go. O endpoint MCP reutiliza essa lógica sem alterações.
- Múltiplos protocolos, um backend: A mesma função PostgreSQL pode ser chamada via JSON-RPC, MCP ou SSE. O banco de dados é agnóstico ao protocolo.
- SQL mais simples: Processar envelopes MCP em PostgreSQL exigiria analisar estruturas JSON complexas em PL/pgSQL, tornando as funções mais difíceis de escrever e manter.
Por que não levar MCP ao banco de dados:
- O handshake MCP não precisa do banco de dados:
initializeepingsão mensagens de protocolo puras. Abrir uma conexão para elas desperdiça recursos. - SQL é a ferramenta errada para lógica de protocolo: Códigos de erro JSON-RPC, roteamento de notificações e gerenciamento de chaves de idempotência são preocupações de middleware, não de dados.