6 min čtení

Architektonická designová rozhodnutí

Tato stránka vysvětluje důvody klíčových architektonických a technologických voleb v projektu PgArachne. Tato rozhodnutí byla učiněna s ohledem na výkon, bezpečnost a produktivitu vývojářů, přičemž byl kladen důraz na vysokou kompatibilitu s moderními AI agenty a LLM modely.

1. JSON-RPC 2.0 vs. REST

PgArachne používá JSON-RPC 2.0 jako primární komunikační protokol místo tradičního RESTu.

Proč JSON-RPC 2.0:

  • Jeden koncový bod (endpoint): Veškerá komunikace probíhá přes POST /{prefix}/{databaze}/jsonrpc. Není třeba navrhovat složité struktury URL ani debatovat o sémantice HTTP metod.
  • Samostatné požadavky: Každý požadavek je kompletní JSON objekt (metoda + parametry + id). Tento formát je pro LLM a AI agenty snadno generovatelný a parsovatelný s vysokou spolehlivostí.
  • Standardizované zpracování chyb: Chybové kódy a zprávy jsou součástí specifikace, což eliminuje potřebu „vymýšlet" konvence HTTP stavových kódů pro byznysové chyby.
  • Dávkové požadavky (batching): Protokol nativně podporuje dávkové požadavky, což umožňuje provést více operací během jediného HTTP dotazu bez dodatečné práce.
  • Objevování (discovery): Endpoint capabilities poskytuje úplný popis API ve formátu, který AI agenti dokáží konzumovat a porozumět dostupným nástrojům bez halucinací.

Proč ne REST:

  • Složitost pro AI: Sémantika RESTu (GET/POST/PATCH/DELETE + parametry v URL + tělo požadavku) je rozprostřena na více místech, což AI agentům ztěžuje spolehlivé sestavení volání.
  • Únik schématu: CRUD nad tabulkami (styl PostgREST) často přímo odhaluje interní strukturu databáze. PgArachne záměrně vystavuje funkce, čímž udržuje byznysovou logiku zapouzdřenou v SQL.
  • Chybějící standardy: REST nenabízí žádný univerzální standard pro dávkové operace, křížové chybové obálky ani automatizované objevování API.

2. SSE (Server-Sent Events) vs. WebSockets

Pro real-time notifikace implementuje PgArachne Server-Sent Events (SSE).

Proč SSE:

  • Čisté HTTP: SSE je běžný HTTP protokol. Funguje přes proxy servery, load balancery a CDN bez speciální konfigurace „protocol upgrade".
  • Nativní podpora v prohlížeči: Rozhraní EventSource je vestavěné ve všech moderních prohlížečích a automaticky řeší znovupřipojení bez nutnosti externích knihoven.
  • Odpovídá sémantice NOTIFY: PostgreSQL příkaz NOTIFY je jednosměrný (server → klient), což přesně odpovídá charakteru SSE.
  • Multiplexování: Přes HTTP/2 mohou stovky SSE proudů sdílet jediné TCP spojení, což je extrémně efektivní.
  • Provozní jednoduchost: SSE spojení se v logách a monitorovacích nástrojích jeví jako běžné HTTP požadavky, což usnadňuje ladění a omezování provozu (rate limiting).

Proč ne WebSockets:

  • Zbytečná obousměrnost: Protože klient nikdy nepotřebuje posílat data zpět přes notifikační kanál, složitost WebSockets nepřináší žádný užitek.
  • Problémy s konektivitou: WebSockets jsou často blokovány nebo předčasně ukončovány korporátními firewally a některými cloudovými load balancery.
  • Vyšší režie: Přidává protokolární složitost (handshaky, ping/pong rámce), která není pro jednoduché streamování událostí nutná.

3. Go vs. alternativy

PgArachne je napsán v jazyce Go, aby poskytoval nejlepší rovnováhu mezi výkonem a jednoduchostí nasazení.

Proč Go:

  • Statické binární soubory: Kompiluje se do jediného souboru bez externích závislostí. Nasazení je tak prosté jako zkopírování souboru na server.
  • Konkurence (concurrency): Gorutiny v Go dělají obsluhu tisíců souběžných SSE a databázových připojení lehkou a přímočarou.
  • Robustní standardní knihovna: Vestavěné knihovny pro HTTP, TLS a JSON jsou na produkční úrovni a nevyžadují žádné „node_modules" ani externí runtime prostředí.
  • Křížová kompilace: Snadno cílí na Linux, macOS i Windows (amd64 i arm64) z jakéhokoli vývojářského stroje.

Proč ne Node.js, PHP nebo Ruby:

  • Runtime prostředí: Tyto jazyky vyžadují instalaci specifického prostředí na každém cílovém stroji.
  • Efektivita: Single-threaded loop v Node.js nebo model process-per-request v PHP jsou méně efektivní pro udržování tisíců neaktivních SSE připojení.
  • Paměťová stopa: Go využívá výrazně méně paměti na jedno připojení než skriptovací jazyky.

Proč ne Rust:

  • Rychlost vývoje: Zatímco Rust nabízí extrémní výkon, jeho složitost (borrow checker) zpomaluje iterace u nástroje zaměřeného na I/O, kde je výkon Go již více než dostatečný.

Proč ne C/C++:

  • Bezpečnost: Manuální správa paměti přináší značná bezpečnostní rizika (přetečení bufferu) bez reálného přínosu k výkonu v aplikaci typu gateway.

4. PostgreSQL funkce jako API rozhraní

PgArachne záměrně vystavuje databázové funkce namísto přímého přístupu k tabulkám.

Proč funkce:

  • Zapouzdření: Byznysová logika žije společně s daty v databázi – na jednom místě pro audit, verzování i zabezpečení.
  • Explicitní bezpečnost: Přes API jsou dostupné pouze funkce, kterým bylo explicitně uděleno oprávnění EXECUTE pro konkrétní roli.
  • Abstrakce: Validace vstupů, vypočtená pole a složité operace nad více tabulkami jsou před klientem skryty, což poskytuje čisté rozhraní.

Proč ne CRUD na úrovni tabulek:

  • Těsná vazba: Přímé vystavení tabulek váže vaše API na interní schéma databáze, což ztěžuje refaktorování databáze bez rozbití klientských aplikací.
  • Roztříštěnost byznysových pravidel: Logika pak končí rozdělená mezi databázová omezení a jakýkoli middleware použitý k filtrování HTTP požadavků.

5. Struktura URL: /{prefix}/{databaze}/{endpoint}

PgArachne směruje všechny endpointy pod konfigurovatelný prefixový segment: /db/{databaze}/jsonrpc, /db/{databaze}/sse, /db/{databaze}/mcp. Výchozí prefix je db a lze ho změnit přes proměnnou API_PREFIX.

Proč tato struktura:

  • Směrování přes reverse proxy: Jedna instance PgArachne může obsluhovat více databází. Reverse proxy (Nginx, Caddy, Traefik) může směrovat podle prefixu nebo názvu databáze bez nutnosti inspekce těla požadavku, což je klíčové pro load balancing a path-based pravidla.
  • Horizontální škálovatelnost: S názvem databáze v URL cestě lze provozovat více instancí PgArachne a směrovat provoz do konkrétních instancí podle databáze pomocí standardních proxy pravidel — bez sticky sessions nebo inspekce těla.
  • Multiplexování protokolů na databázi: Seskupení /jsonrpc, /sse a /mcp pod stejný jmenný prostor /{prefix}/{databaze}/ umožňuje přirozeně aplikovat per-databázové ověřování, rate limiting a řízení přístupu na úrovni proxy.
  • Konfigurovatelný prefix: Nasazení, která již používají /api/ jako prefix ve své infrastruktuře, mohou nastavit API_PREFIX=api. Starší klienti jsou podporováni přes 307 Temporary Redirect ze starých cest.
  • Pozorovatelnost: Agregátory logů a metrické systémy mohou seskupovat a filtrovat provoz podle názvu databáze přímo z URL bez parsování JSON těl.

Proč ne plochá struktura jako /api/{databaze}:

  • Nejednoznačnost protokolu: Jeden plochý endpoint nedokáže rozlišit provoz JSON-RPC, SSE a MCP na úrovni směrování — toto rozhodnutí by padlo do aplikační logiky nebo inspekce hlaviček.
  • Obtížnější rozšíření: Přidání nových protokolů (např. GraphQL, gRPC-gateway) by stejně vyžadovalo zavedení nových cest nejvyšší úrovně, takže strukturovaný jmenný prostor design dopředu připravuje.

6. MCP jako překladová vrstva, nikoli databázový protokol

PgArachne implementuje Model Context Protocol (MCP) jako tenkou překladovou vrstvu v Go serveru. PostgreSQL funkce o MCP nikdy nevědí — zůstávají jednoduchými funkcemi jsonb → json.

Proč překládat MCP na serveru:

  • Žádné změny existujících funkcí: Jakákoli funkce již vystavená přes JSON-RPC je okamžitě dostupná jako MCP nástroj. Žádné SQL změny, žádné přenasazení databázových objektů.
  • MCP je víc než jen nástroje: Protokol zahrnuje inicializační handshake, ping, notifikace a potenciální budoucí rozšíření (resources, prompts, sampling). To jsou obavy na úrovni protokolu, které patří do Go, ne do SQL funkcí.
  • Bezpečnost zůstává na jednom místě: Autentizace, přepínání rolí a validace vstupů jsou již implementovány v Go. MCP endpoint tuto logiku používá beze změny.
  • Více protokolů, jeden backend: Stejnou PostgreSQL funkci lze volat přes JSON-RPC (z běžného klienta), MCP (z Claude Desktop nebo Cursor) nebo sledovat přes SSE. Databáze je protokolově neutrální.
  • Jednodušší SQL: Zpracování MCP obálek (initialize, tools/list, obsluha notifikací) uvnitř PostgreSQL funkcí by vyžadovalo parsování složitých JSON struktur v PL/pgSQL, čímž by funkce byly obtížněji psatelné, testovatelné a udržovatelné.

Proč netlačit MCP do databáze:

  • MCP handshake nepotřebuje databázi: initialize a ping jsou čisté protokolové zprávy. Otevírání databázového připojení pro ně plýtvá zdroji a přidává latenci.
  • SQL není správný nástroj pro protokolovou logiku: Chybové kódy JSON-RPC 2.0, směrování notifikací a správa idempotency klíčů jsou middleware záležitosti, nikoli datové záležitosti.