Digital Lending Journey with Java Microservices,Azure Cloud ,KYC/CDD/EDD Compliance with Fenergo, AML/Financial Crime with Actimize + Real Esatate Builder integration -Customer Amit R Journey
- Anand Nerurkar
- Sep 18
- 9 min read
Full event-driven lending journey with:
Customer: Amit R
Builder: Prestige Group
Platform: Kafka + Java Microservices + Azure (CosmosDB, Redis, Blob, ELK)
Compliance: Fenergo (KYC/CDD/EDD), Actimize (AML/CTR/STR/NTR/CBWR)
Integration: CBS (TCS BaNCS), Builder portal
Data: Relational tables (transactional), CosmosDB (event read model), Redis (fast access)
Security: Idempotency, correlation IDs, encryption, tokenization, audit logs, RBAC
Let’s break it step by step.
🔹 Customer Journey Flow (End-to-End)
1. UI / Customer Interaction
Amit R visits ABC Bank portal → login via Azure AD SSO (OAuth2/JWT token).
Clicks “Apply Loan”.
Enters loan details (amount, term).
Consent screen appears for:
KYC / CDD / EDD (Fenergo)
Credit Score (CIBIL/Experian)
Fraud Score (Experian Hunter, Feedzai)
AML / Financial Crime (Actimize)
Data sharing consent
Uploads documents: PAN, Aadhaar, income proof.
Clicks Submit Loan Application. (post to /loan )
Security at UI: TLS, Input validation, CAPTCHA, PII masking.
2. Loan Service (/loan)/ Backend (Microservices)
Loan Service get called for /loan and creates a loan_application entry with:
idempotencyKey, requestId, correlationId, msgKey
Status: Submitted
Saves:
loan_application table (core details).
consent_table (one row per consent type).
outbox_event (status=pending, type=loan-initiated).
Transaction is atomic → ensures no partial writes.
Customer sees:👉 “Your loan application ref# XXXX is received and under process.”
3. Outbox → Kafka
Outbox Poller:
Scans outbox every few seconds (not 15 min, real-time for UX).
Publishes loan-initiated event to Kafka.
Marks outbox row processed.
Event enriched with:
{LoanAppID, CorrelationID, RequestID, IdempotencyKey, Timestamp}.
Kafka config:
Topics encrypted (AES-256).
ACLs & mTLS enforced.
DLQ for poison messages.
Security: Database role-based access, TLS Kafka, message signing for integrity.
4. Event Consumers (CQRS Style)
Every business event is consumed by:
RedisCacheConsumer
Updates Redis with latest state (loanAppID → current status).
TTL enforced (to auto-expire stale apps).
CosmosDBConsumer
Writes raw immutable event → loan_events container.
Schema:
{ "eventId": "...", "loanAppId": "...", "eventType": "kyc-requested", "timestamp": "...", "correlationId": "...", "payloadHash": "...", "status": "PENDING|DONE|FAILED" }
Acts as read model for dashboards:
Ops dashboard → KYC/AML/STR pipeline progress.
CXO dashboard → Loan pipeline KPIs.
AuditConsumer
Pushes event to ELK (Elasticsearch + Logstash + Kibana).
Provides immutable audit trail with correlation ID.
Enables RBI/SEBI/FIU-IND audit queries.
5. KYC/AML & Risk Checks
5.1 KYC Service (Fenergo)
Listens to "loan-initiated" event
Inserts "kyc-requested" into outbox_event (status = PENDING)
Poller publishes "kyc-requested" to Kafka
KYC Service calls Fenergo Adapter - that call Fenergo API (for KYC/CDD/EDD) and return respone as kyc-done
Writes result to kyc_result table
Inserts "kyc-done" into outbox_event (status = PENDING)
Poller publishes "kyc-done"
5.2 Credit Service (CIBIL / Experian)
Listens to "loan-initiated"
Inserts "credit-score-requested" into outbox_event
Poller publishes credit-score-requested
Calls CIBIL/Experian API
Writes credit_result table
Inserts "credit-score-done" into outbox_event with status =pending
Poller publishes credit-score-done
5.3 Fraud Service (Experian Hunter / Feedzai)
Similar flow:
"fraud-score-requested" → poller → API call → fraud_result → "fraud-score-done" → poller
5.4 AML & Financial Crime Service (Actimize)
"aml-score-requested" → poller → Actimize → aml_result → "aml-done" → poller
"fincrime-score-requested" → poller → Actimize → financial_crime_result → "fincrime-done" → poller
6. Loan Evaluation
Loan Eval Service consumes all *-done events.
Aggregates results from result_table.
Rule engine decides:
Approve → loan-approved
Reject → loan-rejected (with reason)
Borderline → manual-review.
6. Manual Review (if required)
Ops Dashboard (powered by CosmosDB read model + ELK search):
Ops user sees flagged loans.
Manually approves/rejects.
Decision → published as manual-approve-done.
7. Loan Agreement & CBS Account Creation
On approval:
Loan Agreement MS:
Generates digitally signed loan contract (PKI, Aadhaar eSign).
Publishes loan-agreement-created.
Loan Account MS:
Consumes → integrates with CBS (TCS BaNCS) via secured API Gateway.
CBS creates Loan A/c
Publishes loan-account-created.
Notification MS:
Notify Amit R: “Loan approved. Loan A/C: 67890 created”
Notify Builder (Prestige Group): “Customer loan account setup complete”.
send notification to cusotmer/builder for loan approval,loan acount setup,disbursement done.
8. Loan Account Creation
Upon approval, Loan Account Service calls CBS (TCS BaNCS / Finacle).
Inserts loan_account table entry.
Emits loan-account-created event.
Customer notified: loan account created.
Builder notified: customer loan account set up.
Security: TLS + VPN / Private Network for CBS integration.
9. Builder Disbursement Request
Builder (Prestige Group) submits milestone-based disbursement request.
Uploads milestone proof (e.g., plinth completion) to blob storage.
Metadata stored in builder_disbursement_request table.
Event: builder-disbursement-requested emitted.
Security: RBAC, document encryption at rest (Azure Blob Storage).
10. Customer Approval for Disbursement
Customer reviews builder request → approves.
Event: customer-approval-for-disbursement emitted.
11. Loan Officer Validation
Loan officer validates milestone (photo verification, plinth completion).
Inserts into disbursement_validation table.
Event: disbursement-validation-done emitted.
12. Disbursement Service / CBS Integration
Upon validation, disbursement service:
Initiates Saga to CBS for fund transfer to builder.
Generates EMI schedule for approved disbursed amount.
Inserts disbursement table entry, emits disbursement-done event.
Security: End-to-end TLS, logging, idempotency check using idempotencyKey.
13. Compliance Reporting Pipeline
Compliance Type | Service | Frequency | Flow |
KYC / CDD / EDD | Fenergo | Daily / On-demand | Fenergo generates report → Bank Compliance Officer reviews → Upload to RBI portal |
CTR / NTR / STR / CBWR | Actimize | Daily / Weekly | Batch job → Flat file → SFTP → Actimize ETL → Rules segregation → Generate reports → Bank PO uploads to FIU-IND |
Actimize processes all AML / Financial Crime events.
Fenergo handles all KYC/CDD/EDD events.
All reports signed, encrypted, and audited.
14. Event & DB Key Tracking
Every table and event has:
idempotencyKey → ensures duplicate prevention
requestId → maps to user/API request
correlationId → tracks end-to-end journey
msgKey → unique Kafka message key
Redis and CosmosDB store events per idempotencyKey, read models updated for dashboard.
Audit table captures every event consumed/published.
15. Read Models / Dashboard
Per-event read models: kyc_read_model, credit_read_model, fraud_read_model, aml_read_model, financial_crime_read_model, loan_evaluation_read_model, builder_disbursement_read_model, disbursement_read_model.
Aggregated dashboard model example (CosmosDB / MongoDB):
{
loanAppId: "LA1001",
customerId: "CUST123",
customerName: "Amit R",
builder: "Prestige Group",
loanAmount: 7500000,
term: "15Y",
loanStatus: "Approved",
kyc: {status: "Pass", provider: "Fenergo", score: 98},
credit: {status: "Pass", score: 810, bureau: "CIBIL"},
fraud: {status: "Pass", provider: "Experian", riskLevel: "Low"},
aml: {status: "Pass", provider: "Actimize", score: "Low"},
financialCrime: {status: "Pass", provider: "Actimize", riskLevel: "None"},
loanAccountNo: "123456789",
disbursement: {
milestones: [
{milestone: "Plinth", status: "Approved"},
{milestone: "Roof", status: "Pending"}
],
totalDisbursed: "25L",
emiScheduleUrl: "blob://emi.pdf"
},
compliance: {
kycReport: "Submitted to RBI",
ctrReport: "Submitted to FIU-IND"
},
timestamps: {...},
idempotencyKey: "IDEMP-001",
requestId: "REQ-001",
correlationId: "CORR-001",
msgKey: "MSG-001"
}
🔹 DB Schema (Simplified)
. Write Model Tables
1.1 loan_application
loanAppId | customerId | amount | term | status | idempotencyKey | requestId | correlationId | msgKey | createdAt
LA1001 | CUST123 | 7500000 | 15Y | Submitted | IDEMP-001 | REQ-001 | CORR-001 | MSG-001 | 2025-09-17
1.2 consent
consentId | loanAppId | kyc | cdd | edd | credit | fraud | aml | finCrime | status | idempotencyKey | requestId | correlationId | msgKey
CONS-1001 | LA1001 | Y | Y | Y | Y | Y | Y | Y | Accepted | IDEMP-001 | REQ-001 | CORR-001 | MSG-001
1.3 outbox_event
eventId | loanAppId | eventType | payloadRef | status | idempotencyKey | requestId | correlationId | msgKey | createdAt
EVT-001 | LA1001 | loan-initiated | {...} | PENDING | IDEMP-001 | REQ-001 | CORR-001 | MSG-001 | 2025-09-17
EVT-002 | LA1001 | kyc-requested | {...} | PENDING | IDEMP-001 | REQ-001 | CORR-001 | MSG-002 | 2025-09-17
EVT-003 | LA1001 | kyc-done | {...} | PENDING | IDEMP-001 | REQ-001 | CORR-001 | MSG-003 | 2025-09-17
EVT-004 | LA1001 | credit-score-requested | {...} | PENDING | IDEMP-001 | REQ-001 | CORR-001 | MSG-004 | 2025-09-17
EVT-005 | LA1001 | credit-score-done | {...} | PENDING | IDEMP-001 | REQ-001 | CORR-001 | MSG-005 | 2025-09-17
EVT-006 | LA1001 | fraud-score-requested | {...} | PENDING | IDEMP-001 | REQ-001 | CORR-001 | MSG-006 | 2025-09-17
EVT-007 | LA1001 | fraud-score-done | {...} | PENDING | IDEMP-001 | REQ-001 | CORR-001 | MSG-007 | 2025-09-17
EVT-008 | LA1001 | aml-score-requested | {...} | PENDING | IDEMP-001 | REQ-001 | CORR-001 | MSG-008 | 2025-09-17
EVT-009 | LA1001 | aml-done | {...} | PENDING | IDEMP-001 | REQ-001 | CORR-001 | MSG-009 | 2025-09-17
EVT-010 | LA1001 | fincrime-score-requested | {...} | PENDING | IDEMP-001 | REQ-001 | CORR-001 | MSG-010 | 2025-09-17
EVT-011 | LA1001 | fincrime-done | {...} | PENDING | IDEMP-001 | REQ-001 | CORR-001 | MSG-011 | 2025-09-17
EVT-012 | LA1001 | loan-evaluated | {...} | PENDING | IDEMP-001 | REQ-001 | CORR-001 | MSG-012 | 2025-09-17
EVT-013 | LA1001 | loan-account-created | {...} | PENDING | IDEMP-001 | REQ-001 | CORR-001 | MSG-013 | 2025-09-17
EVT-014 | LACC-001 | builder-disbursement-requested| {...} | PENDING | IDEMP-001 | REQ-001 | CORR-001 | MSG-014 | 2025-09-17
EVT-015 | BDR-01 | disbursement-validation | {...} | PENDING | IDEMP-001 | REQ-001 | CORR-001 | MSG-015 | 2025-09-17
EVT-016 | LACC-001 | disbursement-done | {...} | PENDING | IDEMP-001 | REQ-001 | CORR-001 | MSG-016 | 2025-09-17
1.4 kyc_result
kycId | loanAppId | provider | status | score | idempotencyKey | requestId | correlationId | msgKey
KYC-001 | LA1001 | Fenergo | Pass | 98 | IDEMP-001 | REQ-001 | CORR-001 | MSG-003
1.5 credit_result
creditId | loanAppId | bureau | score | status | idempotencyKey | requestId | correlationId | msgKey
CR-001 | LA1001 | CIBIL | 810 | Pass | IDEMP-001 | REQ-001 | CORR-001 | MSG-005
1.6 fraud_result
fraudId | loanAppId | provider | riskLevel | status | idempotencyKey | requestId | correlationId | msgKey
FR-001 | LA1001 | Experian | Low | Pass | IDEMP-001 | REQ-001 | CORR-001 | MSG-007
1.7 aml_result
amlId | loanAppId | provider | score | status | idempotencyKey | requestId | correlationId | msgKey
AML-001 | LA1001 | Actimize | Low | Pass | IDEMP-001 | REQ-001 | CORR-001 | MSG-009
1.8 financial_crime_result
fcId | loanAppId | provider | riskLevel | status | idempotencyKey | requestId | correlationId | msgKey
FC-001 | LA1001 | Actimize | None | Pass | IDEMP-001 | REQ-001 | CORR-001 | MSG-011
1.9 loan_evaluation
evalId | loanAppId | result | remarks | idempotencyKey | requestId | correlationId | msgKey
EVAL-01 | LA1001 | Approved | Good profile | IDEMP-001 | REQ-001 | CORR-001 | MSG-012
1.10 loan_account
loanAccId | loanAppId | cbsAccNo | status | idempotencyKey | requestId | correlationId | msgKey
LACC-001 | LA1001 | 123456789 | Active | IDEMP-001 | REQ-001 | CORR-001 | MSG-013
1.11 builder_disbursement_request
reqId | loanAccId | builder | milestone | docUrl | status | idempotencyKey | requestId | correlationId | msgKey
BDR-01 | LACC-001 | PrestigeGrp | Plinth | blob://plinth | Pending | IDEMP-001 | REQ-001 | CORR-001 | MSG-014
1.12 disbursement_validation
valId | reqId | officerId | photoUrl | status | idempotencyKey | requestId | correlationId | msgKey
VAL-01 | BDR-01 | OFFICER-1 | blob://photo1 | Approved | IDEMP-001 | REQ-001 | CORR-001 | MSG-015
1.13 disbursement
disbId | loanAccId | amount | toAccount | status | emiScheduleUrl | idempotencyKey | requestId | correlationId | msgKey
DIS-01 | LACC-001 | 25L | PrestigeGrp-ACC | Done | blob://emi.pdf | IDEMP-001 | REQ-001 | CORR-001 | MSG-016
1.14 audit_log
auditId | eventId | service | action | timestamp | idempotencyKey | requestId | correlationId | msgKey
AUD-001 | EVT-001 | loan-service | event-published | 2025-09-17 | IDEMP-001 | REQ-001 | CORR-001 | MSG-001
AUD-002 | EVT-002 | kyc-service | event-consumed | 2025-09-17 | IDEMP-001 | REQ-001 | CORR-001 | MSG-002
...
2. Read Models (Per Event)
2.1 kyc_read_model
loanAppId | status | score | provider | timestamp
LA1001 | Pass | 98 | Fenergo | 2025-09-17
2.2 credit_read_model
loanAppId | score | status | bureau | timestamp
LA1001 | 810 | Pass | CIBIL | 2025-09-17
2.3 fraud_read_model
loanAppId | riskLevel | status | provider | timestamp
LA1001 | Low | Pass | Experian | 2025-09-17
2.4 aml_read_model
loanAppId | score | status | provider | timestamp
LA1001 | Low | Pass | Actimize | 2025-09-17
2.5 financial_crime_read_model
loanAppId | riskLevel | status | provider | timestamp
LA1001 | None | Pass | Actimize | 2025-09-17
2.6 loan_evaluation_read_model
loanAppId | result | remarks | timestamp
LA1001 | Approved | Good profile| 2025-09-17
2.7 builder_disbursement_read_model
reqId | milestone | status | timestamp
BDR-01 | Plinth | Approved| 2025-09-17
2.8 disbursement_read_model
disbId | amount | toAccount | status | emiScheduleUrl | timestamp
DIS-01 | 25L | PrestigeGrp-ACC | Done | blob://emi.pdf | 2025-09-17
3. Aggregated Read Model (Dashboard)
{
loanAppId: "LA1001",
customerId: "CUST123",
customerName: "Amit R",
builder: "Prestige Group",
loanAmount: 7500000,
term: "15Y",
loanStatus: "Approved",
kyc: {status: "Pass", provider: "Fenergo", score: 98},
credit: {status: "Pass", score: 810, bureau: "CIBIL"},
fraud: {status: "Pass", provider: "Experian", riskLevel: "Low"},
aml: {status: "Pass", provider: "Actimize", score: "Low"},
financialCrime: {status: "Pass", provider: "Actimize", riskLevel: "None"},
loanAccountNo: "123456789",
disbursement: {
milestones: [
{milestone: "Plinth", status: "Approved"},
{milestone: "Roof", status: "Pending"}
],
totalDisbursed: "25L",
emiScheduleUrl: "blob://emi.pdf"
},
compliance: {
kycReport: "Submitted to RBI",
ctrReport: "Submitted to FIU-IND"
},
timestamps: {...},
idempotencyKey: "IDEMP-001",
requestId: "REQ-001",
correlationId: "CORR-001",
msgKey: "MSG-001"
}
🔹 Event JSON (Samples)
loan-initiated
{
"eventId": "evt-1001",
"eventType": "loan-initiated",
"loanId": "LN12345",
"customerId": "CUST001",
"amount": 500000,
"tenure": 60,
"requestId": "REQ-789",
"correlationId": "CORR-123",
"idempotencyKey": "IDEMP-456",
"timestamp": "2025-09-17T10:00:00Z"
}
kyc-requested
{
"eventId": "evt-1002",
"eventType": "kyc-requested",
"loanId": "LN12345",
"customerId": "CUST001",
"correlationId": "CORR-123",
"requestId": "REQ-789",
"idempotencyKey": "IDEMP-456",
"timestamp": "2025-09-17T10:01:00Z"
}
kyc-done
{
"eventId": "evt-1003",
"eventType": "kyc-done",
"loanId": "LN12345",
"customerId": "CUST001",
"kycStatus": "PASSED",
"riskRating": "LOW",
"provider": "Fenergo",
"correlationId": "CORR-123",
"timestamp": "2025-09-17T10:02:00Z"
}
👉 Similar JSON exists for:
creditscore-requested, creditscore-done
fraud-requested, fraud-done
aml-requested, aml-done
crime-requested, crime-done
loan-approved, loan-rejected, manual-review
agreement-created, agreement-signed
loan-account-created
disbursement-requested, disbursement-approved, disbursement-completed
🔹 CosmosDB Read Model (for Dashboard)
Each event stored as document:
{
"eventId": "evt-1003",
"loanId": "LN12345",
"eventType": "kyc-done",
"customerId": "CUST001",
"payload": {
"kycStatus": "PASSED",
"riskRating": "LOW",
"provider": "Fenergo"
},
"correlationId": "CORR-123",
"requestId": "REQ-789",
"idempotencyKey": "IDEMP-456",
"timestamp": "2025-09-17T10:02:00Z"
}
👉 Dashboards query CosmosDB for:
Loan pipeline status (per stage).
SLA compliance (how long each check took).
CTR/STR/NTR counts.
Builder disbursement pipeline.
🔹 Security
All PII (Aadhaar, PAN) → tokenized + AES-256 encrypted in Blob & DB.
mTLS between services.
Kafka topics secured with SASL_SSL + ACLs.
RBAC for Ops dashboards.
Immutable audit logs in ELK.
Idempotency & correlation IDs ensure safe retries.
🔹 Risks & Mitigation
Business: Loan fraud → Mitigated via Experian fraud score + manual review.
Technology: Event duplication → Idempotency key + outbox pattern.
Data: PII leakage → Encryption + masking in dashboards.
Application: Service downtime → AKS auto-restart + retries.
Security: Insider misuse → RBAC + immutable audit.
Governance: RBI non-compliance → Automated FIU-IND reporting + audit trails.
✅ This architecture gives ABC Bank a foolproof, event-driven, compliant, secure lending journey.
✅ This text-based flow covers:
UI → Azure AD → Microservices → Kafka → Adapters → CBS → Redis → CosmosDB → Audit → Compliance
All events with idempotency / correlation / request tracking
All DB write tables with schema & sample data
Per-event read models + aggregated dashboard model
Security & compliance at each hop
Builder milestone workflow & customer approval integrated
.png)

Comments