> For the complete documentation index, see [llms.txt](https://host2host.onibonje.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://host2host.onibonje.com/docs/21-event-driven-runtime-extensibility.md).

# Event-Driven Architecture and Runtime Extensibility

## 1. Overview

The H2H platform is **event-driven** and **extensible at runtime**. Events are **database-driven** — logical `event_code` values resolve to physical topics/queues, partition keys, and broker bindings from `event_def` and `event_channel_def` — **not** hardcoded naming conventions in Java.

| Property                   | Meaning                                                                                                                                                                        |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Event-driven**           | State changes flow as asynchronous events on Kafka/RabbitMQ — decoupled producers and consumers                                                                                |
| **Database-driven events** | Topic names, broker, and partition strategy (country, region, partner, module, service) configured in DB — see [46 Database-Driven Events](/docs/46-database-driven-events.md) |
| **Runtime extensibility**  | New behavior activated **without rebuilding or redeploying** application JARs — via database publish, hooks, scripts, and event subscriptions                                  |

```mermaid
flowchart TB
  subgraph hotpath [Transaction Hot Path]
    Ingest[SFTP HTTP WebSocket MQ Ingest]
    Camel[Camel Pipeline]
    Finacle[Finacle Post]
  end

  subgraph events [Event Backbone - DB-resolved channels]
    TX[PAYMENT_* events]
    FILE[FILE_* events]
    AUDIT[AUDIT_EVENT]
    CONFIG[CONFIG_PUBLISHED]
    CUSTOM[CUSTOMIZATION_PUBLISHED]
    EXT[EXTENSION events]
  end

  subgraph runtime [Runtime Extensions - No Redeploy]
    Hooks[Hook Executor + Scripts]
    Subs[Event Subscriptions]
    Webhooks[Webhook Dispatcher]
    Jobs[Broker-Delayed Jobs]
  end

  Ingest --> Camel --> Finacle
  Camel --> events
  events --> runtime
  CONFIG --> runtime
  CUSTOM --> runtime
```

**Clarification:** Runtime extensibility does **not** mean hot-swapping Java JARs in memory (OSGi-style) in production. It means **behavior changes go live on publish** — config, scripts, hooks, event handlers, and customization profiles — while the stable capability JARs stay unchanged.

***

## 2. Event-Driven Foundation

> **Canonical reference:** [46 Database-Driven Events](/docs/46-database-driven-events.md)

### 2.1 Message backbone (database-driven)

Physical topic/queue names are **not hardcoded**. Producers call `EventPublisher.publish(eventCode, envelope)`; `EventChannelResolver` loads `event_channel_def` from the config store.

| Category        | `event_code` (logical)                                       | Typical producers | Notes                                            |
| --------------- | ------------------------------------------------------------ | ----------------- | ------------------------------------------------ |
| **Transaction** | `PAYMENT_RECEIVED`, `PAYMENT_POSTED`, `PAYMENT_FAILED`       | Camel routes      | Partition: configurable — default `partnerId`    |
| **File**        | `FILE_RECEIVED`, `FILE_DELIVERED`, `FILE_FAILED`             | File management   | Partition: `countryCode` + `partnerId` composite |
| **Audit**       | `AUDIT_EVENT`                                                | Observability     | High-volume hash spread                          |
| **Config**      | `CONFIG_PUBLISHED`, `CUSTOMIZATION_PUBLISHED`                | Admin API         | Broadcast — `NONE` partition                     |
| **Alerts**      | `ALERT_RAISED`, `SLA_BREACH`                                 | SLA monitor       | Per `event_channel_def`                          |
| **DLQ**         | `DLQ_MESSAGE`                                                | Error handler     | Ops reprocess                                    |
| **Extension**   | Custom `event_def` rows                                      | Hooks, scripts    | Admin-registered                                 |
| **Job**         | `JOB_SCHEDULE`, `JOB_EXECUTE`, `JOB_COMPLETED`, `JOB_FAILED` | Job scheduler     | Per-country channels optional                    |

**Scope dimensions** for channel resolution: `GLOBAL` → `ORG` → `REGION` → `COUNTRY` → `PARTNER` → `MODULE` → `SERVICE` (most specific wins).

**Seed defaults** may use legacy-style names (e.g. `h2h.payment.posted`) as initial `destination_name` values — banks rename in admin without JAR changes.

### 2.2 Event Envelope (standard)

Every platform event uses a consistent envelope:

```java
public record H2hEvent(
    String eventId,
    String eventType,
    String correlationId,
    String partnerId,
    String countryCode,
    Instant timestamp,
    String sourceLibrary,        // e.g. h2h-file-management
    String configVersion,
    String customizationVersion,
    Map<String, String> headers,
    Object payload
) {}
```

**Propagation:** `correlationId`, `partnerId`, and customization version travel with every event — extensions can correlate without tight coupling.

### 2.3 Event-Driven vs Request-Driven

| Pattern                      | Used for                                               | Example                                                   |
| ---------------------------- | ------------------------------------------------------ | --------------------------------------------------------- |
| **Synchronous (in-process)** | STP hot path                                           | File → decrypt → Finacle post in one Camel route          |
| **Asynchronous (event)**     | Side effects, notifications, recon, cache invalidation | `EventPublisher.publish("PAYMENT_POSTED", ...)`           |
| **Hybrid**                   | Critical path sync, everything else async              | Post to Finacle synchronously; notify ERP via Kafka event |

The payment **must** complete synchronously for STP; **extensions** react to the outcome via events.

***

## 3. Runtime Extensibility Model

### 3.1 What Changes at Runtime (No Redeploy)

| Extension                              | Activate how                         | Effective when                                         |
| -------------------------------------- | ------------------------------------ | ------------------------------------------------------ |
| Integration profile / route template   | Admin publish                        | `CONFIG_PUBLISHED` → cache refresh                     |
| Customization profile (all libraries)  | Admin publish                        | `CUSTOMIZATION_PUBLISHED`                              |
| Scripts on pipeline hooks              | Publish `script_def` + `hook_def`    | Next transaction                                       |
| Event subscription (internal handler)  | Publish `event_subscription`         | Consumer picks up on next poll                         |
| Webhook subscription                   | Publish `webhook_subscription`       | Next matching event                                    |
| Scheduled job                          | Publish `job_def`                    | `ScheduleBootstrap` republishes delayed broker message |
| Custom attributes / extension entities | Admin publish                        | Next config resolution                                 |
| Routing / validation rules             | Admin publish                        | Next message                                           |
| Event filter expressions               | Admin publish                        | Next event delivery                                    |
| Enable/disable route pack              | `h2h.modules.*` via config service\* | After config refresh                                   |

\*Module flags typically require pod config reload or rolling restart for **infrastructure** flags; **business** behavior does not.

### 3.2 What Requires JAR Update (Rolling Deploy)

| Extension               | Why                                                             |
| ----------------------- | --------------------------------------------------------------- |
| New Camel step type     | New `Processor` bean in code                                    |
| New `FileStore` backend | New adapter implementation                                      |
| New transform engine    | New `TransformEngineProvider`                                   |
| New Finacle operation   | New `CoreBankingOperationProvider` / `FinacleOperationProvider` |
| New Kafka serdes format | Code change                                                     |

These are **L4 plugin JARs** — deployed via Maven version bump + rolling Kubernetes deploy (\~minutes, zero code fork).

### 3.3 Runtime Extensibility Stack

```
L1  Config publish          → immediate (cache event)
L2  Scripts + hooks           → immediate (next exchange)
L2  Event subscriptions       → immediate (next consumer poll)
L3  Jobs                      → immediate (broker delay reschedule)
L4  Plugin JAR                → rolling deploy
```

***

## 4. Event-Driven Runtime Extensions

### 4.1 Event Subscriptions (database-driven)

Admins register **handlers** for platform events without code deploy.

**Table: `event_subscription`**

| Column              | Description                                                |
| ------------------- | ---------------------------------------------------------- |
| `subscription_id`   | UUID                                                       |
| `event_code`        | FK → `event_def` — e.g. `PAYMENT_POSTED`, `FILE_DELIVERED` |
| `scope`             | GLOBAL, COUNTRY, PARTNER                                   |
| `scope_id`          | Optional filter                                            |
| `handler_type`      | SCRIPT, CAMEL\_ROUTE, WEBHOOK, JOB\_TRIGGER                |
| `handler_ref`       | script\_id, `direct:handle-erp-post`, webhook\_id, job\_id |
| `filter_expression` | JSONata filter on event payload                            |
| `enabled`           | Boolean                                                    |
| `priority`          | Execution order                                            |

**Example:** When `PAYMENT_POSTED` for partner `ACME_NG` → run script `ERP_NOTIFY_V1`. Physical topic resolved via `event_channel_def` for scope `PARTNER` / `ACME_NG` or `COUNTRY` / `NG`.

```mermaid
sequenceDiagram
  participant Camel
  participant Pub as EventPublisher
  participant Resolver as EventChannelResolver
  participant Kafka
  participant Dispatcher as EventExtensionDispatcher
  participant Registry as SubscriptionRegistry
  participant Script as Script Engine

  Camel->>Pub: publish(PAYMENT_POSTED, envelope)
  Pub->>Resolver: resolve channel + partition key
  Resolver->>Kafka: send(destination_name from DB)
  Kafka->>Dispatcher: consume event
  Dispatcher->>Registry: findSubscriptions(event_code)
  Registry-->>Dispatcher: [sub1, sub2]
  loop each subscription
    Dispatcher->>Dispatcher: evaluate filter_expression
    Dispatcher->>Script: execute(script_id, event)
  end
```

**Module:** `h2h-event-extensions` (consumer + dispatcher)

### 4.2 Webhook Subscriptions

External partner/system acknowledgement via HTTPS — configured at runtime:

**Table: `webhook_subscription`** (see [Extensibility Framework](/docs/14-extensibility-framework.md))

On `PAYMENT_POSTED` (logical code) → POST signed payload to partner ERP endpoint.

### 4.3 Hook → Event Bridge

Pipeline hooks can **emit custom events** at runtime:

```groovy
// SCRIPT hook: camel.post_step
if (exchange.getProperty('h2h.status') == 'POSTED') {
    eventPublisher.publish('PARTNER_CUSTOM_NOTIFY', [
        correlationId: h2hContext.correlationId(),
        customField: h2hContext.attributes().get('custom.NG_CBN_REF')
    ], h2hContext)
}
```

Custom events must be registered in `event_def` + `event_channel_def` before publish.

### 4.4 Camel Route as Event Handler

Subscriptions can target internal routes:

```yaml
handler_type: CAMEL_ROUTE
handler_ref: direct:erp-payment-notify
```

Route registered in JAR; **subscription** (when to invoke) is runtime config.

***

## 5. CustomizationProfile + Events

When a `CustomizationProfile` is published:

1. `CUSTOMIZATION_PUBLISHED` event fired (logical code)
2. All pods invalidate customization cache
3. **Event subscriptions** scoped to partner/country re-evaluated
4. Observability applies new SLA rules to subsequent events
5. File management applies new delivery method to next outbound file

Customization and events are linked — one publish updates **behavior and event handling** together.

See [Universal Library Extensibility](/docs/20-universal-library-extensibility.md).

***

## 6. Composable Services (Event-Connected)

Libraries compose into **one or many services**; events are the integration glue.

```mermaid
flowchart LR
  subgraph s1 [h2h-payments-runtime]
    P[Payment Routes]
  end

  subgraph s2 [h2h-file-gateway]
    F[File Poll + Deliver]
  end

  subgraph s3 [h2h-admin-api]
    A[Publish Config]
  end

  subgraph s4 [h2h-event-worker]
    E[Event Subscriptions]
    W[Webhooks]
  end

  P -->|PAYMENT_POSTED| K[Broker - DB-resolved topics]
  F -->|FILE_DELIVERED| K
  A -->|CONFIG_PUBLISHED| K
  K --> E
  K --> W
```

| Service          | Acknowledges system via                             |
| ---------------- | --------------------------------------------------- |
| Payments runtime | Publishes `PAYMENT_POSTED` / `PAYMENT_FAILED`       |
| File gateway     | Updates `file_registry`, publishes `FILE_DELIVERED` |
| Admin API        | Publishes `CONFIG_PUBLISHED`                        |
| Event worker     | Delivers webhooks, runs subscription scripts        |
| Partner ERP      | Receives webhook / polls status API                 |

**No shared database required between services** for acknowledgement — events + `correlationId` suffice (though `file_registry` DB is often shared).

***

## 7. Extension Points for Event Handling

| Library                    | Runtime extension                                           | Event role      |
| -------------------------- | ----------------------------------------------------------- | --------------- |
| **h2h-camel-core**         | Publish standard transaction events                         | Producer        |
| **h2h-observability**      | `AuditEventPublisher`, SLA breach events                    | Producer        |
| **h2h-file-management**    | File lifecycle events                                       | Producer        |
| **h2h-event-extensions**   | `EventSubscription` dispatcher                              | Consumer router |
| **h2h-webhook-dispatcher** | Webhook delivery                                            | Consumer        |
| **h2h-script-engine**      | Script handlers for subscriptions/hooks                     | Handler         |
| **h2h-job-scheduler**      | `JOB_TRIGGER` on event; delayed `h2h.jobs.execute` consumer | Consumer        |
| **h2h-extension-kernel**   | Validates subscriptions at publish                          | Governance      |

### 7.1 SPI: EventHandlerProvider (L4 plugin)

For custom handler types beyond SCRIPT / WEBHOOK / CAMEL\_ROUTE:

```java
public interface EventHandlerProvider extends ExtensionProvider {
    String handlerType();   // e.g. "SAP_IDOC"
    void handle(H2hEvent event, HandlerConfig config);
}
```

Registered via plugin JAR; **subscriptions** referencing `handler_type: SAP_IDOC` are runtime config.

***

## 8. Idempotency and Ordering

### 8.1 Event Consumer Guarantees

| Guarantee              | Implementation                                                                              |
| ---------------------- | ------------------------------------------------------------------------------------------- |
| At-least-once delivery | Kafka consumer groups                                                                       |
| Idempotent handlers    | `event_handler_log` dedup by `eventId + subscriptionId`                                     |
| Ordering per partner   | `partition_strategy` + `partition_key_fields` on `event_channel_def` (default: `partnerId`) |
| Dead letter            | Failed handlers → `DLQ_MESSAGE` channel (configurable destination)                          |

**Table: `event_handler_log`**

| Column            | Description              |
| ----------------- | ------------------------ |
| `event_id`        | From envelope            |
| `subscription_id` | FK                       |
| `status`          | SUCCESS, FAILED, SKIPPED |
| `processed_at`    | Timestamp                |

### 8.2 Runtime Handler Retry

Subscription config:

```json
{
  "maxRetries": 3,
  "retryDelayMs": 10000,
  "onExhaustion": "DLQ"
}
```

***

## 9. Admin Portal — Event Extension UI

| Screen                 | Capability                                       |
| ---------------------- | ------------------------------------------------ |
| Event catalog          | List `event_def` + linked `event_channel_def`    |
| Channel manager        | Topic/queue name, partition strategy, scope      |
| Subscription designer  | `event_code` + filter + handler                  |
| Custom event registrar | New `event_def` + channel binding                |
| Webhook manager        | URL, auth, `event_code` binding                  |
| Test harness           | Publish sample event → preview handler execution |
| Handler execution log  | Search `event_handler_log` by correlationId      |

***

## 10. Publish Workflow (Unified)

Publishing event subscriptions follows the same workflow as all runtime extensions:

```
DRAFT → test (sample event) → PENDING_APPROVAL → PUBLISHED → Kafka invalidation
```

`ExtensionValidator` checks:

* `event_code` exists in `event_def` and has a `PUBLISHED` `event_channel_def`
* `handler_ref` resolves (script published, route exists, webhook defined)
* `filter_expression` valid JSONata
* Scope permissions

***

## 11. Architecture Summary

| Question                       | Answer                                                                               |
| ------------------------------ | ------------------------------------------------------------------------------------ |
| Is the platform event-driven?  | **Yes** — Kafka/RabbitMQ backbone; channels and partitions **database-driven**       |
| Extensible at runtime?         | **Yes** — subscriptions, webhooks, hooks, scripts, jobs, customization — no redeploy |
| Microservices required?        | **No** — single runtime default; services communicate via events if split            |
| Hot-swap JARs in prod?         | **No** — plugin JARs use rolling deploy; behavior extension is DB-driven             |
| Cross-service acknowledgement? | **Yes** — events + correlationId + file\_registry + webhooks                         |
| Tied to library extensibility? | **Yes** — `CustomizationProfile` + `H2hContext` on every event envelope              |

***

## 12. Decision Guide

| Need                               | Use                                                            |
| ---------------------------------- | -------------------------------------------------------------- |
| Notify ERP after payment           | `event_subscription` → webhook or script                       |
| Custom logic after Finacle post    | `hook` at `finacle.post_post` or subscribe to `PAYMENT_POSTED` |
| Invalidate caches on config change | Built-in consumer for `CONFIG_PUBLISHED`                       |
| New protocol handler (SAP, MQ)     | L4 `EventHandlerProvider` plugin JAR                           |
| Partner ACK file                   | Sync in Camel route + `FILE_DELIVERED` event                   |
| Async recon                        | Subscribe to `PAYMENT_POSTED` → trigger recon job              |

***

## 13. New Module

```
h2h-event-extensions/
├── api/
│   ├── EventPublisher.java
│   ├── EventChannelResolver.java
│   ├── PartitionKeyComputer.java
│   ├── EventSubscriptionRegistry.java
│   └── EventHandlerProvider.java
├── dispatcher/
│   ├── EventExtensionDispatcher.java
│   └── SubscriptionFilterEvaluator.java
├── channel/
│   ├── EventChannelCache.java
│   └── DynamicKafkaConsumerRegistrar.java
├── kafka/
│   ├── H2hEventSerializer.java
│   └── EventConsumerConfig.java
└── config/
    └── EventExtensionsAutoConfiguration.java
```

***

## 14. Related Documents

* [46 Database-Driven Events](/docs/46-database-driven-events.md)
* [Universal Library Extensibility](/docs/20-universal-library-extensibility.md)
* [Extensibility Framework](/docs/14-extensibility-framework.md)
* [Execution Context](/docs/18-execution-context.md)
* [Monitoring and Logging](/docs/17-monitoring-and-logging.md)
* [File Management System](/docs/15-file-management-system.md)
* [Modular JAR Architecture](/docs/03-modular-jar-architecture.md)
* [Cloud-Agnostic Deployment](/docs/19-cloud-agnostic-deployment.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://host2host.onibonje.com/docs/21-event-driven-runtime-extensibility.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
