Add all CBS custom modules: KYC, Sanctions, RBI Feed, OpenProject, Mobile Lookup, Charges, Avro schemas

Includes all prior work not yet committed on this branch:
- KYC module (LincPay eKYC: PAN, Aadhaar OTP, GSTIN verification)
- Sanctions screening (UN Security Council consolidated list)
- RBI Feed integration with scheduled jobs
- OpenProject API integration
- Mobile lookup service
- Charge module enhancements (current account support)
- Client family member nominee fields
- Avro schema updates
- Liquibase migrations 0216-0224
- Postman collections for OpenProject, RBI Feeds, Sanctions
- SQL seed scripts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Aditya
2026-03-18 17:54:10 +05:30
co-authored by Claude Opus 4.6
parent 78f37257a7
commit ba5365d4af
102 changed files with 9757 additions and 18 deletions
+139
View File
@@ -0,0 +1,139 @@
-- =============================================================================
-- KYC Module – Table Creation Script (MySQL / MariaDB)
-- =============================================================================
-- DB Connection (from config/docker/env/fineract-common.env & mariadb.env):
-- Host : localhost (or 'db' inside Docker)
-- Port : 3306
-- Database : fineract_default ← tenant database (your actual data lives here)
-- Username : root
-- Password : skdcnwauicn2ucnaecasdsajdnizucawencascdca
--
-- Run command:
-- mysql -h localhost -P 3306 -u root -p'skdcnwauicn2ucnaecasdsajdnizucawencascdca' fineract_default < create_kyc_tables_mysql_mariadb.sql
-- =============================================================================
USE fineract_default;
-- =============================================================================
-- TABLE: m_client_kyc
-- One KYC record per client (enforced by UNIQUE on client_id).
-- Stores PAN, Aadhaar (masked), GSTIN, CKYCRR number, risk category,
-- lifecycle dates and audit fields.
-- =============================================================================
CREATE TABLE IF NOT EXISTS `m_client_kyc` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`client_id` BIGINT NOT NULL,
-- kyc_status : 100=PENDING | 200=IN_PROGRESS | 300=VERIFIED | 400=REJECTED | 500=EXPIRED
`kyc_status` SMALLINT NOT NULL DEFAULT 100,
-- kyc_type : 1=INDIVIDUAL | 2=NON_INDIVIDUAL
`kyc_type` SMALLINT NOT NULL,
-- risk_category : 1=LOW (re-KYC 10yr) | 2=MEDIUM (8yr) | 3=HIGH (2yr)
`risk_category` SMALLINT NOT NULL DEFAULT 1,
-- PAN (Permanent Account Number – Income Tax Dept)
-- Format: 5 uppercase letters + 4 digits + 1 uppercase letter e.g. ABCDE1234F
`pan_number` VARCHAR(10) NULL,
`pan_verified` TINYINT(1) NOT NULL DEFAULT 0,
`pan_verified_on` DATE NULL,
-- Aadhaar – ONLY masked form stored (last 4 digits visible) per UIDAI directive
-- e.g. XXXXXXXX1234
`aadhaar_number_masked` VARCHAR(12) NULL,
`aadhaar_verified` TINYINT(1) NOT NULL DEFAULT 0,
`aadhaar_verified_on` DATE NULL,
-- GSTIN (15-char GST Identification Number – mandatory for NON_INDIVIDUAL)
-- Format: 2-digit state code + 10-char PAN + 1 entity num + Z + check digit
`gstin_number` VARCHAR(15) NULL,
`gstin_verified` TINYINT(1) NOT NULL DEFAULT 0,
`gstin_verified_on` DATE NULL,
-- CKYCRR – Central KYC Records Registry number (issued by CERSAI, 14 digits)
`ckyc_number` VARCHAR(14) NULL,
-- Lifecycle timestamps
`initiated_on` DATE NULL,
`verified_on` DATE NULL,
`rejected_on` DATE NULL,
-- expiry_date computed as: verified_on + risk_category years offset
`expiry_date` DATE NULL,
`remarks` VARCHAR(500) NULL,
-- Audit fields (AbstractAuditableWithUTCDateTimeCustom)
`created_by` BIGINT NOT NULL,
`created_on_utc` DATETIME NOT NULL,
`last_modified_by` BIGINT NOT NULL,
`last_modified_on_utc` DATETIME NOT NULL,
`version` BIGINT NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
UNIQUE KEY `uq_m_client_kyc_client_id` (`client_id`),
CONSTRAINT `FK_m_client_kyc_client_id`
FOREIGN KEY (`client_id`) REFERENCES `m_client` (`id`)
ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- =============================================================================
-- TABLE: m_client_kyc_verification_log
-- Immutable audit trail for every 3rd-party PAN / Aadhaar / GSTIN API call.
-- =============================================================================
CREATE TABLE IF NOT EXISTS `m_client_kyc_verification_log` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`kyc_id` BIGINT NOT NULL,
-- verification_type: PAN | AADHAAR | GSTIN
`verification_type` VARCHAR(20) NOT NULL,
-- verification_status: SUCCESS | FAILURE | PENDING | ERROR
`verification_status` VARCHAR(20) NOT NULL,
-- External reference id returned by the 3rd-party vendor API
`request_reference` VARCHAR(100) NULL,
-- Full raw JSON response from the vendor – stored for compliance audit
`api_response` TEXT NULL,
`remarks` VARCHAR(500) NULL,
-- Audit fields
`created_by` BIGINT NOT NULL,
`created_on_utc` DATETIME NOT NULL,
`last_modified_by` BIGINT NOT NULL,
`last_modified_on_utc` DATETIME NOT NULL,
`version` BIGINT NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
CONSTRAINT `FK_m_kyc_verification_log_kyc_id`
FOREIGN KEY (`kyc_id`) REFERENCES `m_client_kyc` (`id`)
ON DELETE CASCADE ON UPDATE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- =============================================================================
-- PERMISSIONS – Insert into m_permission
-- =============================================================================
INSERT IGNORE INTO `m_permission`
(`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`)
VALUES
('portfolio', 'READ_CLIENTKYC', 'CLIENTKYC', 'READ', 0),
('portfolio', 'CREATE_CLIENTKYC', 'CLIENTKYC', 'CREATE', 1),
('portfolio', 'UPDATE_CLIENTKYC', 'CLIENTKYC', 'UPDATE', 1),
('portfolio', 'VERIFY_CLIENTKYC', 'CLIENTKYC', 'VERIFY', 1),
('portfolio', 'REJECT_CLIENTKYC', 'CLIENTKYC', 'REJECT', 1);
-- =============================================================================
-- VERIFY CREATION
-- =============================================================================
SELECT 'Tables created:' AS info;
SHOW TABLES LIKE 'm_client_kyc%';
SELECT 'Permissions inserted:' AS info;
SELECT code, entity_name, action_name FROM m_permission WHERE entity_name = 'CLIENTKYC';
+155
View File
@@ -0,0 +1,155 @@
-- =============================================================================
-- KYC Module – Table Creation Script (PostgreSQL)
-- =============================================================================
-- DB Connection (from config/docker/env/postgresql.env & application.properties):
-- Host : localhost
-- Port : 5432
-- Database : fineract_default ← tenant database (your actual data lives here)
-- Username : postgres
-- Password : skdcnwauicn2ucnaecasdsajdnizucawencascdca
--
-- Run command:
-- psql -h localhost -p 5432 -U postgres -d fineract_default -f create_kyc_tables_postgresql.sql
--
-- (It will prompt for password: skdcnwauicn2ucnaecasdsajdnizucawencascdca)
-- =============================================================================
\connect fineract_default;
-- =============================================================================
-- TABLE: m_client_kyc
-- One KYC record per client (enforced by UNIQUE on client_id).
-- =============================================================================
CREATE TABLE IF NOT EXISTS m_client_kyc (
id BIGSERIAL NOT NULL,
client_id BIGINT NOT NULL,
-- kyc_status : 100=PENDING | 200=IN_PROGRESS | 300=VERIFIED | 400=REJECTED | 500=EXPIRED
kyc_status SMALLINT NOT NULL DEFAULT 100,
-- kyc_type : 1=INDIVIDUAL | 2=NON_INDIVIDUAL
kyc_type SMALLINT NOT NULL,
-- risk_category : 1=LOW (re-KYC 10yr) | 2=MEDIUM (8yr) | 3=HIGH (2yr)
risk_category SMALLINT NOT NULL DEFAULT 1,
-- PAN (Permanent Account Number – Income Tax Dept)
-- Format: 5 uppercase letters + 4 digits + 1 uppercase letter e.g. ABCDE1234F
pan_number VARCHAR(10),
pan_verified BOOLEAN NOT NULL DEFAULT FALSE,
pan_verified_on DATE,
-- Aadhaar – ONLY masked form stored (last 4 digits visible) per UIDAI directive
aadhaar_number_masked VARCHAR(12),
aadhaar_verified BOOLEAN NOT NULL DEFAULT FALSE,
aadhaar_verified_on DATE,
-- GSTIN (15-char GST Identification Number – mandatory for NON_INDIVIDUAL)
gstin_number VARCHAR(15),
gstin_verified BOOLEAN NOT NULL DEFAULT FALSE,
gstin_verified_on DATE,
-- CKYCRR – Central KYC Records Registry number (issued by CERSAI, 14 digits)
ckyc_number VARCHAR(14),
-- Lifecycle timestamps
initiated_on DATE,
verified_on DATE,
rejected_on DATE,
expiry_date DATE,
remarks VARCHAR(500),
-- Audit fields (AbstractAuditableWithUTCDateTimeCustom)
created_by BIGINT NOT NULL,
created_on_utc TIMESTAMP WITH TIME ZONE NOT NULL,
last_modified_by BIGINT NOT NULL,
last_modified_on_utc TIMESTAMP WITH TIME ZONE NOT NULL,
version BIGINT NOT NULL DEFAULT 0,
CONSTRAINT pk_m_client_kyc PRIMARY KEY (id),
CONSTRAINT uq_m_client_kyc_client_id UNIQUE (client_id),
CONSTRAINT fk_m_client_kyc_client_id
FOREIGN KEY (client_id) REFERENCES m_client(id)
ON DELETE RESTRICT ON UPDATE RESTRICT
);
COMMENT ON TABLE m_client_kyc IS 'RBI-mandated KYC record – one per client';
COMMENT ON COLUMN m_client_kyc.kyc_status IS '100=PENDING,200=IN_PROGRESS,300=VERIFIED,400=REJECTED,500=EXPIRED';
COMMENT ON COLUMN m_client_kyc.kyc_type IS '1=INDIVIDUAL, 2=NON_INDIVIDUAL';
COMMENT ON COLUMN m_client_kyc.risk_category IS '1=LOW(10yr), 2=MEDIUM(8yr), 3=HIGH(2yr) re-KYC period';
COMMENT ON COLUMN m_client_kyc.aadhaar_number_masked IS 'Masked Aadhaar: first 8 digits X, last 4 visible. Full number must NOT be stored per UIDAI directive.';
-- =============================================================================
-- TABLE: m_client_kyc_verification_log
-- Immutable audit trail for every 3rd-party API call.
-- =============================================================================
CREATE TABLE IF NOT EXISTS m_client_kyc_verification_log (
id BIGSERIAL NOT NULL,
kyc_id BIGINT NOT NULL,
-- verification_type: PAN | AADHAAR | GSTIN
verification_type VARCHAR(20) NOT NULL,
-- verification_status: SUCCESS | FAILURE | PENDING | ERROR
verification_status VARCHAR(20) NOT NULL,
request_reference VARCHAR(100),
api_response TEXT,
remarks VARCHAR(500),
-- Audit fields
created_by BIGINT NOT NULL,
created_on_utc TIMESTAMP WITH TIME ZONE NOT NULL,
last_modified_by BIGINT NOT NULL,
last_modified_on_utc TIMESTAMP WITH TIME ZONE NOT NULL,
version BIGINT NOT NULL DEFAULT 0,
CONSTRAINT pk_m_client_kyc_verification_log PRIMARY KEY (id),
CONSTRAINT fk_m_kyc_verification_log_kyc_id
FOREIGN KEY (kyc_id) REFERENCES m_client_kyc(id)
ON DELETE CASCADE ON UPDATE RESTRICT
);
COMMENT ON TABLE m_client_kyc_verification_log IS 'Audit log of all 3rd-party KYC API calls (PAN/Aadhaar/GSTIN)';
-- =============================================================================
-- PERMISSIONS
-- =============================================================================
INSERT INTO m_permission (grouping, code, entity_name, action_name, can_maker_checker)
SELECT 'portfolio', 'READ_CLIENTKYC', 'CLIENTKYC', 'READ', FALSE
WHERE NOT EXISTS (SELECT 1 FROM m_permission WHERE code = 'READ_CLIENTKYC');
INSERT INTO m_permission (grouping, code, entity_name, action_name, can_maker_checker)
SELECT 'portfolio', 'CREATE_CLIENTKYC', 'CLIENTKYC', 'CREATE', TRUE
WHERE NOT EXISTS (SELECT 1 FROM m_permission WHERE code = 'CREATE_CLIENTKYC');
INSERT INTO m_permission (grouping, code, entity_name, action_name, can_maker_checker)
SELECT 'portfolio', 'UPDATE_CLIENTKYC', 'CLIENTKYC', 'UPDATE', TRUE
WHERE NOT EXISTS (SELECT 1 FROM m_permission WHERE code = 'UPDATE_CLIENTKYC');
INSERT INTO m_permission (grouping, code, entity_name, action_name, can_maker_checker)
SELECT 'portfolio', 'VERIFY_CLIENTKYC', 'CLIENTKYC', 'VERIFY', TRUE
WHERE NOT EXISTS (SELECT 1 FROM m_permission WHERE code = 'VERIFY_CLIENTKYC');
INSERT INTO m_permission (grouping, code, entity_name, action_name, can_maker_checker)
SELECT 'portfolio', 'REJECT_CLIENTKYC', 'CLIENTKYC', 'REJECT', TRUE
WHERE NOT EXISTS (SELECT 1 FROM m_permission WHERE code = 'REJECT_CLIENTKYC');
-- =============================================================================
-- VERIFY CREATION
-- =============================================================================
SELECT tablename AS "Tables created"
FROM pg_tables
WHERE schemaname = 'public'
AND tablename LIKE 'm_client_kyc%';
SELECT code, entity_name, action_name
FROM m_permission
WHERE entity_name = 'CLIENTKYC';