Documentation Index
Fetch the complete documentation index at: https://docs.kaireonai.com/llms.txt
Use this file to discover all available pages before exploring further.
Overview
The KaireonAI Domain Event Stream publishes lightweight notifications whenever the platform records an interaction or makes a recommendation. Subscribers (analytics workers, ML feature pipelines, external sinks) can consume these events without polling the OLTP database.
This stream is separate from the POST /api/v1/events ingestion endpoint, which accepts inbound customer behavior events.
Topics
| Topic | When fired | Carries |
|---|
interaction.recorded.v1 | Every successful insert into InteractionHistory (impressions, clicks, conversions, complaints, unsubscribes) | tenantId, customerId, offerId, creativeId, channelId, interactionType, outcomeTypeKey, campaignId, recommendationId, timestamp |
decision.made.v1 | Every successful POST /api/v1/recommend decision | tenantId, customerId, recommendationId, offersReturned, topOfferId, topPropensity, decisionFlowKey, timestamp |
Event envelope
Every event is published as JSON with this shape:
{
"type": "interaction.recorded.v1",
"timestamp": "2026-04-28T12:00:00.000Z",
"payload": {
"tenantId": "...",
"customerId": "...",
"offerId": "...",
"creativeId": "...",
"channelId": "...",
"interactionType": "click",
"outcomeTypeKey": "click",
"campaignId": null,
"recommendationId": "...",
"timestamp": "2026-04-28T12:00:00.000Z"
}
}
Choosing a backend
The publisher backend is selected via the EVENT_PUBLISHER environment variable. Pick the trade-off that fits your operational story — durability, cost, ops weight all vary.
EVENT_PUBLISHER | Backend | Durability | When to use |
|---|
redis (default) | Redis pub/sub | None — fire-and-forget; consumers must be online | Local dev with Upstash or docker compose up redis; playground; small self-hosted setups where the OLTP InteractionHistory is enough |
kafka / redpanda | Kafka API (kafkajs) | Replayable with consumer groups + offsets | Local dev with docker compose --profile kafka up redpanda; self-hosted Kafka or Redpanda; Confluent Cloud; Aiven |
msk / aws_msk | Amazon MSK (IAM-auth Kafka) | Replayable | AWS-native deployments using Managed Streaming for Apache Kafka |
eventbridge | AWS EventBridge | Pay-per-event, durable, fan-out to many AWS targets | When downstream consumers are AWS Lambda / Step Functions / SQS |
kinesis | AWS Kinesis Data Streams | Replayable, 24-hr to 365-day retention | When downstream consumers want streaming-shard semantics |
Switch backends without code changes — set EVENT_PUBLISHER and the per-backend env vars below. Topic names + event payloads stay identical, so subscribers don’t need to be rewritten.
Local dev with Redpanda (free Kafka API)
Redpanda is a Kafka-compatible broker that runs as a single binary, no Zookeeper, no JVM. It is included as an optional Docker Compose profile:
# Start the broker (~5 seconds)
docker compose --profile kafka up -d redpanda
# Point the platform at it
export EVENT_PUBLISHER=kafka
export KAFKA_BROKERS=localhost:19092 # host port (in-cluster clients use redpanda:9092)
npm run dev
For Redpanda Cloud Serverless (free tier survives indefinitely for low-traffic):
export EVENT_PUBLISHER=kafka
export KAFKA_BROKERS=your-cluster.redpanda.com:9092
export KAFKA_TLS_ENABLED=true
export KAFKA_SASL_MECHANISM=scram-sha-256
export KAFKA_SASL_USERNAME=<from-redpanda-cloud-console>
export KAFKA_SASL_PASSWORD=<from-redpanda-cloud-console>
Durability — what each backend gives you
redis: none. Consumers must be online when an event fires. If no subscriber is connected to a topic, the event is silently dropped.
kafka / redpanda / msk: events are persisted to the broker. Consumers can replay from any offset within the configured retention window (default Kafka retention is 7 days). Multiple consumer groups read independently.
eventbridge: durable per-event delivery to subscribed targets. No replay (use SQS DLQ for failures).
kinesis: durable shards with 24-hour to 365-day replay window.
In all backends, the publish call is fail-open: if the broker is unreachable or required env vars are missing, the platform logs a warning and continues. The OLTP source of truth remains InteractionHistory — query it directly if you need a replayable record older than your stream’s retention window.
Configuration reference
Common
| Env var | Required | Notes |
|---|
EVENT_PUBLISHER | No | One of redis (default) / kafka / redpanda / msk / aws_msk / eventbridge / kinesis |
Redis backend (EVENT_PUBLISHER=redis)
| Env var | Required | Notes |
|---|
REDIS_URL | When EVENT_PUBLISHER=redis | If unset on the redis backend, event stream is disabled; platform keeps functioning |
Kafka / Redpanda backend (EVENT_PUBLISHER=kafka or redpanda)
| Env var | Required | Notes |
|---|
KAFKA_BROKERS | Yes | Comma-separated host:port list |
KAFKA_CLIENT_ID | No | Defaults to kaireon-platform |
KAFKA_TLS_ENABLED | No | true to enable TLS |
KAFKA_SASL_MECHANISM | No | plain, scram-sha-256, or scram-sha-512 |
KAFKA_SASL_USERNAME / KAFKA_SASL_PASSWORD | When SASL enabled | Auth credentials |
KAFKA_CONSUMER_GROUP_ID | No | Defaults to kaireon-consumers |
MSK backend (EVENT_PUBLISHER=msk)
| Env var | Required | Notes |
|---|
MSK_BROKERS | Yes | Comma-separated bootstrap brokers |
MSK_REGION | No | Defaults to us-east-1 |
MSK_AUTH_MODE | No | iam_role (default) or sasl_scram |
MSK_ROLE_ARN | When IAM mode | IAM role for sigv4 |
MSK_SASL_USERNAME / MSK_SASL_PASSWORD | When SASL mode | — |
MSK_CONSUMER_GROUP_ID | No | — |
MSK_TOPIC_PREFIX | No | Optional prefix for all topics |
(Equivalent env-var sets exist for eventbridge and kinesis — see platform/src/lib/infra/container.ts.)
Sample subscriber (ioredis)
import Redis from "ioredis";
const sub = new Redis(process.env.REDIS_URL!);
await sub.subscribe("interaction.recorded.v1");
await sub.subscribe("decision.made.v1");
sub.on("message", (channel, raw) => {
const event = JSON.parse(raw);
switch (channel) {
case "interaction.recorded.v1":
console.log("interaction:", event.payload);
break;
case "decision.made.v1":
console.log("decision:", event.payload);
break;
}
});
Where it’s wired
| Code path | Source file |
|---|
| Publisher singleton | platform/src/lib/events/interaction-events.ts |
| Redis backend | platform/src/lib/infra/redis-events.ts |
InteractionStore.recordEvent | platform/src/lib/infra/pg-interaction-store.ts |
POST /api/v1/respond | platform/src/app/api/v1/respond/route.ts |