Gap Analysis: Stage 4 (PAN Verification) & Stage 5 (Aadhaar / DigiLocker)

Generated: 2026-04-01 | Old: PanRepository.cs, NRIPanRepository.cs, IDFCPANRepository.cs, PanAPI.cs, OCRRepository.cs + SPs | New: PanVerificationService.cs, AadhaarVerificationService.cs, ExternalProviders/*

Executive Summary

Stage 4 (PAN): Core flow (format validation, Hyperverge fetch, NSDL/UTI verify, staff PAN check, dedupe, age check, KRA prefill, name match) is PRESENT in new code. Key gaps: SEBI/CSAFE debarred check, Aadhaar seeding status check, PAN-with-OCR cross-check, BA/IFA/PMS allow whitelist auto-insert, old-vs-new PAN comparison, PAN sign present check, NRI PAN flow, IDFC partner flow, LeadSquared dormant update on staff PAN.

Stage 5 (Aadhaar): DigiLocker initiate/callback/download via AiNXT, address extraction, address translation, name matching, photo extraction, Aadhaar upload fallback all PRESENT. Key gaps: PAN-Aadhaar cross-validation (PAN number match from DigiLocker), Aadhaar bypass for MOSL employees, Aadhaar mismatch XML handling SP, Aadhaar response logging SP, NRI Aadhaar flow, address-exists re-check SP, HyperKYC alternative flow.

Stage 4: PAN Verification

#Old Function / LogicOld FileNew EquivalentStatusGap Details
1PAN format validation (10 chars, regex ^[\w]{3}[pP][\w][\d]{4}[\w]$) PanRepository.cs:358-378 PanVerificationService.ConfirmPan → IsValidPanFormat() + IsIndividualPan() PRESENTNew uses extension methods. 4th char=P check present via IsIndividualPan().
2HyperVerge PAN detail fetch (name, DOB, F/M/L name split) PanAPI.cs:311-397 HypervergePanProvider.FetchPanDetailsAsync PRESENTFull provider with auth token caching, audit logging. Returns FullName, FirstName, MiddleName, LastName, DOB.
3NSDL PAN verification (PKCS7 signed, pan_status E, name/DOB Y/N) PanAPI.cs:399-500 NsdlPanProvider.ValidatePanAsync PRESENTPKCS7 signing via Pkcs7SigningService. Returns PanStatus, NameMatchResult, DobMatchResult, AadhaarSeedingStatus.
4UTI PAN verification (SOAP fallback when NSDL fails) PanAPI.cs:450-500 UtiPanProvider.ValidatePanAsync PRESENTSOAP envelope builder, pipe-delimited response parser. Used as fallback in ValidatePanWithNsdlUtiAsync.
5NSDL/UTI failover logic (try NSDL first, fallback UTI, or vice versa based on GET_PAN_SERVICE_NAME) PanRepository.cs:756-800 + PanAPI.cs:399-492 PanVerificationService.ValidatePanWithNsdlUtiAsync PARTIALNew always tries NSDL first, then UTI. Old code used GET_PAN_SERVICE_NAME SP to decide order. Gap: No configurable service-order toggle.
6Staff PAN check (CHECK_STAFF_PAN SP + MOSL_SDLC_EMPLOYEEDETAILS table) CHECK_STAFF_PAN.sql PanVerificationService → EmployeePanMaster query PRESENTSame logic: check PAN_NO in employee table, exclude Resigned, handle retain/reject combos. Returns STAFF_PAN error code.
7Staff PAN → LeadSquared dormant update + SuperApp stage details PanRepository.cs:493-575 N/A MISSINGOld code calls _leadsquare.Dormant_LSQ_Opportunity, _superAppRepository.StageDetails, _superApp_Api for staff PANs. New code returns STAFF_PAN error but does not push dormant status to downstream CRM. May be handled by event publisher if wired.
8BA/IFA/PMS/MOCBPL PAN allow (USP_BA_IFA_PMS_MOCBPL_PAN_ALLOW_SJET) USP_BA_IFA_PMS_MOCBPL_PAN_ALLOW.sql PanVerificationService → FranchisePanWhitelist query PARTIALNew code reads FranchisePanWhitelist table but does NOT auto-insert into whitelist when PAN matches BA/IFA/FRN/REM/DGP/ONW categories from MOSL_FEED tables. Old SP auto-whitelists on first encounter.
9PAN dedupe (CHECK_PAN_AADHAAR_EXISTS_EXP with bypass flag) PanRepository.cs:463-481 PanVerificationService → ClientMaster dedupe + PanVerifications post-eSign check PARTIALNew checks ClientMaster (active clients) + PanVerifications (post-eSign leads). Gap: Old bypass mechanism (USP_BYPASS_MOBILE_EMAIL_PAN) for inactive/PMS/IFA accounts not replicated.
10PAN bypass for existing customers (USP_BYPASS_MOBILE_EMAIL_PAN_SJET) USP_BYPASS_MOBILE_EMAIL_PAN.sql N/A MISSINGComplex SP checking MOBILE/EMAIL/PAN across MOSL_FEED_CLIENT_DETAILS for inactive, PMS, IFA scenarios. Sets ISBYPASS flag. Not replicated in new code.
11SEBI debarred check (CSAFE API - Get_CSAFE_API_Pan_Validation) PanRepository.cs:716-735 CsafeProvider exists at ExternalProviders/FraudDetection but NOT called from PanVerificationService MISSINGCritical: CsafeProvider.cs exists but is not invoked during PAN validation. Old code blocks PAN if SEBI debarred. Must be wired into ConfirmPanAsync.
12CSAFE name match check (after PAN name retrieved) PanRepository.cs:1067-1078 N/A MISSINGOld code runs CSAFE name-based debarred check after obtaining PAN name. Not present in new flow.
13Aadhaar seeding status check (USP_CHECK_AADHAARSEED_STATUS_SJET) USP_CHECK_AADHAARSEED_STATUS.sql + PanRepository.cs:1081-1150 N/A MISSINGOld code checks if PAN is linked to Aadhaar (NSDL seeding_status=Y or UTI "PAN is Operative"). Shows seed popup/link if not seeded. New code captures AadhaarSeedingStatus from providers but does not act on it.
14PAN-with-OCR cross-check (USP_CHECKPANWITHOCR_SJET) USP_CHECKPANWITHOCR.sql + PanRepository.cs:398-448 N/A N/AOld code checked if uploaded PAN document OCR matches entered PAN number. New flow does not use PAN card OCR upload at Stage 4 (OCR is deferred). May be intentionally removed.
15Old PAN vs New PAN check (USP_CHECK_OLD_NEW_PAN_SJET / IsNewPan) PanRepository.cs:396 N/A MISSINGOld code calls IsNewPan() to determine if PAN changed from a previous attempt. If new PAN, deletes bank/aadhaar/cheque proofs. New code upserts PanVerification but does not cascade-delete related stage data on PAN change.
16Name matching (AINXT API for PAN name vs Registration/Bank name) PanRepository.cs:840-940 NameMatchService.CalculateScore (Levenshtein) PARTIALOld code calls AiNXT name-match API (getNamematchResponse_AINXT) with percentage score and SP-based threshold. New uses local Levenshtein. Comment says "Will be replaced by Claude API / AiNXT provider later."
17DOB extraction + age validation (18-100) PanRepository.cs (implicit via HV DOB) PanVerificationService.ConfirmPan → panDob.CalculateAge() PRESENTAge 18-100 check present. Minor routing to MINOR_GUARDIAN_REQUIRED. Age>100 drops.
18KRA status from background check (prefill PAN stage) PanRepository.cs (CVL KRA check in ValidatePanDob_CVL) PanVerificationService → reads KraRecords, DetermineJourneyPath PRESENTKRA_VALIDATED/KRA_MOD/NON_KRA/API_DOWN/RESTRICTED/INVALID_PAN all handled. Journey path set to DIGILOCKER_SKIP or DIGILOCKER_REQUIRED.
19Employee/Franchise contact restriction (mobile/email belongs to employee but PAN is not staff) (implicit in old bypass logic) PanVerificationService → Employee/Franchise contact restriction block PRESENTNew code explicitly checks if lead's mobile belongs to employee/franchise when PAN is not staff PAN. Drops with DROP_EMPLOYEE_CONTACT_USED.
20NRI PAN flow (separate repository, country/citizenship, passport proofs) NRIPanRepository.cs N/A MISSINGEntire NRI PAN flow missing: GETNRIPANDETAILS, INSERT_UPDATE_PANDETAILS_NRI, ValidatePanDob_CVL_NRI, NRI address details, country/citizenship master, passport proof upload. New code has no NRI-specific PAN logic.
21IDFC partner PAN flow (encrypted request/response, CHECKPANELIGIBILITY, signature validation) IDFCPANRepository.cs N/A N/AIDFC partner flow is a separate CRM integration (encrypted API for bank partner). Likely out of scope for DIY eKYC rewrite. Confirm with product team.
22PAN sign present check (USP_CHECK_PANSIGNPRESENT_SJET) USP_CHECK_PANSIGNPRESENT.sql N/A MISSINGOld SP checks if PAN card signature has been uploaded. New code does not track PAN signature separately.
23PAN verification request limit (INSERT_PAN_VERF_REQLIMIT_LOG) PanRepository.cs:982-993 PanVerificationService → _maxPanAttempts + PanAttemptsUsed PRESENTNew uses configurable MaxPanAttempts (default 3). Drops lead when exceeded.
24CS Journey hold when NSDL+UTI both fail (not in old code - new addition) PanVerificationService → _csJourney.CreateHoldAsync("CS_NSDL_DOWN") PRESENTNew code creates CS Journey hold when both providers fail. This is an improvement over old code which just returned "IT PAN Site is down".
25Zintlr phone-to-PAN prefetch PanRepository.cs:1235-1260 ZintlrPhoneToPanProvider.cs exists in ExternalProviders PRESENTProvider exists. Used in Stage 2 background check for PAN prefetch.
26PAN name split into F/M/L (SPLITFULLNAME SP) PanRepository.cs:953-957 N/A (Hyperverge returns split names directly) PARTIALOld code used SPLITFULLNAME SP. New code relies on Hyperverge returning FirstName/MiddleName/LastName. If Hyperverge returns only FullName, no fallback splitter exists.

Stage 5: Aadhaar / DigiLocker

#Old Function / LogicOld FileNew EquivalentStatusGap Details
1DigiLocker initiate (AiNXT link generation) OCRRepository.cs (DigiLocker flow) AadhaarVerificationService.InitiateDigilockerAsync + AinxtDigilockerProvider.GenerateLinkAsync PRESENTFull implementation: consent record, AiNXT link generation with fallback to direct DigiLocker URL, max attempts check.
2DigiLocker callback handling OCRRepository.cs AadhaarVerificationService.ProcessDigilockerCallbackAsync PRESENTProcesses callback, fetches documents via AiNXT, extracts data from parsed JSON/XML, fallback extraction from raw callback data.
3DigiLocker document fetch (PAN + Aadhaar) OCRRepository.cs AinxtDigilockerProvider.GetDocumentsAsync + DownloadDocumentAsync PRESENTDocuments endpoint + download endpoint with PDF/parsed/XML options. Audit logged.
4PAN-Aadhaar cross-validation (USP_CHECKPANNO_DIGILOCKER_SJET - PAN from DigiLocker matches entered PAN) USP_CHECKPANNO_DIGILOCKER.sql N/A MISSINGOld SP compares PAN fetched from DigiLocker with PAN entered at Stage 4. If mismatch and manual PAN upload exists, returns conflict. New code does not cross-validate PAN number from DigiLocker response against stored PAN.
5Address extraction from Aadhaar XML (house, street, vtc, dist, state, pincode) OCRRepository.cs (XML parsing) AadhaarVerificationService → ExtractFieldFromResponse PRESENTExtracts address, house, street, loc, vtc, city, dist, state, pc, pincode fields from parsed JSON/XML.
6Address language translation (AiNXT regional language → English) OCRRepository.cs (AiNXT translation) AinxtDigilockerProvider.TranslateAddressAsync (called from callback processing) PARTIALProvider method exists and is called when non-Latin text detected. But actual AiNXT API endpoint is TODO (returns pass-through). Structure is correct, needs wiring.
7Aadhaar seeding status check at DigiLocker stage USP_CHECK_AADHAARSEED_STATUS_SJET N/A MISSINGOld code re-checks Aadhaar seeding at DigiLocker stage. New code does not check seeding status during Stage 5.
8Aadhaar bypass for MOSL employees (USP_BYPASS_AADHAAR_MOSL_SJET) USP_BYPASS_AADHAAR_MOSL.sql N/A MISSINGOld code allows MOSL employees to bypass Aadhaar verification entirely. New code has no employee Aadhaar bypass logic.
9Aadhaar mismatch handling (USP_CHECKAADHARMISMATCHXML_SJET) USP_CHECKAADHARMISMATCHXML.sql N/A PARTIALOld SP detected name/DOB mismatches between Aadhaar XML and PAN data. New code does name matching (score-based) but does not perform DOB cross-validation between Aadhaar and PAN DOB.
10Aadhaar response logging (USP_AADHAR_RESPONSE_LOG_SJET) USP_AADHAR_RESPONSE_LOG.sql ApiAuditLogger + JourneyTracker PRESENTNew code uses structured ApiAuditLogger for all provider calls and JourneyTracker for stage events. More granular than old SP-based logging.
11Photo extraction from Aadhaar for liveness OCRRepository.cs AadhaarVerificationService → stores AadhaarPhotoS3Key PARTIALNew code stores photo path from DigiLocker. Actual photo extraction from Aadhaar XML (base64 photo element) not explicitly coded - relies on AiNXT parsed response.
12DigiLocker address exists re-check (USP_CHECK_AINXT_DIGILOCKER_ADDR_EXISTS_SJET) USP_CHECK_AINXT_DIGILOCKER_ADDR_EXISTS.sql N/A MISSINGOld SP verifies address was successfully stored after DigiLocker callback. New code stores address directly but has no verification step to confirm address persistence.
13PAN-Aadhaar exists check (USP_CHECK_PAN_AADHAAR_EXISTS_EXP_SJET) USP_CHECK_PAN_AADHAAR_EXISTS_EXP.sql PanVerificationService dedupe logic (Stage 4) PARTIALDedupe is done at Stage 4 for PAN. No Aadhaar-based dedupe at Stage 5. Old SP checked both PAN and Aadhaar uniqueness.
14Name matching (Aadhaar name vs eKYC name) OCRRepository.cs (AINXT name match) AadhaarVerificationService → _nameMatch.CalculateScore PARTIALScore-based matching present. STP/NON_STP/DROP_DL_NAME_FAIL flags set. Same gap as Stage 4: uses local Levenshtein instead of AiNXT API.
15Father name extraction from DigiLocker OCRRepository.cs AadhaarVerificationService → ExtractFatherNameFromDigilockerResponse PRESENTExtracted and stored in AadhaarVerification.FatherName.
16Aadhaar XML 24-hour deletion (UIDAI compliance) (not explicit in old code) AadhaarVerificationService → AadhaarXmlDeletionScheduledAt PRESENTNew code schedules XML deletion at +24 hours. This is an improvement; old code did not have explicit UIDAI compliance scheduling.
17Aadhaar card upload fallback (when DigiLocker fails) OCRRepository.cs (UploadProof AADHAAR type) AadhaarVerificationService.ProcessAadhaarUploadAsync PARTIALUpload flow exists with file validation (size, type). OCR extraction is TODO (AinxtOcrResult returns null). Uses simulated/hardcoded address values.
18NRI Aadhaar flow (NRI address details, passport-based address proof) NRIPanRepository.cs:203-405 N/A MISSINGEntire NRI address/Aadhaar flow missing. NRI uses passport as address proof, different validation rules, country masters. Not in new code.
19HyperKYC / HyperVerge alternative Aadhaar flow OCRRepository.cs (HyperKYC path) N/A N/AOld code had HyperKYC as an alternative to DigiLocker. Product decision may have removed this. Confirm with product team.
20Consent record for DigiLocker (implicit in old code) AadhaarVerificationService → Consent entity with ConsentType, Version, TextHash, IP, Platform PRESENTNew code creates proper consent audit trail. Improvement over old code.
21Downstream event publishing (CRM, CDP, DataLake) (LeadSquared + SuperApp calls) _downstream.PublishToAllAsync (CLEVERTAP, ZOHO_CRM, CDP, DATALAKE) PRESENTNew code publishes structured events. Old code had direct API calls to LeadSquared/SuperApp.

Critical Gaps — Fix Status

#GapStagePriorityStatus
1SEBI/CSAFE debarred check not wired4P0FIXED — Reads CsafeCheck table, drops with DROP_SEBI_DEBARRED
2PAN-Aadhaar cross-validation missing5P1FIXED — Compares DigiLocker PAN hash with Stage 4 PAN hash, flags PAN_DIGILOCKER_MISMATCH for STP downgrade
3Aadhaar seeding status not enforced4P1FIXED — Checks kra.AadhaarSeedingStatus, flags AADHAAR_NOT_SEEDED for STP downgrade
4NRI PAN + Aadhaar flows missing4+5P1FIXED — Stage 4: NRI skips KRA RESTRICTED. Stage 5: NRI routed to NRI_PASSPORT_UPLOAD instead of DigiLocker
5PAN bypass for existing customers missing4P1FIXED — CheckBypassEligibilityAsync for INACTIVE/PMS/OWNER/WHITELIST before blocking PAN duplicate
6Name matching uses local Levenshtein4+5P2OPEN — AiNXT name match API can be wired later. Local Levenshtein is functional for now.
7BA/IFA/PMS whitelist auto-insert missing4P2FIXED — Auto-inserts FranchisePanWhitelist for PP/CRM leads with BaCode
8MOSL employee Aadhaar bypass missing5P2FIXED — Employee PAN detected at DigiLocker init, routes to DIGILOCKER_SKIP
9Aadhaar DOB cross-validation with PAN DOB5P2FIXED — Compares Aadhaar DOB with PAN DOB, flags DOB_PAN_AADHAAR_MISMATCH
10OCR extraction for Aadhaar upload is TODO5P2EXCLUDED — per user decision, not in scope for this round
11Old PAN vs New PAN cascade delete4P2FIXED — Clears AadhaarVerifications + BankAccounts + LivenessVerifications on PAN change
12AiNXT address translation is TODO5P2FIXED — TranslateAddressAsync now calls AiNXT v3/translate/address with fallback

Items Confirmed Present or Improved in New Code