Architecture Overview
This guide provides a comprehensive overview of the Eloquent platform architecture, including system components, data flow, and design decisions.
System Architecture
CLIENT LAYER
Eloquent App (Platform core, admin dashboard, workflows, agents)
Next.js 16.1+ (App Router)
|
HTTP (REST API)
|
API GATEWAY LAYER
Middleware Stack:
1. Recovery (panic handling)
2. Request ID (correlation)
3. CORS (cross-origin requests)
4. Logging (structured logs)
5. JWT Authentication
6. Scope Authorization
|
HTTP (Internal)
|
SERVICE LAYER
Entities | KG Service | Agents | Integrations
Chat | Workflow | Scheduler | Docs
Go Microservices (REST APIs)
|
DATA LAYER
PostgreSQL | ClickHouse | Redis
(Entities) | (Knowledge | (Cache,
| Graph) | Embeddings)
NATS (Service-to-Service Only):
Used for internal async messaging between backend services (not clients). Subjects: entity.events.*, kg.events.*, workflow.events.*
Core Components
Frontend Applications
| Application | Purpose | URL |
|---|---|---|
| Eloquent App | Platform core, admin dashboard, workflow designer, agent builder | /* |
All applications:
- Built with Next.js 16.1+ (App Router)
- Share packages from
@elqnt/* - Communicate with backend via API Gateway (HTTP REST)
- Use JWT tokens for authentication
Shared Packages (@elqnt/*)
packages/eloquent/
├── auth/ # Authentication context and hooks
├── api/ # API Gateway client and utilities
├── entity/ # Entity management hooks and types
├── kg/ # Knowledge graph hooks and types
├── chat/ # Chat/messaging types and hooks
├── workflow/ # Workflow engine integration
├── agents/ # Agent configuration types
├── types/ # Shared TypeScript types
└── react/ # Shared React components
Backend Services
| Service | API Path | Purpose |
|---|---|---|
| Entities | /api/v1/entities/* | Dynamic entity CRUD with JSON Schema |
| KG Query | /api/v1/kg/query/* | Knowledge graph queries and search |
| KG Ingest | /api/v1/kg/ingest/* | Knowledge graph data ingestion |
| Agents | /api/v1/agents/* | AI agent configuration and execution |
| Chat | /api/v1/chat/* | Real-time messaging and chat history |
| Workflow | /api/v1/workflow/* | Business process automation |
| Auth | /api/v1/auth/* | Authentication and authorization |
| Docs | /api/v1/docs/* | Document processing and analysis |
Data Stores
| Store | Purpose | Technology |
|---|---|---|
| PostgreSQL | Entity definitions and records | JSONB, per-org schemas |
| ClickHouse | Knowledge graph nodes and edges | Columnar, per-org databases |
| Redis | Cache, embeddings, sessions | Key-value, TTL support |
Multi-Tenancy
Every organization gets isolated resources:
Organization: org_0197b2d3-982f-7b79-b2bf-710f6def104a
PostgreSQL Schema:
└── org_0197b2d3_982f_7b79_b2bf_710f6def104a
├── entity_definitions
├── entity_records
└── entity_views
ClickHouse Database:
└── org_0197b2d3_982f_7b79_b2bf_710f6def104a
├── kg_nodes
└── kg_edges
Rule: Every request includes orgId in headers or body.
Communication Patterns
1. Browser to API Gateway to Service (Primary)
All browser requests communicate with backend services through the API Gateway using standard HTTP.
// Browser-side: Custom hook wrapping useEntities
import { useEntities } from "@elqnt/entity/hooks";
function useTickets() {
const { createRecord, loading, error } = useEntities({
baseUrl: config.apiGatewayUrl,
orgId: config.orgId,
});
const createTicket = async (data) => {
const record = await createRecord("ticket", { fields: data });
return record;
};
return { createTicket, loading, error };
}
2. Two Communication Paths
| Path | Use Case | URL Source |
|---|---|---|
| Browser → Gateway | Interactive CRUD, real-time | API_GATEWAY_URL_PUBLIC |
| Server → Gateway | SSR, auth flows, sensitive ops | API_GATEWAY_URL_INTERNAL |
3. JWT Authentication
// Token generated server-side, used for all API requests
const token = await new jose.SignJWT({
org_id: orgId,
user_id: userId,
email: userEmail,
role: "user",
scopes: ["read", "write"],
})
.setProtectedHeader({ alg: "HS256" })
.setExpirationTime("1h")
.sign(secret);
// Token sent with every request
headers: { Authorization: `Bearer ${token}` }
4. Service-to-Service (NATS - Internal Only)
NATS is used only for internal backend service communication, not for client applications:
// Backend service publishes events
js.Publish("entity.events.created", eventPayload)
// Other backend services subscribe
nc.Subscribe("entity.events.created", func(msg *nats.Msg) {
// Handle event
})
Data Flow Examples
Creating an Entity Record
1. User submits form in React component
│
▼
2. API client sends POST to /api/v1/entities/records
│
▼
3. API Gateway validates JWT token
│
▼
4. Gateway proxies request to Entities Service
│
▼
5. Service validates against JSON Schema
│
▼
6. Service writes to PostgreSQL (org schema)
│
▼
7. Service publishes internal event via NATS (optional)
│
▼
8. HTTP response returned through Gateway
│
▼
9. Hook updates local state, UI reflects change
Server-Side Rendering (SSR) Data Fetch
1. User navigates to /admin/projects
│
▼
2. Server Component calls api-client-server.ts
│
▼
3. Server generates JWT directly (has JWT_SECRET)
│
▼
4. Request sent to API_GATEWAY_URL_INTERNAL
│
▼
5. Gateway proxies to Projects Service
│
▼
6. Data returned, rendered in Server Component
│
▼
7. HTML sent to browser (instant load, no spinner)
NATS Usage (Internal Only)
CRITICAL: NATS is used only between backend Go services. Using NATS in client applications (browser or Next.js server) is strictly forbidden.
Allowed NATS Use Cases
- Service-to-Service Request/Response
- JetStream for Persistence (KV Store, Streams)
Security
Multi-Tenancy Isolation
- Every request validated for
orgId - PostgreSQL: Separate schemas per org
- ClickHouse: Separate databases per org
- No cross-org data access possible
Authentication Flow
1. User authenticates (OAuth/OIDC via NextAuth)
│
▼
2. Session established in Next.js app
│
▼
3. Browser requests: Fetch JWT via /api/gateway-token
Server requests: Generate JWT directly (has JWT_SECRET)
│
▼
4. JWT includes: orgId, userId, email, role, scopes
│
▼
5. API Gateway validates JWT on every request
│
▼
6. Gateway extracts claims and forwards to backend:
- X-Org-ID, X-User-ID, X-User-Email headers
Next Steps
- API Gateway - Building API Gateways for frontend-backend communication
- Frontend Apps - React patterns, SSR, and client-server communication
- Type System - Go to TypeScript type generation
- Entities Management - Working with dynamic entities