6 min de lecture

Décisions de Conception Architecturale

Cette page explique le raisonnement derrière les choix technologiques et architecturaux clés de PgArachne. Ces décisions ont été prises pour donner la priorité aux performances, à la sécurité et à la productivité des développeurs, tout en assurant une haute compatibilité avec les agents d’IA et les modèles LLM modernes.

1. JSON-RPC 2.0 vs REST

PgArachne utilise JSON-RPC 2.0 comme protocole de communication principal au lieu du traditionnel REST.

Pourquoi JSON-RPC 2.0 :

  • Endpoint Unique : Toute la communication passe par POST /{prefixe}/{base_de_donnees}/jsonrpc. Il n’est pas nécessaire de concevoir des structures d’URL complexes.
  • Appels Auto-contenus : Chaque requête est un objet JSON complet (méthode + paramètres + id), facile à générer et à analyser pour les LLM.
  • Gestion des Erreurs Standardisée : Les codes et messages d’erreur font partie de la spécification.
  • Lotissement (Batching) : Le protocole prend nativement en charge les requêtes par lots en un seul aller-retour HTTP.
  • Découverte (Discovery) : L’endpoint de capacités fournit une description complète de l’API pour les agents d’IA sans hallucinations.

Pourquoi pas REST :

  • Complexité pour l’IA : La sémantique REST est dispersée à plusieurs endroits, rendant difficile la construction d’appels fiables pour les agents d’IA.
  • Fuite de Schéma : Le CRUD sur tables expose souvent la structure interne. PgArachne expose délibérément des fonctions.
  • Absence de Standards : REST n’offre pas de standard universel pour les lots, les enveloppes d’erreurs ou la découverte automatisée.

2. SSE (Server-Sent Events) vs WebSockets

Pour les notifications en temps réel, PgArachne implémente les Server-Sent Events (SSE).

Pourquoi SSE :

  • HTTP Pur : SSE est du HTTP standard, fonctionnant à travers les proxys et CDNs sans configuration spéciale.
  • Support Natif du Navigateur : L’API EventSource gère la reconnexion automatique sans bibliothèques externes.
  • Correspond à la Sémantique NOTIFY : NOTIFY de PostgreSQL est unidirectionnel, ce qui correspond parfaitement au SSE.
  • Multiplexage : Sur HTTP/2, des centaines de flux SSE partagent une seule connexion TCP.
  • Simplicité Opérationnelle : Les connexions SSE apparaissent comme des requêtes HTTP normales dans les logs.

Pourquoi pas WebSockets :

  • Bidirectionnalité Inutile : Le client n’envoie jamais de données via le canal de notification.
  • Problèmes de Connectivité : Souvent bloqués par les pare-feux d’entreprise et certains équilibreurs de charge cloud.
  • Surcharge Plus Élevée : Handshakes et trames ping/pong inutiles pour le simple streaming d’événements.

3. Go vs Alternatives

PgArachne est écrit en Go pour offrir le meilleur équilibre entre performances et simplicité de déploiement.

Pourquoi Go :

  • Binaires Statiques : Un seul fichier exécutable sans dépendances externes.
  • Concurrence : Les goroutines gèrent des milliers de connexions simultanées légèrement.
  • Bibliothèque Standard Robuste : HTTP, TLS et JSON intégrés, de qualité production.
  • Compilation Croisée : Linux, macOS et Windows (amd64 et arm64) depuis n’importe quelle machine.

Pourquoi pas Node.js, PHP ou Ruby :

  • Runtimes : Nécessitent un environnement d’exécution spécifique sur chaque machine cible.
  • Efficacité : Moins efficaces pour des milliers de connexions SSE inactives.
  • Empreinte Mémoire : Go utilise beaucoup moins de mémoire par connexion.

Pourquoi pas Rust :

  • Vitesse de Développement : Sa complexité ralentit l’itération pour un outil I/O où Go est déjà suffisant.

Pourquoi pas C/C++ :

  • Sécurité : La gestion manuelle de la mémoire ajoute des risques sans gain réel dans une application de passerelle.

4. Fonctions PostgreSQL comme Surface d’API

PgArachne expose délibérément des fonctions de base de données plutôt que des tables brutes.

Pourquoi les fonctions :

  • Encapsulation : La logique métier réside avec les données dans la base de données — un seul endroit pour auditer, versionner et sécuriser.
  • Sécurité Explicite : Seules les fonctions avec permissions EXECUTE pour un rôle spécifique sont accessibles.
  • Abstraction : Validation, champs calculés et opérations complexes sont masqués pour le client.

Pourquoi pas de CRUD au niveau des tables :

  • Couplage Fort : Expose le schéma interne, rendant la refactorisation difficile sans casser les clients.
  • Fragmentation des Règles Métier : La logique se retrouve divisée entre contraintes de base de données et middleware.

5. Structure d’URL : /{prefixe}/{base_de_donnees}/{endpoint}

PgArachne route tous les endpoints sous un segment de préfixe configurable : /db/{base_de_donnees}/jsonrpc, /db/{base_de_donnees}/sse, /db/{base_de_donnees}/mcp. Le préfixe par défaut est db et peut être changé via API_PREFIX.

Pourquoi cette structure :

  • Routage par reverse proxy : Un seul serveur PgArachne peut servir plusieurs bases de données. Un reverse proxy peut router par préfixe ou nom de base de données sans inspecter le corps de la requête, ce qui est essentiel pour l’équilibrage de charge.
  • Scalabilité horizontale : Avec le nom de base de données dans le chemin URL, plusieurs instances PgArachne peuvent être déployées et le trafic dirigé par base de données via des règles de proxy standard, sans sessions persistantes.
  • Multiplexage de protocoles par base de données : Regrouper /jsonrpc, /sse et /mcp sous le même espace de noms permet d’appliquer l’authentification, le rate limiting et le contrôle d’accès par base de données au niveau du proxy.
  • Préfixe configurable : Les déploiements utilisant déjà /api/ peuvent configurer API_PREFIX=api. Les clients legacy sont supportés via 307 Temporary Redirect.
  • Observabilité : Les systèmes de logs et de métriques peuvent grouper le trafic par nom de base de données directement depuis l’URL sans parser les corps JSON.

Pourquoi pas une structure plate comme /api/{base_de_donnees} :

  • Ambiguïté de protocole : Un endpoint plat unique ne peut pas distinguer le trafic JSON-RPC, SSE et MCP au niveau du routage.
  • Plus difficile à étendre : L’ajout de nouveaux protocoles nécessiterait de toute façon de nouvelles routes, donc l’espace de noms structuré prépare la conception pour l’avenir.

6. MCP comme Couche de Traduction, pas comme Protocole de Base de Données

PgArachne implémente le Model Context Protocol (MCP) comme une couche de traduction mince dans le serveur Go. Les fonctions PostgreSQL ne connaissent jamais MCP — elles restent de simples fonctions jsonb → json.

Pourquoi traduire MCP sur le serveur :

  • Aucun changement aux fonctions existantes : Toute fonction déjà exposée via JSON-RPC est instantanément disponible comme outil MCP. Aucun changement SQL.
  • MCP est plus que des outils : Le protocole inclut le handshake d’initialisation, ping, notifications et extensions futures — des préoccupations de niveau protocole qui appartiennent à Go.
  • La sécurité reste en un seul endroit : Authentification, changement de rôle et validation sont déjà implémentés en Go. L’endpoint MCP réutilise cette logique inchangée.
  • Plusieurs protocoles, un backend : La même fonction PostgreSQL peut être appelée via JSON-RPC, MCP ou SSE. La base de données est agnostique au protocole.
  • SQL plus simple : Traiter les enveloppes MCP dans PostgreSQL nécessiterait de parser des structures JSON complexes en PL/pgSQL, rendant les fonctions plus difficiles à écrire et maintenir.

Pourquoi ne pas pousser MCP dans la base de données :

  • Le handshake MCP ne nécessite pas de base de données : initialize et ping sont des messages de protocole purs. Ouvrir une connexion pour eux gaspille des ressources.
  • SQL est le mauvais outil pour la logique de protocole : Les codes d’erreur JSON-RPC, le routage des notifications et la gestion des clés d’idempotence sont des préoccupations middleware, pas des préoccupations de données.