feat(cfcfrms): I4C-MHA API integration with holds, intimation, GRM and MRM
Fineract Build & Cucumber tests (without E2E tests) / verify (main, build-core) (push) Waiting to run
Fineract Build & Cucumber tests (without E2E tests) / verify (main, cucumber) (push) Waiting to run
Fineract Build & Cucumber tests (without E2E tests) / verify (progressive-loan, build-progressive-loan) (push) Waiting to run
Fineract Docker Builds / build (false, docker-compose-postgresql.yml, postgresql) (push) Waiting to run
Fineract Docker Builds / build (true, docker-compose.yml, mariadb) (push) Waiting to run
Fineract Documentation build / build (push) Waiting to run
Fineract E2E Tests / E2E Tests (Shard 1 of 10) (push) Waiting to run
Fineract E2E Tests / E2E Tests (Shard 10 of 10) (push) Waiting to run
Fineract E2E Tests / E2E Tests (Shard 2 of 10) (push) Waiting to run
Fineract E2E Tests / E2E Tests (Shard 3 of 10) (push) Waiting to run
Fineract E2E Tests / E2E Tests (Shard 4 of 10) (push) Waiting to run
Fineract E2E Tests / E2E Tests (Shard 5 of 10) (push) Waiting to run
Fineract E2E Tests / E2E Tests (Shard 6 of 10) (push) Waiting to run
Fineract E2E Tests / E2E Tests (Shard 7 of 10) (push) Waiting to run
Fineract E2E Tests / E2E Tests (Shard 8 of 10) (push) Waiting to run
Fineract E2E Tests / E2E Tests (Shard 9 of 10) (push) Waiting to run
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-1) (push) Waiting to run
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-2) (push) Waiting to run
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-3) (push) Waiting to run
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-4) (push) Waiting to run
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-5) (push) Waiting to run
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-2) (push) Waiting to run
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-3) (push) Waiting to run
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-4) (push) Waiting to run
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-5) (push) Waiting to run
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-1) (push) Waiting to run
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-1) (push) Waiting to run
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-2) (push) Waiting to run
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-3) (push) Waiting to run
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-4) (push) Waiting to run
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-5) (push) Waiting to run
Fineract Liquibase Only mode - PostgreSQL / test (push) Waiting to run
Fineract Messaging Smoke Tests / Smoke Test with ActiveMQ (push) Waiting to run
Fineract Messaging Smoke Tests / Smoke Test with Kafka (push) Waiting to run

Real NCRP-CFCFRMS integration to the I4C-MHA API Specification 2.0, alongside
the existing demo module (new paths under /v1/i4c, /v1/i4c/admin, /v1/i4c/cases).

- Inbound token and complaint APIs (Bearer / Basic / body auth, CryptoJS AES,
  IP allowlist), Section 5 / Section 7 acks, idempotent repeat pushes.
- Complaint processing: account and transaction matching, automatic hold of the
  disputed amount with prospective top-up, onward trace, Section 6 response via
  an outbox with retry, optional ack callback, API log for the periodic review.
- Holds register: 90-day review, maker-checker release (full or partial),
  freeze / unfreeze, unfreeze-and-release.
- Automatic customer intimation (email active, SMS / WhatsApp configurable)
  with manual recording and history.
- GRM grievance register (EDD, GR id, nodal, IO / DGRO / SGRO decisions,
  deadlines, escalation) and MRM restoration register (assessment, pro-rata,
  victim request and papers, bank actions, restoration to the victim through a
  restoration pool, victim-bank cases), documents with SHA-256, statements.
- Paged, filterable officer lists with date ranges; local I4C simulator.
- Migrations 0610-0613, jobs I4C Dispatch and I4C Hold Review, runbook.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-23 11:43:22 +05:30
co-authored by Claude Opus 5.5
parent 43c60223af
commit f016bde385
53 changed files with 10773 additions and 0 deletions
@@ -81,6 +81,15 @@ public class TenantAwareBasicAuthenticationFilter extends BasicAuthenticationFil
@Setter
private RequestMatcher requestMatcher = AnyRequestMatcher.INSTANCE;
/**
* Tenant used for the I4C (NCRP-CFCFRMS) server-to-server endpoints when the caller sends no tenant header. I4C
* calls the bank exactly as its API specification describes and has no notion of a Fineract tenant, so a bank
* deploying the integration names its tenant once in configuration ({@code fineract.i4c.tenant-identifier}). Blank
* leaves those endpoints under the ordinary rule: the header is required.
*/
@Setter
private String i4cDefaultTenantIdentifier;
public TenantAwareBasicAuthenticationFilter(final AuthenticationManager authenticationManager,
final AuthenticationEntryPoint authenticationEntryPoint, ToApiJsonSerializer<PlatformRequestLog> toApiJsonSerializer,
ConfigurationDomainService configurationDomainService, CacheWritePlatformService cacheWritePlatformService,
@@ -156,6 +165,11 @@ public class TenantAwareBasicAuthenticationFilter extends BasicAuthenticationFil
tenantIdentifier = request.getParameter("tenantIdentifier");
}
if (org.apache.commons.lang3.StringUtils.isBlank(tenantIdentifier) && isI4cInboundPath(request)
&& org.apache.commons.lang3.StringUtils.isNotBlank(i4cDefaultTenantIdentifier)) {
tenantIdentifier = i4cDefaultTenantIdentifier;
}
if (tenantIdentifier == null && EXCEPTION_IF_HEADER_MISSING) {
throw new InvalidTenantIdentifierException("No tenant identifier found: Add request header of '"
+ TENANT_ID_REQUEST_HEADER + "' or add the parameter 'tenantIdentifier' to query string of request URL.");
@@ -233,6 +247,12 @@ public class TenantAwareBasicAuthenticationFilter extends BasicAuthenticationFil
return exempt;
}
/** The endpoints I4C itself calls (token and complaint push), plus the local I4C simulator. Not the officer screens. */
private static boolean isI4cInboundPath(final HttpServletRequest request) {
final String uri = request.getRequestURI();
return uri != null && (uri.contains("/i4c/auth/") || uri.endsWith("/i4c/complaints") || uri.contains("/i4c-sim/"));
}
@Override
protected void onSuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, Authentication authResult)
throws IOException {