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.
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
statusoraccountStatus(not entity-specific names) - Γ’Εβ¦ Enums sent as integer values + string descriptions
- Γ’Εβ¦ Account numbers use
accountNumberconsistently - Γ’Εβ¦ 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:
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 Type | Enum Value | Description | Handler |
|---|---|---|---|
| None | 0 | No specific entity | N/A |
| Entity | 1 | Generic entity base | N/A |
| Contact | 2 | Customer/Client | AdministrationCoreContactCommandHandlers |
| Loan | 3 | Loan Account | AdministrationCoreLoanCommandHandlers |
| Deposit | 4 | Deposit Account | AdministrationCoreDepositCommandHandlers |
| Transaction | 11 | Generic transaction | Multiple handlers |
| Teller | 13 | Teller transaction | AdministrationCoreTelleringTransactionCommandHandlers |
| InwardTransaction | 14 | Inbound NIP/NIBSS | NIP Integration |
| Customer | 100 | Channel customer (same as Contact) | Channel handlers |
| LoanRequest | 101 | Channel loan request | SelfServiceLoanCommandHandlers |
| Transfer | 102 | Fund transfer | SelfServiceBankingCommandHandlers |
| BillsPayment | 103 | Bills payment | SelfServiceBankingCommandHandlers |
| AirtimeRecharge | 104 | Airtime recharge | SelfServiceBankingCommandHandlers |
| DataRecharge | 105 | Data bundle purchase | SelfServiceBankingCommandHandlers |
| Reconciliation | 200 | Reconciliation process | Batch processes |
3. Process Trigger Eventsβ
Events defined in ProcessDefinitionTriggerEventsEnum:
Core Banking Eventsβ
| Event | Value | Description | Entity Type |
|---|---|---|---|
| OnCustomerCreation | 1 | Customer/Contact created | Contact (2) |
| OnAccountCreation | 2 | Deposit account created | Deposit (4) |
| OnLoanCreation | 3 | Loan account created | Loan (3) |
| OnDepositCreation | 4 | Deposit product created | Deposit (4) |
| OnTransactionCreation | 5 | Transaction posted | Transaction (11) |
Teller Eventsβ
| Event | Value | Description | Entity Type |
|---|---|---|---|
| OnCashDeposit | 21 | Cash deposited at teller | Teller (13) |
| OnCashWithdrawal | 22 | Cash withdrawn at teller | Teller (13) |
| OnTellerBalanceCheck | 23 | Teller balance verified | Teller (13) |
| OnTellerEndOfDay | 24 | Teller day closed | Teller (13) |
Transfer Eventsβ
| Event | Value | Description | Entity Type |
|---|---|---|---|
| OnTransferReceived | 25 | Transfer received | Transfer (102) |
| OnTransferInitiated | 26 | Transfer started | Transfer (102) |
| OnTransferCompleted | 27 | Transfer completed | Transfer (102) |
Bills Payment Eventsβ
| Event | Value | Description | Entity Type |
|---|---|---|---|
| OnBillsPaymentTransactionInitiated | 28 | Bills payment started | BillsPayment (103) |
| OnBillsPaymentTransactionCompleted | 29 | Bills payment completed | BillsPayment (103) |
| OnBillsPaymentTransactionFailed | 30 | Bills payment failed | BillsPayment (103) |
| OnBillsPaymentTransactionReversed | 31 | Bills payment reversed | BillsPayment (103) |
Airtime Recharge Eventsβ
| Event | Value | Description | Entity Type |
|---|---|---|---|
| OnAirtimeRechargeTransactionInitiated | 32 | Airtime recharge started | AirtimeRecharge (104) |
| OnAirtimeRechargeTransactionCompleted | 33 | Airtime recharge completed | AirtimeRecharge (104) |
| OnAirtimeRechargeTransactionFailed | 34 | Airtime recharge failed | AirtimeRecharge (104) |
| OnAirtimeRechargeTransactionReversed | 35 | Airtime recharge reversed | AirtimeRecharge (104) |
Data Recharge Eventsβ
| Event | Value | Description | Entity Type |
|---|---|---|---|
| OnDataRechargeTransactionInitiated | 36 | Data recharge started | DataRecharge (105) |
| OnDataRechargeTransactionCompleted | 37 | Data recharge completed | DataRecharge (105) |
| OnDataRechargeTransactionFailed | 38 | Data recharge failed | DataRecharge (105) |
| OnDataRechargeTransactionReversed | 39 | Data recharge reversed | DataRecharge (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 requestinitiatorUserId: 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 initiated1= PROCESSING - Currently being processed2= SUCCESSFUL - Completed successfully3= FAILED - Transaction failed4= 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:
Implementation details removed for security.
Contact support for implementation guidance.
Key Integration Principlesβ
- Call After Save: Always dispatch events AFTER
_uow.SaveChanges()so the entity has a valid ID - Use Try-Catch: Wrap dispatcher calls in try-catch to prevent process failures from breaking transactions
- Log Warnings: Log failures as warnings (not errors) since they shouldn't break the main operation
- Simple Enum Names: Use enum names without namespace qualification (e.g.,
ProcessEntityType.Contact) - Navigation Properties: Access related entity properties via navigation (e.g.,
entity.ClientContact?.ContactEmail) - User Context: Pass
GetTokenData()?.UserNamefor 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 usedinitiatorUserId: 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:
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:
- Event Type: Must match the trigger event
- Entity Type: Must match the entity type (optional)
- Condition: Must evaluate to true (optional)
- Tenant: Process must be active for the tenant
Testing Process Integrationβ
Manual Testingβ
- Create Entity: Perform the operation that creates the entity (e.g., create a customer)
- Check Logs: Look for dispatcher log entries indicating event was published
- Verify Process: Check if process instance was created in process dashboard
- Monitor Execution: Follow process execution through BPMN diagram
- 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:
Implementation details removed for security.
Contact support for implementation guidance.
Pattern 2: Conditional Dispatchβ
Only dispatch events when certain conditions are met:
Implementation details removed for security.
Contact support for implementation guidance.
Pattern 3: Multiple Event Dispatchβ
Dispatch different events based on state:
Implementation details removed for security.
Contact support for implementation guidance.
Pattern 4: State Transition Dispatchβ
Dispatch when entity changes state:
Implementation details removed for security.
Contact support for implementation guidance.
Best Practicesβ
1. Error Handlingβ
DO:
Implementation details removed for security.
Contact support for implementation guidance.
DON'T:
Implementation details removed for security.
Contact support for implementation guidance.
2. Context Propertiesβ
DO: Include relevant business context
Implementation details removed for security.
Contact support for implementation guidance.
DON'T: Include sensitive data or large objects
Implementation details removed for security.
Contact support for implementation guidance.
3. Event Timingβ
DO: Dispatch after commit
Implementation details removed for security.
Contact support for implementation guidance.
DON'T: Dispatch before save
Implementation details removed for security.
Contact support for implementation guidance.
4. Transaction Boundariesβ
DO: Keep dispatcher calls outside transaction scope
Implementation details removed for security.
Contact support for implementation guidance.
DON'T: Dispatch inside transaction (can cause deadlocks)
Troubleshootingβ
Event Not Triggering Processβ
Check:
- Is the process definition active?
- Does the event type match the trigger configuration?
- Does the entity type match (if specified)?
- Does the condition evaluate to true (if specified)?
- Is the tenant correct?
Solution: Review process definition trigger configuration and logs.
Process Fails to Startβ
Check:
- Are all required process variables available in context?
- Is the process definition valid BPMN?
- Are there any script errors in the process?
- Check process engine logs for errors
Solution: Validate process definition and context data.
Dispatcher Exceptionsβ
Check:
- Is IProcessEventDispatcher registered in DI?
- Are you catching exceptions properly?
- 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:
- Async Processing: Events are processed asynchronously - main transaction isn't blocked
- Process Complexity: Keep process definitions simple for high-volume events
- Conditional Triggers: Use conditions to filter unnecessary process instances
- 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β
-
Teller Transactions (Deferred - Complex)
- Multiple transaction types require conditional logic
- Events: OnCashDeposit, OnCashWithdrawal, OnTellerEndOfDay
-
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.