Αρχιτεκτονικές Αποφάσεις

7 λεπτά ανάγνωσης

Αποφάσεις Αρχιτεκτονικού Σχεδιασμού

Αυτή η σελίδα εξηγεί τη λογική πίσω από τις βασικές αρχιτεκτονικές και τεχνολογικές επιλογές στο PgArachne. Αυτές οι αποφάσεις ελήφθησαν με προτεραιότητα στην απόδοση, την ασφάλεια και την παραγωγικότητα των developers, εξασφαλίζοντας παράλληλα ότι το σύστημα παραμένει πλήρως συμβατό με σύγχρονους AI και LLM agents.

1. JSON-RPC 2.0 έναντι REST

Το PgArachne χρησιμοποιεί το JSON-RPC 2.0 ως το κύριο πρωτόκολλο επικοινωνίας του, αντί για το παραδοσιακό REST.

Γιατί JSON-RPC 2.0:

  • Ένα Μόνο Endpoint: Όλη η επικοινωνία γίνεται μέσω POST /{prefix}/{database}/jsonrpc. Δεν υπάρχει ανάγκη σχεδιασμού πολύπλοκων δομών URL ή συζήτησης σχετικά με τη σημασιολογία των HTTP verbs.
  • Αυτοτελείς Κλήσεις: Κάθε request είναι ένα πλήρες JSON object (method + params + id). Αυτή η μορφή παράγεται και αναλύεται εύκολα από LLMs και AI agents με υψηλή αξιοπιστία.
  • Τυποποιημένη Διαχείριση Σφαλμάτων: Οι κωδικοί και τα μηνύματα σφάλματος αποτελούν μέρος της προδιαγραφής, εξαλείφοντας την ανάγκη να «εφευρίσκετε» συμβάσεις HTTP status codes για επιχειρησιακά σφάλματα.
  • Batching: Το πρωτόκολλο υποστηρίζει εγγενώς batch requests, επιτρέποντας πολλαπλές λειτουργίες (π.χ. αρκετές κλήσεις functions) σε ένα μόνο HTTP round-trip χωρίς επιπλέον δουλειά.
  • Discovery: Το capabilities endpoint παρέχει μια πλήρη περιγραφή του API σε μορφή που οι AI agents μπορούν να καταναλώσουν για να κατανοήσουν τα διαθέσιμα εργαλεία χωρίς hallucinations.

Γιατί όχι REST:

  • Πολυπλοκότητα για AI: Η σημασιολογία του REST (GET/POST/PATCH/DELETE + URL params + body) είναι διασκορπισμένη σε πολλά σημεία, καθιστώντας δυσκολότερη τη σύνθεση κλήσεων με αξιοπιστία από τους AI agents.
  • Διαρροή Σχήματος: Το CRUD-over-tables (όπως το PostgREST) συχνά αφήνει να διαρρεύσει η εσωτερική δομή της βάσης δεδομένων απευθείας στο API. Το PgArachne σκόπιμα εκθέτει functions, κρατώντας τη business logic ενσωματωμένη στην SQL.
  • Έλλειψη Προτύπων: Το REST δεν προσφέρει καθολικό πρότυπο για batch operations, cross-platform error envelopes, ή αυτοματοποιημένη ανακάλυψη API.

2. SSE (Server-Sent Events) έναντι WebSockets

Για ειδοποιήσεις πραγματικού χρόνου, το PgArachne υλοποιεί Server-Sent Events (SSE).

Γιατί SSE:

  • Απλό HTTP: Το SSE είναι τυπικό HTTP. Λειτουργεί μέσα από proxies, load balancers και CDNs χωρίς ειδική διαμόρφωση «protocol upgrade».
  • Native Υποστήριξη Browser: Το API EventSource είναι ενσωματωμένο σε όλους τους σύγχρονους browsers και διαχειρίζεται αυτόματη επανασύνδεση χωρίς καμία client library.
  • Ταιριάζει με τη Σημασιολογία του NOTIFY: Το NOTIFY της PostgreSQL είναι μονόδρομο (από τον server στον client), το οποίο ταιριάζει απόλυτα με το SSE.
  • Multiplexing: Πάνω από HTTP/2, εκατοντάδες SSE streams μπορούν να μοιραστούν μία μόνο σύνδεση TCP, κάνοντάς το εξαιρετικά αποδοτικό.
  • Λειτουργική Απλότητα: Οι συνδέσεις SSE εμφανίζονται ως κανονικά HTTP requests σε logs και εργαλεία monitoring, καθιστώντας ευκολότερο το debugging και το rate-limiting.

Γιατί όχι WebSockets:

  • Άσκοπη Διπλή Κατεύθυνση: Καθώς ο client δεν έχει ποτέ ανάγκη να στείλει δεδομένα πίσω μέσω του καναλιού ειδοποιήσεων, η πολυπλοκότητα των WebSockets δεν προσφέρει κανένα όφελος.
  • Προβλήματα Συνδεσιμότητας: Τα WebSockets συχνά μπλοκάρονται ή κλείνονται πρόωρα από εταιρικά firewalls και ορισμένα cloud load balancers.
  • Υψηλότερο Overhead: Προσθέτει πολυπλοκότητα πρωτοκόλλου (handshakes, ping/pong frames) που δεν απαιτείται για απλό event streaming.

3. Go έναντι Εναλλακτικών

Το PgArachne είναι γραμμένο σε Go για να προσφέρει την καλύτερη ισορροπία μεταξύ απόδοσης και απλότητας deployment.

Γιατί Go:

  • Static Binaries: Μεταγλωττίζεται σε ένα μόνο binary χωρίς εξωτερικές εξαρτήσεις. Το deployment είναι τόσο απλό όσο η αντιγραφή του αρχείου στον server.
  • Concurrency: Οι goroutines της Go κάνουν τη διαχείριση χιλιάδων ταυτόχρονων συνδέσεων SSE και βάσης δεδομένων ελαφριά και απλή.
  • Ισχυρή Standard Library: Οι ενσωματωμένες βιβλιοθήκες για HTTP, TLS και JSON είναι production-grade και δεν απαιτούν «node_modules» ή εξωτερικά runtimes.
  • Cross-Compilation: Στοχεύει εύκολα Linux, macOS και Windows (amd64 και arm64) από οποιοδήποτε μηχάνημα ανάπτυξης.

Γιατί όχι Node.js, PHP, ή Ruby:

  • Runtimes: Απαιτούν την εγκατάσταση ενός συγκεκριμένου runtime environment σε κάθε μηχάνημα-στόχο.
  • Αποδοτικότητα: Ο single-threaded loop της Node ή το μοντέλο process-per-request της PHP είναι λιγότερο αποδοτικά για τη διατήρηση χιλιάδων ανενεργών συνδέσεων SSE.
  • Αποτύπωμα Μνήμης: Η Go χρησιμοποιεί σημαντικά λιγότερη μνήμη ανά σύνδεση από τις scripted γλώσσες.

Γιατί όχι Rust:

  • Ταχύτητα Ανάπτυξης: Ενώ η Rust προσφέρει εξαιρετική απόδοση, η πολυπλοκότητά της (borrow checker) επιβραδύνει την επαναληπτική ανάπτυξη για ένα εργαλείο περιορισμένο από I/O, όπου η απόδοση της Go είναι ήδη υπεραρκετή.

Γιατί όχι C/C++:

  • Ασφάλεια: Η χειροκίνητη διαχείριση μνήμης προσθέτει σημαντικούς κινδύνους ασφαλείας (buffer overflows) χωρίς ουσιαστικό κέρδος απόδοσης σε μια εφαρμογή gateway.

4. PostgreSQL Functions ως Επιφάνεια API

Το PgArachne εκθέτει σκόπιμα functions της βάσης δεδομένων αντί για raw πίνακες.

Γιατί functions:

  • Encapsulation: Η business logic βρίσκεται συνεντοπισμένη με τα δεδομένα στη βάση δεδομένων — ένα μόνο σημείο για audit, versioning και ασφάλεια.
  • Ρητή Ασφάλεια: Μόνο functions στις οποίες έχουν ρητά χορηγηθεί δικαιώματα EXECUTE σε συγκεκριμένο ρόλο είναι προσβάσιμες μέσω του API.
  • Abstraction: Η επικύρωση εισόδου, τα υπολογιζόμενα πεδία και οι σύνθετες λειτουργίες πολλών πινάκων είναι κρυμμένες από τον client, παρέχοντας ένα καθαρό interface.

Γιατί όχι CRUD σε επίπεδο πίνακα:

  • Στενή Σύζευξη: Η απευθείας έκθεση πινάκων συνδέει στενά το API σας με το εσωτερικό σχήμα της βάσης δεδομένων, καθιστώντας δύσκολο το refactoring της βάσης χωρίς να «σπάσουν» οι clients.
  • Κατακερματισμός Επιχειρησιακών Κανόνων: Η business logic καταλήγει μοιρασμένη ανάμεσα σε constraints της βάσης δεδομένων και σε όποιο middleware χρησιμοποιείται για το φιλτράρισμα HTTP requests.

5. Δομή URL: /{prefix}/{database}/{endpoint}

Το PgArachne δρομολογεί όλα τα endpoints κάτω από ένα ρυθμιζόμενο τμήμα προθέματος: /db/{database}/jsonrpc, /db/{database}/sse, /db/{database}/mcp. Το πρόθεμα έχει προεπιλογή db και μπορεί να αλλάξει μέσω API_PREFIX.

Γιατί αυτή η δομή:

  • Δρομολόγηση μέσω reverse proxy: Ένα μόνο instance PgArachne μπορεί να εξυπηρετήσει πολλαπλές βάσεις δεδομένων. Ένας reverse proxy (Nginx, Caddy, Traefik) μπορεί να δρομολογήσει βάσει προθέματος ή ονόματος βάσης δεδομένων χωρίς να επιθεωρεί το σώμα του request, κάτι κρίσιμο για load balancing και κανόνες δρομολόγησης βάσει path.
  • Οριζόντια Κλιμακωσιμότητα: Με το όνομα της βάσης δεδομένων στο URL path, μπορείτε να τρέξετε πολλαπλά instances PgArachne και να δρομολογήσετε traffic σε συγκεκριμένα instances ανά βάση δεδομένων χρησιμοποιώντας τυπικούς κανόνες proxy — χωρίς sticky sessions ή επιθεώρηση body.
  • Protocol multiplexing ανά βάση δεδομένων: Η ομαδοποίηση των /jsonrpc, /sse και /mcp κάτω από τον ίδιο namespace /{prefix}/{database}/ κάνει φυσιολογική την εφαρμογή authentication, rate limiting και access control ανά βάση δεδομένων στο επίπεδο του proxy.
  • Ρυθμιζόμενο πρόθεμα: Deployments που χρησιμοποιούν ήδη το /api/ ως πρόθεμα στην υποδομή τους μπορούν να ορίσουν API_PREFIX=api για να ταιριάξουν με τις συμβάσεις τους.
  • Παρατηρησιμότητα: Τα εργαλεία συγκέντρωσης logs και συστήματα μετρικών μπορούν να ομαδοποιήσουν και να φιλτράρουν το traffic βάσει ονόματος βάσης δεδομένων απευθείας από το URL, χωρίς να αναλύουν JSON bodies.

Γιατί όχι μια πλατή δομή όπως /api/{database}:

  • Ασάφεια Πρωτοκόλλου: Ένα μόνο πλατό endpoint δεν μπορεί να διακρίνει μεταξύ traffic JSON-RPC, SSE και MCP στο επίπεδο δρομολόγησης — αυτή η απόφαση καταλήγει στη λογική της εφαρμογής ή στην επιθεώρηση headers.
  • Δυσκολότερη Επέκταση: Η προσθήκη νέων πρωτοκόλλων (π.χ. GraphQL, gRPC-gateway) απαιτεί ούτως ή άλλως την εισαγωγή νέων top-level paths, οπότε ο δομημένος namespace καθιστά τον σχεδιασμό ανθεκτικό στο μέλλον.

6. MCP ως Translation Layer, Όχι ως Πρωτόκολλο Βάσης Δεδομένων

Το PgArachne υλοποιεί το Model Context Protocol (MCP) ως ένα λεπτό translation layer στον Go server. Οι PostgreSQL functions δεν έχουν ποτέ επίγνωση του MCP — παραμένουν απλές functions jsonb → json.

Γιατί το MCP μεταφράζεται στον server:

  • Μηδενικές αλλαγές σε υπάρχουσες functions: Κάθε function που είναι ήδη εκτεθειμένη μέσω JSON-RPC γίνεται άμεσα διαθέσιμη ως εργαλείο MCP. Καμία αλλαγή SQL, καμία επανεγκατάσταση αντικειμένων της βάσης δεδομένων.
  • Το MCP είναι πολύ περισσότερο από εργαλεία: Το πρωτόκολλο περιλαμβάνει handshake αρχικοποίησης, ping, notifications, και πιθανές μελλοντικές επεκτάσεις (resources, prompts, sampling). Αυτά είναι ζητήματα επιπέδου πρωτοκόλλου που ανήκουν στη Go, όχι σε SQL functions.
  • Η ασφάλεια παραμένει σε ένα σημείο: Η authentication, η αλλαγή ρόλων και η επικύρωση εισόδου είναι ήδη υλοποιημένες στη Go. Το endpoint MCP επαναχρησιμοποιεί αυτή τη λογική αμετάβλητη.
  • Πολλαπλά πρωτόκολλα, ένα backend: Η ίδια PostgreSQL function μπορεί να κληθεί μέσω JSON-RPC (από κανονικό client), MCP (από Claude Desktop ή Cursor), ή SSE (για event subscriptions). Η βάση δεδομένων είναι protocol-agnostic.
  • Απλούστερη SQL: Η επεξεργασία envelopes MCP (initialize, tools/list, χειρισμός notifications) εντός PostgreSQL functions θα απαιτούσε ανάλυση σύνθετων δομών JSON σε PL/pgSQL, καθιστώντας τις functions δυσκολότερες στη γραφή, τη δοκιμή και τη συντήρηση.

Γιατί όχι να μεταφερθεί το MCP στη βάση δεδομένων:

  • Το handshake του MCP δεν χρειάζεται βάση δεδομένων: Τα initialize και ping είναι καθαρά μηνύματα πρωτοκόλλου. Το άνοιγμα σύνδεσης βάσης δεδομένων για αυτά σπαταλά πόρους και προσθέτει latency.
  • Η SQL είναι λάθος εργαλείο για λογική πρωτοκόλλου: Οι κωδικοί σφάλματος JSON-RPC 2.0, η δρομολόγηση notifications και η διαχείριση idempotency keys είναι ζητήματα middleware, όχι ζητήματα δεδομένων.