Skip to main content

Event-Driven Process Architecture

Overview​

The BankLingo platform implements an event-driven process automation architecture that allows business processes to be triggered automatically when specific events occur in the system. This architecture uses the ProcessEventDispatcher service to publish events when entities are created or updated, which can then trigger BPMN process definitions.

Event Context Naming Standards

All event contexts now follow standardized naming conventions for consistency across all entity types. See the Event Context Standards guide for complete details on field naming, enum values, and implementation patterns.

Key Standards:

  • Òœ… Status fields use status or accountStatus (not entity-specific names)
  • Òœ… Enums sent as integer values + string descriptions
  • Òœ… Account numbers use accountNumber consistently
  • Òœ… Database commits happen BEFORE event dispatch

Architecture Components

1. ProcessEventDispatcher Service​

Location: BankLingo.Entities/ExecutionEngine/ProcessEventDispatcher.cs

The dispatcher is responsible for:

  • Publishing events when entities are created/updated
  • Creating process context with relevant entity data
  • Triggering configured BPMN process definitions
  • Managing the process lifecycle

Key Methods:

Code Removed

Implementation details removed for security.

Contact support for implementation guidance.

2. Process Entity Types​

Entities that can trigger processes are defined in the ProcessEntityType enum:

Entity TypeEnum ValueDescriptionHandler
None0No specific entityN/A
Entity1Generic entity baseN/A
Contact2Customer/ClientAdministrationCoreContactCommandHandlers
Loan3Loan AccountAdministrationCoreLoanCommandHandlers
Deposit4Deposit AccountAdministrationCoreDepositCommandHandlers
Transaction11Generic transactionMultiple handlers
Teller13Teller transactionAdministrationCoreTelleringTransactionCommandHandlers
InwardTransaction14Inbound NIP/NIBSSNIP Integration
Customer100Channel customer (same as Contact)Channel handlers
LoanRequest101Channel loan requestSelfServiceLoanCommandHandlers
Transfer102Fund transferSelfServiceBankingCommandHandlers
BillsPayment103Bills paymentSelfServiceBankingCommandHandlers
AirtimeRecharge104Airtime rechargeSelfServiceBankingCommandHandlers
DataRecharge105Data bundle purchaseSelfServiceBankingCommandHandlers
Reconciliation200Reconciliation processBatch processes

3. Process Trigger Events​

Events defined in ProcessDefinitionTriggerEventsEnum:

Core Banking Events​

EventValueDescriptionEntity Type
OnCustomerCreation1Customer/Contact createdContact (2)
OnAccountCreation2Deposit account createdDeposit (4)
OnLoanCreation3Loan account createdLoan (3)
OnDepositCreation4Deposit product createdDeposit (4)
OnTransactionCreation5Transaction postedTransaction (11)

Teller Events​

EventValueDescriptionEntity Type
OnCashDeposit21Cash deposited at tellerTeller (13)
OnCashWithdrawal22Cash withdrawn at tellerTeller (13)
OnTellerBalanceCheck23Teller balance verifiedTeller (13)
OnTellerEndOfDay24Teller day closedTeller (13)

Transfer Events​

EventValueDescriptionEntity Type
OnTransferReceived25Transfer receivedTransfer (102)
OnTransferInitiated26Transfer startedTransfer (102)
OnTransferCompleted27Transfer completedTransfer (102)

Bills Payment Events​

EventValueDescriptionEntity Type
OnBillsPaymentTransactionInitiated28Bills payment startedBillsPayment (103)
OnBillsPaymentTransactionCompleted29Bills payment completedBillsPayment (103)
OnBillsPaymentTransactionFailed30Bills payment failedBillsPayment (103)
OnBillsPaymentTransactionReversed31Bills payment reversedBillsPayment (103)

Airtime Recharge Events​

EventValueDescriptionEntity Type
OnAirtimeRechargeTransactionInitiated32Airtime recharge startedAirtimeRecharge (104)
OnAirtimeRechargeTransactionCompleted33Airtime recharge completedAirtimeRecharge (104)
OnAirtimeRechargeTransactionFailed34Airtime recharge failedAirtimeRecharge (104)
OnAirtimeRechargeTransactionReversed35Airtime recharge reversedAirtimeRecharge (104)

Data Recharge Events​

EventValueDescriptionEntity Type
OnDataRechargeTransactionInitiated36Data recharge startedDataRecharge (105)
OnDataRechargeTransactionCompleted37Data recharge completedDataRecharge (105)
OnDataRechargeTransactionFailed38Data recharge failedDataRecharge (105)
OnDataRechargeTransactionReversed39Data recharge reversedDataRecharge (105)

Process Context Models​

Each entity type has a corresponding context model that carries relevant data to the process engine.

ContactProcessContext​

Used when customers are created or updated.

Properties:

{
"entityType": 2,
"entityId": 12345,
"clientCode": "CUST001",
"firstName": "John",
"middleName": "Michael",
"lastName": "Doe",
"contactEmail": "john.doe@example.com",
"contactMobile": "+2348012345678",
"clientState": "Active",
"isIndividual": true,
"clientType": "Retail",
"bvn": "12345678901",
"createdAt": "2024-01-15T10:30:00Z",
"createdBy": "admin"
}

Use Cases:

  • Customer onboarding workflows
  • KYC verification processes
  • Welcome message automation
  • Account officer assignment

LoanProcessContext​

Used when core banking loan accounts are created.

Properties:

{
"entityType": 3,
"entityId": 67890,
"loanAccountNumber": "LN001234567",
"principalAmount": 500000.00,
"interestRate": 18.5,
"tenureMonths": 12,
"loanStatus": "Partial_Application",
"accountName": "John Doe - Personal Loan",
"firstRepaymentDate": "2024-02-15T00:00:00Z",
"disbursementDate": "2024-01-20T00:00:00Z",
"productId": 45,
"clientId": 12345,
"createdAt": "2024-01-15T10:30:00Z",
"createdBy": "loan_officer_01"
}

Use Cases:

  • Loan approval workflows
  • Disbursement automation
  • Credit committee review
  • Loan documentation generation
  • Repayment schedule notifications

DepositProcessContext​

Used when deposit accounts (savings, current, fixed deposit) are created.

Properties:

{
"entityType": 4,
"entityId": 54321,
"accountNumber": "0123456789",
"accountName": "John Doe Savings Account",
"accountType": "Savings_Account",
"accountStatus": "Pending_Approval",
"balance": 0.00,
"interestRate": 5.0,
"productId": 12,
"clientId": 12345,
"branchId": 7,
"createdAt": "2024-01-15T10:30:00Z",
"createdBy": "branch_officer_02"
}

Use Cases:

  • Account opening workflows
  • Account approval automation
  • Welcome kit generation
  • Debit card issuance
  • Account statement setup

LoanRequestProcessContext​

Used for channel/self-service loan requests (different from core banking loans).

Properties:

{
"entityType": 101,
"entityId": 98765,
"loanAmount": 250000.00,
"loanPurpose": "Business expansion",
"tenureMonths": 6,
"requestStatus": "Pending",
"customerAccountNumber": "0123456789",
"customerName": "John Doe",
"userId": 7890,
"initiatorUserId": 7890,
"createdAt": "2024-01-15T10:30:00Z",
"createdBy": "john.doe@example.com"
}

User Tracking Fields:

  • userId: The end user who owns the loan request
  • initiatorUserId: The user who initiated this specific action (may be different in agency banking)

Use Cases:

  • Loan request approval workflows
  • Credit scoring automation
  • Document collection
  • Offer letter generation

TransferProcessContext​

Used for fund transfers between accounts.

Properties:

{
"entityType": 102,
"entityId": 45678,
"sourceAccountNumber": "0123456789",
"destinationAccountNumber": "9876543210",
"amount": 50000.00,
"currency": "NGN",
"status": 0,
"statusDescription": "PENDING",
"transferType": "IntraBank",
"narration": "Payment for services",
"beneficiaryName": "Jane Smith",
"beneficiaryBank": "Access Bank",
"userId": 7890,
"initiatorUserId": 7890,
"createdAt": "2024-01-15T10:30:00Z",
"createdBy": "john.doe@example.com"
}

Note: Òœ… Uses standardized status field (integer enum) + statusDescription (string). See Event Context Standards for details.

Status Values (SelfServiceTransactionStatus):

  • 0 = PENDING - Transaction initiated
  • 1 = PROCESSING - Currently being processed
  • 2 = SUCCESSFUL - Completed successfully
  • 3 = FAILED - Transaction failed
  • 4 = REVERSED - Transaction reversed

Use Cases:

  • Large transfer approval workflows
  • Fraud detection automation
  • Beneficiary verification
  • Transfer limit enforcement
  • Compliance checks

BillsPaymentProcessContext​

Used for bills payment transactions.

Properties:

{
"entityType": 103,
"entityId": 23456,
"billerId": "EKEDC001",
"billerName": "Eko Electricity Distribution",
"amount": 15000.00,
"accountNumber": "0123456789",
"customerReference": "1234567890",
"status": 0,
"statusDescription": "PENDING",
"billerCategory": "Electricity",
"userId": 7890,
"initiatorUserId": 7890,
"createdAt": "2024-01-15T10:30:00Z",
"createdBy": "john.doe@example.com"
}

Note: Òœ… Uses standardized status field (integer enum) + statusDescription (string). See Event Context Standards.

Use Cases:

  • High-value bills approval
  • Failed payment retry automation
  • Biller reconciliation
  • Customer notification

AirtimeRechargeProcessContext​

Used for airtime recharge transactions.

Properties:

{
"entityType": 104,
"entityId": 34567,
"phoneNumber": "+2348012345678",
"amount": 1000.00,
"provider": "MTN",
"status": 0,
"statusDescription": "PENDING",
"accountNumber": "0123456789",
"userId": 7890,
"initiatorUserId": 7890,
"createdAt": "2024-01-15T10:30:00Z",
"createdBy": "john.doe@example.com"
}

Note: Òœ… Uses standardized status field (integer enum) + statusDescription (string). See Event Context Standards.

Use Cases:

  • Failed recharge retry
  • Bulk recharge processing
  • Promotional bonus application
  • Usage analytics

DataRechargeProcessContext​

Used for data bundle purchase transactions.

Properties:

{
"entityType": 105,
"entityId": 45678,
"phoneNumber": "+2348012345678",
"dataBundle": "10GB Monthly",
"amount": 3000.00,
"provider": "Airtel",
"status": 0,
"statusDescription": "PENDING",
"accountNumber": "0123456789",
"userId": 7890,
"initiatorUserId": 7890,
"createdAt": "2024-01-15T10:30:00Z",
"createdBy": "john.doe@example.com"
}

Note: Òœ… Uses standardized status field (integer enum) + statusDescription (string). See Event Context Standards.

Use Cases:

  • Failed recharge retry
  • Bundle recommendation
  • Promotional offers
  • Usage tracking

Integration Pattern​

Standard Implementation​

To integrate the process dispatcher into a command handler, follow this pattern:

Code Removed

Implementation details removed for security.

Contact support for implementation guidance.

Key Integration Principles​

  1. Call After Save: Always dispatch events AFTER _uow.SaveChanges() so the entity has a valid ID
  2. Use Try-Catch: Wrap dispatcher calls in try-catch to prevent process failures from breaking transactions
  3. Log Warnings: Log failures as warnings (not errors) since they shouldn't break the main operation
  4. Simple Enum Names: Use enum names without namespace qualification (e.g., ProcessEntityType.Contact)
  5. Navigation Properties: Access related entity properties via navigation (e.g., entity.ClientContact?.ContactEmail)
  6. User Context: Pass GetTokenData()?.UserName for audit trail

Implemented Integrations​

Òœ… Contact Handler​

File: CB.Administration.Api/Commands/BPMCore/Contacts/AdministrationCoreContactCommandHandlers.cs

Event: OnCustomerCreation
Entity Type: Contact (2)

Integration Point: After contact creation in Handle(CreateContactCommand) method

Context Properties:

  • clientCode, firstName, middleName, lastName
  • contactEmail, contactMobile (via ClientContact navigation)
  • clientState, isIndividual, clientType, bvn

Example Process Use Cases:

  • Welcome email/SMS automation
  • KYC document collection workflow
  • Account opening recommendations
  • Customer segmentation

Òœ… Loan Handler​

File: CB.Administration.Api/Commands/BPMCore/Loans/AdministrationCoreLoanCommandHandlers.cs

Event: OnLoanCreation
Entity Type: Loan (3)

Integration Point: After loan account creation in Handle(CreateLoanCommand) method

Context Properties:

  • loanAccountNumber, principalAmount, interestRate, tenureMonths
  • loanStatus, accountName
  • firstRepaymentDate, disbursementDate
  • productId, clientId

Example Process Use Cases:

  • Multi-level loan approval workflow
  • Credit committee review
  • Loan documentation generation
  • Disbursement automation
  • Repayment reminder scheduling

Òœ… Deposit Handler​

File: CB.Administration.Api/Commands/BPMCore/Deposits/AdministrationCoreDepositCommandHandlers.cs

Event: OnAccountCreation
Entity Type: Deposit (4)

Integration Point: After deposit account creation in Handle(CreateDepositCommand) method

Context Properties:

  • accountNumber, accountName, accountType
  • accountStatus, balance, interestRate
  • productId, clientId, branchId

Example Process Use Cases:

  • Account approval workflow
  • Debit card issuance
  • Welcome kit generation
  • Account statement setup
  • Signatory verification

User Tracking in Channel Contexts​

Channel/self-service contexts include two user tracking fields:

userId​

The end user who owns the transaction or request. This is the customer using the channel (mobile app, internet banking, agent channel).

initiatorUserId​

The user who initiated this specific action. In most cases, this is the same as userId. However, in agency banking scenarios, these differ:

  • userId: The customer whose account is being used
  • initiatorUserId: The agent performing the transaction on behalf of the customer

Example:

{
"userId": 12345, // Customer: John Doe
"initiatorUserId": 67890, // Agent: Jane Smith (performing transaction for John)
"accountNumber": "0123456789", // John's account
"amount": 50000.00
}

This distinction enables:

  • Proper audit trails
  • Agent performance tracking
  • Fraud detection
  • Commission calculation
  • Compliance reporting

Configuration and Deployment​

1. Dependency Injection Setup​

The dispatcher is registered in Startup.cs:

Code Removed

Implementation details removed for security.

Contact support for implementation guidance.

Scope: Scoped (per HTTP request) - ensures proper isolation between tenant requests.

2. Process Definition Configuration​

Process definitions are created in the BPM Designer and must be configured to listen for specific events.

Example Process Definition Trigger Configuration (YAML):

triggers:
- event: onCustomerCreation
entityType: contact
condition: "clientState == 'Active' && isIndividual == true"
variables:
customerName: "{{ firstName }} {{ lastName }}"
customerEmail: "{{ contactEmail }}"
bvn: "{{ bvn }}"

3. Event-to-Process Mapping​

The process engine automatically routes events to matching process definitions based on:

  1. Event Type: Must match the trigger event
  2. Entity Type: Must match the entity type (optional)
  3. Condition: Must evaluate to true (optional)
  4. Tenant: Process must be active for the tenant

Testing Process Integration​

Manual Testing​

  1. Create Entity: Perform the operation that creates the entity (e.g., create a customer)
  2. Check Logs: Look for dispatcher log entries indicating event was published
  3. Verify Process: Check if process instance was created in process dashboard
  4. Monitor Execution: Follow process execution through BPMN diagram
  5. Validate Outcome: Confirm process completed expected tasks

Log Patterns to Look For​

Successful Dispatch:

INFO: Dispatching event OnCustomerCreation for Contact ID 12345
INFO: Process definition 'customer-onboarding' triggered for Contact 12345

Dispatch Warning (non-critical):

WARN: Failed to dispatch Contact creation event for Contact ID 12345
Exception: [Details]

Process Execution:

INFO: Process instance 'cust-onboard-12345' started
INFO: Task 'send-welcome-email' completed successfully

Common Integration Patterns​

Pattern 1: Simple Entity Creation​

For entities with straightforward creation:

Code Removed

Implementation details removed for security.

Contact support for implementation guidance.

Pattern 2: Conditional Dispatch​

Only dispatch events when certain conditions are met:

Code Removed

Implementation details removed for security.

Contact support for implementation guidance.

Pattern 3: Multiple Event Dispatch​

Dispatch different events based on state:

Code Removed

Implementation details removed for security.

Contact support for implementation guidance.

Pattern 4: State Transition Dispatch​

Dispatch when entity changes state:

Code Removed

Implementation details removed for security.

Contact support for implementation guidance.


Best Practices​

1. Error Handling​

DO:

Code Removed

Implementation details removed for security.

Contact support for implementation guidance.

DON'T:

Code Removed

Implementation details removed for security.

Contact support for implementation guidance.

2. Context Properties​

DO: Include relevant business context

Code Removed

Implementation details removed for security.

Contact support for implementation guidance.

DON'T: Include sensitive data or large objects

Code Removed

Implementation details removed for security.

Contact support for implementation guidance.

3. Event Timing​

DO: Dispatch after commit

Code Removed

Implementation details removed for security.

Contact support for implementation guidance.

DON'T: Dispatch before save

Code Removed

Implementation details removed for security.

Contact support for implementation guidance.

4. Transaction Boundaries​

DO: Keep dispatcher calls outside transaction scope

Code Removed

Implementation details removed for security.

Contact support for implementation guidance.

DON'T: Dispatch inside transaction (can cause deadlocks)


Troubleshooting​

Event Not Triggering Process​

Check:

  1. Is the process definition active?
  2. Does the event type match the trigger configuration?
  3. Does the entity type match (if specified)?
  4. Does the condition evaluate to true (if specified)?
  5. Is the tenant correct?

Solution: Review process definition trigger configuration and logs.


Process Fails to Start​

Check:

  1. Are all required process variables available in context?
  2. Is the process definition valid BPMN?
  3. Are there any script errors in the process?
  4. Check process engine logs for errors

Solution: Validate process definition and context data.


Dispatcher Exceptions​

Check:

  1. Is IProcessEventDispatcher registered in DI?
  2. Are you catching exceptions properly?
  3. Check logs for stack traces

Solution: Verify DI registration and error handling.


Performance Considerations​

Event Volume​

High-volume events (e.g., transactions) can impact performance. Consider:

  1. Async Processing: Events are processed asynchronously - main transaction isn't blocked
  2. Process Complexity: Keep process definitions simple for high-volume events
  3. Conditional Triggers: Use conditions to filter unnecessary process instances
  4. Batch Processing: For bulk operations, consider batch event processing

Context Size​

Keep context dictionaries small:

  • Òœ… Good: 10-20 key properties (< 5KB)
  • Òő ï¸ Moderate: 50 properties (5-20KB)
  • ҝŒ Bad: 100+ properties or large objects (> 50KB)

Large contexts can slow down process engine and database.


Future Enhancements​

Planned Entity Integrations​

  1. Teller Transactions (Deferred - Complex)

    • Multiple transaction types require conditional logic
    • Events: OnCashDeposit, OnCashWithdrawal, OnTellerEndOfDay
  2. Channel Transactions (Deferred - Complex)

    • Quote-based workflow with multiple states
    • Events: OnTransferInitiated/Completed, OnBillsPaymentInitiated/Completed
    • Events: OnAirtimeRechargeInitiated/Completed, OnDataRechargeInitiated/Completed

Additional Features​

  • State machine integration for complex entity lifecycles
  • Bulk event processing for batch operations
  • Event replay for process definition updates
  • Process version migration support

Conclusion​

The Event-Driven Process Architecture provides a powerful, flexible way to automate business processes based on system events. With the core entity integrations (Contact, Loan, Deposit) now complete, you can create BPMN process definitions that automatically respond to customer onboarding, loan origination, and account opening events.

For additional support or to request new entity integrations, consult the development team or refer to DISPATCHER_IMPLEMENTATION_COMPLETE.md for implementation details.