ADR-015: Skip inbound connectors¶
- Status: Accepted
- Date: 2026-05-14
- Tags: integration, connectors
Context and Problem Statement¶
Camunda tiene framework de inbound connectors (Webhook, Kafka consumer, etc.) con lifecycle complex (activate/deactivate, correlation, failure strategies). ¿Replicamos este pattern, o expose APIs directas para que users construyan sus integrations?
Decision Drivers¶
- Inbound connector framework es 10x más complejo que outbound
- Users pueden construir webhook handlers triviales usando API
- Pattern emerge naturalmente sin abstraction adicional
- Camunda's CorrelationFailureHandlingStrategy es overengineering para 95% de casos
Considered Options¶
- Skip inbound framework completamente (use REST API)
- Build inbound framework full (como Camunda)
- Build subset minimal de inbound
- Webhook receiver built-in
Decision Outcome¶
Chosen option: Skip inbound framework completamente porque:
- Users escriben sus propios webhook handlers / Kafka consumers
- Llaman REST API del engine: POST /v2/messages/{name}/correlate
- Cero framework code que mantener
- Pattern emerge sin abstraction prematura
Positive Consequences¶
- Cero código de framework inbound a mantener
- Users tienen control total (su language, su framework)
- No vendor lock-in en webhook reception
- APIs del engine son ya-suficientes (publish message, broadcast signal)
Negative Consequences¶
- Users escriben código boilerplate (webhook handler básico)
- Sin element templates para Web Modeler
- Pattern emerging sin guidance puede inconsistent
API patterns para inbound¶
Webhook → process¶
User-controlled webhook handler:
// User's app
import express from 'express';
import { WorkflowClient } from '@mvp/sdk';
const app = express();
const client = new WorkflowClient({ apiKey: '...' });
app.post('/webhooks/payment-received', async (req, res) => {
const { orderId, amount } = req.body;
await client.publishMessage({
name: 'payment-received',
correlationKey: orderId,
variables: { amount }
});
res.status(200).send('ok');
});
10 líneas. Eso es un inbound connector. Cero abstracción.
Kafka consumer → process¶
import { Kafka } from 'kafkajs';
import { WorkflowClient } from '@mvp/sdk';
const kafka = new Kafka({ brokers: ['kafka:9092'] });
const client = new WorkflowClient({ apiKey: '...' });
const consumer = kafka.consumer({ groupId: 'workflow-handlers' });
await consumer.subscribe({ topic: 'orders' });
await consumer.run({
eachMessage: async ({ message }) => {
const order = JSON.parse(message.value.toString());
await client.publishMessage({
name: 'order-placed',
correlationKey: order.orderId,
variables: order
});
}
});
User controls everything: error handling, retry policy, dedup. Standard Kafka patterns work.
Timer → process¶
Cron job + REST call:
# crontab
0 8 * * * curl -X POST $ENGINE/v2/process-instances \
-H "Authorization: Bearer $TOKEN" \
-d '{"bpmnProcessId": "daily-report", "variables": {"date": "today"}}'
Beneficios¶
Comparado con Camunda's inbound framework:
| Aspecto | Camunda inbound | MVP approach |
|---|---|---|
| LOC to maintain | ~100K | 0 (sólo REST API) |
| User language | Java only (mostly) | Any |
| Activation logic | Framework-controlled | User-controlled |
| Failure handling | Strategies abstractas | Standard practices |
| Testing | Hard (lifecycle) | Trivial (HTTP) |
| Onboarding | Learn framework | Learn REST API |
Cuándo build inbound framework¶
SI cliente needs: - Element templates en Web Modeler que auto-generan inbound handlers - Lifecycle managed por la plataforma (engine starts/stops listeners) - Centralized retry/failure handling
Para 95% de casos, ninguno aplica. User code wins.
Documentation pattern¶
# Receiving Events into Workflows
The MVP engine accepts events via REST API. You write the receiver, the engine
handles correlation.
## Pattern: Webhook → Workflow
1. Your service receives webhook from external system
2. Call POST /v2/messages/{name}/correlate
3. Engine correlates to waiting process instance
## Pattern: Kafka → Workflow
1. Your Kafka consumer reads message
2. Call POST /v2/messages/{name}/correlate
3. ...
## Pattern: Timer → Workflow
Use cron + curl, or your scheduler of choice + REST call.
## Templates
[Link to example handlers in different languages]
Links¶
- adrs/adr-016-minimal-outbound-worker-sdk — Complementario (outbound SDK)
- concepts/connector-sdk-architecture — Camunda's full pattern (reference only)
- concepts/message-correlation — Cómo funciona correlation