Architecture
Apostol CRM combines two frameworks into a single backend: a high-performance C++20 HTTP server and a PostgreSQL-based business logic engine. Together they deliver 418 REST API endpoints, OAuth 2.0 authentication, a workflow engine, WebSocket pub/sub, background processing, and file storage -- all in a single binary.
Overview
| Framework | Role | What it provides |
|---|---|---|
| libapostol | C++20 server | HTTP/WebSocket server, async PostgreSQL, single epoll event loop -- 507K RPS |
| db-platform | PostgreSQL layer | 26 PL/pgSQL modules, 100+ tables, 800+ functions -- REST API, auth, workflow, entities |
No PHP, Python, or Node.js. HTTP requests flow directly from C++ to PostgreSQL -- zero intermediate layers, sub-millisecond latency.
Request Flow
The C++ layer handles HTTP parsing, TLS, connection pooling, WebSocket, JWT verification, and async I/O. The database layer handles business logic, REST routing, access control, workflow transitions, and data storage. They communicate through libpq -- one event loop, no threads.
Module System
The C++ server is assembled from independent modules. Each module is a separate GitHub repository that can be included or excluded.
Workers -- handle HTTP/WebSocket requests
| Module | Description |
|---|---|
| AppServer | Auth-aware REST API dispatch to PostgreSQL |
| AuthServer | OAuth 2.0 (6 grant types), JWT, cookie auth, PKCE |
| WebSocketAPI | JSON-RPC + pub/sub over WebSocket |
| FileServer | File serving with JWT authentication |
| PGHTTP | Raw HTTP-to-PL/pgSQL function dispatch |
| WebServer | Static files, SPA support, Swagger UI |
Worker registration order matters (first match wins):
static inline void create_workers(Application& app)
{
// Auth endpoints: /oauth2/*
if (app.module_enabled("AuthServer") && app.has_db_pool())
app.module_manager().add_module(std::make_unique<AuthServer>(app));
// REST API: /api/* (with auth)
if (app.module_enabled("AppServer") && app.has_db_pool())
app.module_manager().add_module(std::make_unique<AppServer>(app));
// Static files: /* (last -- catches everything else)
app.module_manager().add_module(std::make_unique<WebServer>(app));
}
Helpers -- background modules in the helper process
| Module | Description |
|---|---|
| PGFetch | LISTEN/NOTIFY triggers outbound HTTP requests |
| PGFile | LISTEN/NOTIFY triggers file sync (PostgreSQL to filesystem) |
Processes -- independent background daemons
| Process | Description |
|---|---|
| MessageServer | Email/SMS/push dispatch via SMTP, FCM, HTTP API |
| TaskScheduler | Cron-like job execution from db.job queue |
| ReportServer | LISTEN-driven report generation |
Database Architecture
The PostgreSQL layer uses a two-layer design with four schemas:
| Schema | Role | Example |
|---|---|---|
rest | REST dispatcher -- routes URL paths to API functions | rest.sensor('/sensor/list', '{}') |
api | Public API -- views and CRUD wrappers with access checks | api.list_sensor(...) |
kernel | Business logic -- core functions and views | CreateSensor(...), EditSensor(...) |
db | Data layer -- tables, indexes, triggers | db.sensor |
A typical request flows through all four layers:
POST /api/v1/sensor/list
-> rest.sensor('/sensor/list', payload)
-> api.list_sensor(search, filter, limit, offset, orderby)
-> SELECT * FROM kernel.ObjectSensor (view)
-> JOIN db.sensor, db.document, db.object, ...
Platform modules (26)
The db-platform provides 26 reusable PL/pgSQL modules:
- Core: entity, class, type, object, document, reference
- Auth: session, user, oauth2, token
- Workflow: state, method, transition, action, event
- Access control: ACU (class-level), AOU (object-level), AMU (method-level)
- Infrastructure: job, message, file, log, notification
Three database roles
| Role | Used by | Purpose |
|---|---|---|
daemon | Workers | HTTP request handling |
apibot | Helper and processes | Background tasks |
kernel | Administrative operations | Schema migrations, setup |
Entity System
Apostol CRM ships with 30 business entities (clients, invoices, payments, subscriptions, devices, and more). Each entity follows a standard 8-file convention:
entity/object/document/myentity/
├── table.sql # CREATE TABLE, indexes, triggers
├── view.sql # 3 kernel views (data, access, full object)
├── routine.sql # Create*/Edit*/Get* functions
├── api.sql # API schema views + 6 CRUD wrappers
├── rest.sql # REST dispatcher (6 standard routes)
├── event.sql # 9 event handler functions
├── init.sql # Workflow: class, type, states, methods, transitions
└── create.psql # Master install script
Every entity inherits from either document (business objects with lifecycle and area-based access) or reference (lookup/catalog data). Creating a new entity means creating these 8 files and wiring them into the parent.
Workflow Engine
Every entity has a built-in state machine. The default lifecycle:
┌────── restore ───────┐
v |
[Created] --enable--> [Enabled] --disable--> [Disabled]
| | |
|--disable--> [Disabled] |--enable--> [Enabled]
| | |
|--delete--> [Deleted] <--delete-- [Deleted] <--delete--
Four state types: created, enabled, disabled, deleted.
You can customize the workflow per entity by adding custom states, methods, transitions, and events. For example, a charging station might have available, unavailable, and faulted as sub-states within the enabled state type. See the Workflow Customization guide.
Module Composition
libapostol is designed as a module constructor. You pick the modules you need:
- Minimal (no database): WebServer only -- static file serving + healthcheck
- HTTP gateway: PGHTTP + WebServer + PGFetch -- routes HTTP requests to PostgreSQL
- Full backend: All workers + helpers + processes -- complete platform with auth, files, WebSocket, background tasks
- Custom: Pick any combination. Each module is standalone
Production Projects
Projects built on the same architecture:
| Project | Industry |
|---|---|
| ChargeMeCar | EV charging station management (OCPP) |
| Apostol ARB | Crypto futures arbitrage aggregator |
| PlugMe | OCPP Central System |
| Ship Safety ERP | Maritime safety ERP |
| CopyFrog | AI content generation |
| Campus CORS | GNSS correction data system |