Architecture Overview
apptor flow is a multi-module platform built around an actor-based asynchronous execution engine. This page gives you the full system picture before you dive into individual modules.
System Diagram
Module Map
apptor flow is a Gradle multi-module Java project with 26 modules:
| Module | Role |
|---|---|
apptor-flow-sdk | Domain models: Node, NodeType enum, Variable, LoopCharacteristics, execution events |
apptor-flow-json-parser | Converts workflow JSON text → typed domain models; type mapper, parser classes per node type |
apptor-flow-core | Execution engine: node handlers (24), process lifecycle, actor dispatch, variable resolution |
apptor-actor-framework | Generic actor model: actor pools, message queues, thread management |
apptor-flow-api | REST API layer: 41 controllers, Micronaut routes, filters, DTOs |
apptor-flow-persistence | JPA/Hibernate entities, repositories, Liquibase changelog management |
apptor-flow-config | Configuration loading, environment-specific settings |
apptor-flow-messaging | Internal messaging: topics, event emitter, subscriber framework |
apptor-flow-bpmn | BPMN-compatible process model constructs |
apptor-flow-scheduler | Time-based trigger scheduling |
apptor-flow-plugins | Plugin execution framework for node event handlers |
apptor-flow-sql-plugin | SQL execution plugin (direct and AI-assisted query modes) |
apptor-rest-client | HTTP client for REST API service tasks |
apptor-secrets | Encrypted secret storage and retrieval |
apptor-flow-rag | RAG pipeline: chunking, embedding, vector search |
apptor-rag-sdk | RAG domain models and interfaces |
apptor-flow-voice | Voice call automation: Twilio integration, OpenAI voice models |
apptor-mail | Email sending: SMTP, connection management |
apptor-drive | Google Drive integration for document access |
apptor-drive-sync | Drive document sync to knowledge base |
apptor-flow-task-server-sdk | SDK for building external task servers |
apptor-flow-task-server | Runtime for external task servers |
apptor-flow-vertical-integrations | Domain model framework: verticals, actions, provider mappings |
apptor-auth-apptorid | apptor ID authentication provider integration |
apptor-oauth | OAuth credential management for integrations |
apptor-workflow-creator | AI-powered workflow generation from natural language |
Request Flow: Execute a Workflow
Webhook Pipeline
Webhooks are processed through a dedicated three-stage pipeline, separate from the main REST request flow.
Verification Engine
WebhookVerifierRegistry maps each authType to its verifier. Every verifier receives all active secrets and tries each — supporting zero-downtime secret rotation where both old and new secrets are valid simultaneously.
Normalization
After verification, WebhookNormalizerRegistry extracts standard fields (event type, event ID, timestamp) from provider-specific locations. This means flows always receive {webhookEventType} and {webhookEventId} regardless of which provider sent the event.
Secret Storage
Secrets are encrypted at rest using AES-256-GCM with a random IV per secret. The encryption key is loaded from the apptor.secret.encryption-key environment variable. Secrets are cached for 5 seconds only and never written to logs.
Circuit Breaker
Each endpoint tracks consecutive_failures. At 5 failures the endpoint moves to CIRCUIT_BREAKER status and stops accepting events. An in-app notification is sent to the org. Reset is manual (admin action) after investigating the cause.
Retry
Transient processing failures are retried 7 times with exponential backoff (1m → 5m → 15m → 1hr → 6hr → 24hr → DLQ). Verification failures are not retried — they are deterministic.
Key Architectural Decisions
Actor-Based Execution
Each node type has its own named actor pool with a configurable number of threads. This means:
- A slow SQL query never blocks the email actor
- AI Task threads (1) can be kept low without affecting other throughput
- Thread allocation can be tuned per deployment in
flow-config.json
Asynchronous by Default
The engine returns immediately after queuing the first node. Clients poll for status via GET /process/instance/{id} or stream logs via SSE. This means workflows of any length do not block the API thread.
State in PostgreSQL
All execution state — variables, node status, event subscriptions — is persisted in PostgreSQL. The engine can restart or be horizontally scaled without losing in-flight executions (pending messages are re-queued from the queue_item table).
JSON Workflow Format
Workflows are stored as JSON strings (processText) and parsed at execution time by apptor-flow-json-parser. This means the same workflow definition can be versioned, exported, imported, and diffed like any other text file.
Variable Resolution
Node property values containing {variableName} are resolved by TemplateVariableResolver just before the node executes. The resolver reads from the execution's variable context. See Variable Reference for full details.
Technology Stack
| Concern | Technology |
|---|---|
| Language | Java 21 |
| Framework | Micronaut 4.4.2 |
| Build | Gradle (multi-module) |
| Database | PostgreSQL 16 |
| Migrations | Liquibase |
| ORM | JPA/Hibernate (Micronaut Data) |
| Cache | Hazelcast |
| AI | LangChain4j |
| Voice | Twilio + OpenAI |
| Auth | OIDC (Micronaut Security) + custom API Key filter |
| Frontend | Angular 18+, TypeScript |
| Diagram | GoJS |
| Scripting | GraalVM Polyglot (JavaScript, Python) |
Further Reading
- Backend Architecture → — module details, handler lifecycle, AI integration
- Frontend Architecture → — Angular components, services, A2UI
- Execution Engine → — actor model, thread pools, node handler lifecycle
- Auth Model → — OIDC, API Keys, permissions, multi-tenant
- Variable Resolution → — template vars, JUEL, nested access
- Database Schema → — all tables and their purpose