🎯 Learning Path:

  1. Complete REL-ID Complete Activation & Login Flow Codelab
  2. Complete REL-ID IDV Post-Login Flow Codelab
  3. You are here → Additional Document Scan Implementation for Enhanced IDV
  4. Optional: REL-ID Forgot Password Flow Codelab

Welcome to the REL-ID Identity Verification Additional Document Scan Flow codelab! This tutorial teaches you how to implement advanced additional document scanning capabilities for enhanced identity verification, allowing users to provide supplementary identity documents for more comprehensive verification.

What You'll Build

In this codelab, you'll enhance your existing REL-ID IDV application with:

What You'll Learn

By completing this codelab, you'll master:

  1. Additional Document Scan API: Implementing initiateIDVAdditionalDocumentScan SDK method for enhanced document verification and recapture functionality
  2. Advanced Event Handling: Managing onIDVAdditionalDocumentScan events with comprehensive error handling and navigation logic
  3. Document Recapture Flow: Implementing built-in retry mechanisms for improved document quality and enhanced user experience
  4. Enhanced UI Components: Building comprehensive document review interfaces with collapsible sections, detailed analysis display, and modal interactions
  5. Biometric Consent Management: Implementing challenge mode-aware biometric template storage consent with proper UI and error handling
  6. Production Integration Patterns: Seamlessly integrating additional document scanning with existing IDV workflows and dashboard navigation

Prerequisites

Before starting this codelab, ensure you have:

Get the Code from GitHub

The code to get started can be found in a GitHub repository.

You can clone the repository using the following command:

git clone https://github.com/uniken-public/codelab-react-native.git

Navigate to the relid-IDV-AdditionalDocumentScan folder in the repository you cloned earlier

Required IDV Plugins Installation

Mandatory IDV Plugins

The IDV implementation requires these mandatory native plugins:

# Navigate to the codelab folder
cd relid-IDV-AdditionalDocumentScan

# Place the required native plugins at root folder of this project:
# - react-native-rdna-client (base REL-ID SDK)
# - react-native-relid-idv-document-capture (document scanning plugin)
# Note: For this Additional Document Scan implementation, only document capture plugin is required

# Install dependencies
npm install

# iOS additional setup (required for CocoaPods and IDV plugins)
cd ios && pod install && cd ..

# Run the application
npx react-native run-android
# or
npx react-native run-ios

Required IDV Assets:

Plugin Configuration:

The IDV plugins require specific configuration in your React Native project:

Codelab Architecture Overview

This codelab extends your MFA application with three core Additional Document Scan components:

  1. Document Process Start Confirmation Screen: Initiates document scanning with user consent and workflow-specific guidelines
  2. Enhanced Document Details Confirmation Screen: Comprehensive document analysis with collapsible sections, detailed validation results, and built-in recapture functionality
  3. Biometric Opt-in Consent Screen: Challenge mode-aware biometric consent handling with proper UI and error management

The IDV implementation adds the following files to your existing React Native project structure:

Component

Purpose

File Location

IDV Service Methods

Enhanced service with IDV API methods

src/uniken/services/rdnaService.ts

IDV Event Handlers

Event manager with IDV callback handlers

src/uniken/services/rdnaEventManager.ts

IDV Event Provider

Global IDV event handling integration

src/uniken/providers/SDKEventProvider.tsx

Navigation Integration

IDV screen navigation and routing

src/tutorial/navigation/AppNavigator.tsx

Document Start Screen

Document scanning initiation with workflow-specific guidelines

src/tutorial/screens/idv/IDVDocumentProcessStartConfirmationScreen.tsx

Enhanced Document Confirmation Screen

Comprehensive document analysis with collapsible sections and recapture functionality

src/tutorial/screens/idv/IDVConfirmDocumentDetailsScreen.tsx

Biometric Consent Screen

Challenge mode-aware biometric consent handling

src/tutorial/screens/idv/IDVBiometricOptInConsentScreen.tsx

Complete Project Directory Structure

After implementing IDV functionality, your project structure will include:

src/
├── uniken/
│   ├── services/
│   │   ├── rdnaEventManager.ts          # Enhanced with IDV event handlers
│   │   └── rdnaService.ts               # Enhanced with IDV API methods
│   ├── providers/
│   │   └── SDKEventProvider.tsx         # Enhanced with IDV event integration
│   └── types/
│       └── rdnaEvents.ts                # Enhanced with IDV event interfaces
├── tutorial/
│   ├── navigation/
│   │   └── AppNavigator.tsx             # Enhanced with IDV screen registration
│   └── screens/
│       ├── idv/                         # NEW: IDV screen components
│       │   ├── IDVDocumentProcessStartConfirmationScreen.tsx
│       │   ├── IDVConfirmDocumentDetailsScreen.tsx
│       │   └── IDVBiometricOptInConsentScreen.tsx
│       ├── auth/                        # Existing authentication screens
│       └── components/                  # Shared UI components
├── assets/
└── react-native-plugins/               # Required for IDV functionality
    └── react-native-relid-idv-document-capture/

Required IDV Assets Structure

# Android IDV Assets
android/app/src/main/assets/Regula/
├── db.dat                              # Document recognition database (~108MB)
├── certificates/                       # Security certificates bundle
└── regula.license                      # Production license file

# iOS IDV Assets  
ios/
├── db.dat                             # Document recognition database
├── regula.license                     # Production license file
└── certificates/                      # Security certificates bundle

The Enhanced Identity Verification Challenge

While standard IDV processes provide basic identity verification through single document scanning, many organizations require enhanced verification capabilities for high-risk transactions, regulatory compliance, or comprehensive identity verification processes. Organizations face several challenges with basic IDV implementations:

Standard IDV Limitations for Enhanced Compliance

📋 Single Document Verification Constraints

🔍 Limited Document Quality Recovery

📱 Restricted Workflow Flexibility

🛡️ Enhanced Verification Requirements

🌐 User Experience Limitations

🔄 Integration and Extensibility Gaps

How REL-ID IDV Additional Document Scan Addresses These Challenges

The REL-ID Identity Verification (IDV) Additional Document Scan functionality extends the core IDV capabilities to provide enhanced verification workflows that address complex compliance and user experience requirements:

🔄 Enhanced Document Workflow Support

Additional Document Scan API Integration

// Initiate additional document scan for enhanced verification
await RdnaService.initiateIDVAdditionalDocumentScan('Enhanced Verification Required');

// Handle additional document scan response
const handleIDVAdditionalDocumentScan = (data: RDNAIDVAdditionalDocumentScanData) => {
  // Navigate to enhanced document confirmation screen
  NavigationService.navigateOrUpdate('IDVConfirmDocumentDetailsScreen', {
    title: 'Confirm Additional Document Details',
    documentDetails: data,
    isAdditionalDocScan: true
  });
};

🎯 Interactive Document Review & Recapture

Enhanced User Control Over Verification Process

⚡ Extensible Integration Architecture

Seamless Ecosystem Integration

📊 Enterprise-Grade Compliance & Reporting

Regulatory Framework Alignment

🔄 Seamless Integration Architecture

Event-Driven IDV Workflow

// Complete IDV event chain for Additional Document Scan
const idvWorkflow = [
  'getIDVDocumentScanProcessStartConfirmation',  // Document capture initiation
  'onIDVAdditionalDocumentScan',                 // Additional document scan response with comprehensive analysis
  'getIDVBiometricOptInConsent'                  // Basic consent handling (optional)
];

Business Impact & ROI

Operational Efficiency Gains

Security & Compliance Benefits

Enhanced User Experience

Before implementing Additional Document Scan functionality, let's understand the key SDK events and APIs that power the enhanced identity verification workflow.

Additional Document Scan Event Flow Sequence

The additional document scan process follows this enhanced event-driven pattern:

User Flow Trigger → initiateIDVAdditionalDocumentScan API → onIDVAdditionalDocumentScan Event →
Enhanced Document Confirmation Screen with Comprehensive Analysis → Document Recapture (Optional) → Navigation to Dashboard

Core Additional Document Scan Event Types

The REL-ID SDK provides these enhanced events for additional document scanning:

Event Type

Description

User Action Required

initiateIDVAdditionalDocumentScan

API to trigger additional document scan

Application initiates additional verification

onIDVAdditionalDocumentScan

Additional document scan response event with comprehensive analysis

User reviews detailed document analysis with collapsible sections

Enhanced Document Confirmation Screen

Comprehensive document analysis with recapture functionality

User can review all document details, recapture, or confirm

Document Recapture Flow

Built-in retry mechanism for improved document quality

User retakes photos via initiateIDVAdditionalDocumentScan

Additional Document Scan Requirements

Additional document scan functionality requires these enhanced setup conditions:

Requirement

Description

Status Check

Basic IDV Completed

Standard IDV flow must be implemented and working

✅ Required foundation

SDK Version 4.5+

REL-ID SDK with Additional Document Scan support

✅ Must support new APIs

Event Handler Setup

onIDVAdditionalDocumentScan event handler registered

✅ Required for response handling

Enhanced UI Components

Comprehensive document confirmation screen with recapture capability

✅ Enhanced user interface required

API Integration

initiateIDVAdditionalDocumentScan, setIDVDocumentScanProcessStartConfirmation, getIDVConfig, and setIDVBiometricOptInConsent implemented

✅ Core API methods

Additional Document Scan API Integration Pattern

Add these TypeScript definitions to understand the Additional Document Scan API structure:

// src/uniken/services/rdnaService.ts (Additional Document Scan API)

/**
 * Initiates additional document scan for enhanced verification
 * After successful API call, the SDK will trigger onIDVAdditionalDocumentScan event.
 * Uses sync response pattern similar to other API methods.
 * 
 * @param reason The reason for initiating additional document scan
 * @returns Promise<RDNASyncResponse> that resolves with sync response structure
 */
async initiateIDVAdditionalDocumentScan(reason: string): Promise<RDNASyncResponse> {
  return new Promise((resolve, reject) => {
    console.log('RdnaService - Initiating IDV additional document scan with reason:', reason);
    
    RdnaClient.initiateIDVAdditionalDocumentScan(reason, response => {
      console.log('RdnaService - InitiateIDVAdditionalDocumentScan sync callback received');

      const result: RDNASyncResponse = (response as any)[0] || response;
      
      if (result.error.longErrorCode === 0) {
        console.log('RdnaService - InitiateIDVAdditionalDocumentScan sync response success, waiting for onIDVAdditionalDocumentScan event');
        resolve(result);
      } else {
        console.error('RdnaService - InitiateIDVAdditionalDocumentScan sync response error:', result);
        reject(result);
      }
    });
  });
}

Let's implement the Additional Document Scan API methods in your service layer, building on the existing IDV infrastructure.

Enhance rdnaService.ts with Additional Document Scan Methods

Add the Additional Document Scan API methods to your existing service implementation:

// src/uniken/services/rdnaService.ts (IDV methods addition)

/**
 * Confirms document scan process start with IDV workflow parameter
 * @param isConfirm User confirmation decision (true = start document scan, false = cancel)
 * @param idvWorkflow IDV workflow type (0=activation, 2=device activation, 4=recovery, 5=post-login, 6=KYC, 13=agent KYC)
 * @returns Promise<RDNASyncResponse> that resolves with sync response structure
 */
async setIDVDocumentScanProcessStartConfirmation(isConfirm: boolean, idvWorkflow: number): Promise<RDNASyncResponse> {
  return new Promise((resolve, reject) => {
    console.log('RdnaService - Setting IDV document scan process start confirmation:', {
      isConfirm,
      idvWorkflow
    });
    
    RdnaClient.setIDVDocumentScanProcessStartConfirmation(isConfirm, idvWorkflow, response => {
      console.log('RdnaService - setIDVDocumentScanProcessStartConfirmation sync callback received');

      const result: RDNASyncResponse = response;
      
      if (result.error && result.error.longErrorCode === 0) {
        console.log('RdnaService - Document scan confirmation success, waiting for async events');
        resolve(result);
      } else {
        console.error('RdnaService - Document scan confirmation error:', result);
        reject(result);
      }
    });
  });
}

/**
 * Sets IDV biometric opt-in consent for template storage
 * @param isOptIn User consent decision (true = allow biometric storage, false = deny)
 * @param challengeMode Challenge mode from the getIDVBiometricOptInConsent event
 * @returns Promise<RDNASyncResponse>
 */
async setIDVBiometricOptInConsent(isOptIn: boolean, challengeMode: number): Promise<RDNASyncResponse> {
  return new Promise((resolve, reject) => {
    console.log('RdnaService - Setting IDV biometric opt-in consent:', {
      isOptIn,
      challengeMode
    });
    
    RdnaClient.setIDVBiometricOptInConsent(isOptIn, challengeMode, response => {
      console.log('RdnaService - setIDVBiometricOptInConsent sync callback received');

      const result: RDNASyncResponse = response;
      
      if (result.error && result.error.longErrorCode === 0) {
        console.log('RdnaService - Biometric consent success, waiting for async events');
        resolve(result);
      } else {
        console.error('RdnaService - Biometric consent error:', result);
        reject(result);
      }
    });
  });
}

/**
 * Gets IDV configuration from server
 * @returns Promise<RDNASyncResponse> that resolves with config data
 */
async getIDVConfig(): Promise<RDNASyncResponse> {
  return new Promise((resolve, reject) => {
    console.log('RdnaService - Getting IDV configuration');
    
    RdnaClient.getIDVConfig(response => {
      console.log('RdnaService - getIDVConfig sync callback received');
      const result: RDNASyncResponse = response;
      
      if (result.error && result.error.longErrorCode === 0) {
        console.log('RdnaService - IDV config retrieved successfully');
        resolve(result);
      } else {
        console.error('RdnaService - IDV config error:', result);
        reject(result);
      }
    });
  });
}

APIs Actually Used in Additional Document Scan

The project implements these specific APIs:

API Method

Purpose

Usage in Project

initiateIDVAdditionalDocumentScan

Triggers additional document scanning

Main functionality - starts enhanced document verification and recapture

setIDVDocumentScanProcessStartConfirmation

Confirms document scan process start

Used by document scan start confirmation screen

getIDVConfig

Retrieves IDV configuration

Called before document scan to get settings

setIDVBiometricOptInConsent

Handles basic biometric consent

Used by biometric consent screen for template storage

Service Pattern Consistency

These implementations follow the established REL-ID SDK service patterns:

Pattern Element

Implementation Detail

Promise Wrapper

Wraps native sync SDK callback in Promise for async/await usage

Parameter Validation

Validates longErrorCode === 0 for success

Comprehensive Logging

Detailed console logging for debugging Additional Document Scan flows

Error Handling

Proper reject/resolve based on sync response patterns

Configure your event manager to handle the complete IDV event chain with proper navigation coordination.

Update rdnaEventManager.ts with IDV Handlers

Add comprehensive IDV event handlers to your existing event manager:

// src/uniken/services/rdnaEventManager.ts (IDV event handlers)

/**
 * Handle IDV document scan process start confirmation request
 */
onGetIDVDocumentScanProcessStartConfirmation: (data: RDNAGetIDVDocumentScanProcessStartConfirmationData) => {
  console.log('EventManager - onGetIDVDocumentScanProcessStartConfirmation triggered');
  console.log('EventManager - Document scan data:', {
    userID: data.userID,
    documentType: data.documentType,
    instructions: data.instructions
  });
  
  NavigationService.navigate('IDVDocumentProcessStartConfirmationScreen', {
    eventName: 'getIDVDocumentScanProcessStartConfirmation',
    eventData: data,
    title: 'Document Scan Setup',
    subtitle: `Prepare to scan your ${data.documentType || 'identity document'}`,
    responseData: data
  });
},

/**
 * Handle IDV additional document scan response (Main functionality)
 */
onIDVAdditionalDocumentScan: (data: RDNAIDVAdditionalDocumentScanData) => {
  console.log('EventManager - onIDVAdditionalDocumentScan triggered');
  console.log('EventManager - Additional document scan data:', {
    challengeMode: data.challengeMode,
    errorCode: data.error?.longErrorCode,
    statusCode: data.challengeResponse?.status?.statusCode,
    documentVersion: data.idvResponse?.version,
    documentType: data.idvResponse?.document_type
  });
  
  // Navigate to enhanced document confirmation screen with additional scan flag
  NavigationService.navigate('IDVConfirmDocumentDetailsScreen', {
    title: 'Confirm Additional Document Details',
    documentDetails: data,
    isAdditionalDocScan: true
  });
},

/**
 * Handle IDV biometric opt-in consent request
 */
onGetIDVBiometricOptInConsent: (data: RDNAGetIDVBiometricOptInConsentData) => {
  console.log('EventManager - onGetIDVBiometricOptInConsent triggered');
  console.log('EventManager - Biometric consent data:', {
    userID: data.userID,
    biometricTypes: data.availableBiometrics,
    isOptional: data.isOptional
  });
  
  NavigationService.navigate('IDVBiometricOptInConsentScreen', {
    title: 'Biometric Authentication Setup',
    userDetails: data
  });
},

Register IDV Event Handlers

Ensure your event handlers are properly registered in the event manager initialization:

// src/uniken/services/rdnaEventManager.ts (handler registration)

/**
 * Initialize event manager with all callbacks including IDV handlers
 */
const initializeEventManager = () => {
  // ... existing handler registrations ...
  
  // Register IDV Additional Document Scan event handlers
  eventManager.setGetIDVDocumentScanProcessStartConfirmationHandler(
    rdnaEventHandlers.onGetIDVDocumentScanProcessStartConfirmation
  );
  
  eventManager.setGetIDVBiometricOptInConsentHandler(
    rdnaEventHandlers.onGetIDVBiometricOptInConsent
  );
  
  // Register Additional Document Scan handler (main functionality)
  eventManager.setIDVAdditionalDocumentScanHandler(
    rdnaEventHandlers.onIDVAdditionalDocumentScan
  );
  
  console.log('EventManager - All Additional Document Scan handlers registered successfully');
};

Event Chain Flow Validation

Add debugging utilities to validate the complete IDV event chain:

// src/uniken/services/rdnaEventManager.ts (debugging utility)

const debugIDVEventChain = () => {
  console.log('=== IDV Event Chain Debug ===');
  console.log('IDV Handler Registration Status:', {
    documentScanStart: !!eventManager.onGetIDVDocumentScanProcessStartConfirmationCallback,
    additionalDocumentScan: !!eventManager.onIDVAdditionalDocumentScanCallback,
    biometricConsent: !!eventManager.onGetIDVBiometricOptInConsentCallback,
  });
  console.log('Expected IDV Flow:');
  console.log('1. Document Scan Start → 2. Document Confirm → 3. Additional Document Scan → 4. Biometric Consent (optional)');
};

Now let's implement the six core IDV screen components following established patterns and best practices.

Complete IDV Screen Implementation Overview

The IDV Post-Login KYC flow requires these six screens:

  1. IDVConfigSettings - IDV configuration management screen (optional advanced settings)
  2. IDVDocumentProcessStartConfirmationScreen - Document scan process initiation
  3. IDVConfirmDocumentDetailsScreen - Document validation and confirmation

1. IDV Document Process Start Confirmation Screen

Create the initial document scanning confirmation screen with workflow-specific guidelines:

// src/tutorial/screens/idv/IDVDocumentProcessStartConfirmationScreen.tsx

import React, { useState, useEffect } from 'react';
import {
  View,
  Text,
  StyleSheet,
  SafeAreaView,
  Alert, 
  StatusBar, 
  ActivityIndicator, 
  Platform,
  Dimensions,
  TouchableOpacity
} from 'react-native';
import { useRoute } from '@react-navigation/native';
import type { RouteProp } from '@react-navigation/native';
import RdnaService from '../../../uniken/services/rdnaService';
import type { RDNAGetIDVDocumentScanProcessStartConfirmationData } from '../../../uniken/types/rdnaEvents';
import type { RootStackParamList } from '../../navigation/AppNavigator';

const { width: SCREEN_WIDTH, height: SCREEN_HEIGHT } = Dimensions.get('window');

type IDVDocumentProcessStartConfirmationScreenRouteProp = RouteProp<RootStackParamList, 'IDVDocumentProcessStartConfirmationScreen'>;

const IDVDocumentProcessStartConfirmationScreen: React.FC = () => {
  const route = useRoute<IDVDocumentProcessStartConfirmationScreenRouteProp>();
  
  // Extract parameters passed from SDKEventProvider
  const {
    eventName,
    eventData,
    title = 'Document Scan Information',
    subtitle = 'Prepare to scan your identity document',
    responseData,
  } = route.params || {};

  const [isProcessing, setIsProcessing] = useState<boolean>(false);
  const [error, setError] = useState<string>('');
  const [scanData, setScanData] = useState<RDNAGetIDVDocumentScanProcessStartConfirmationData | null>(responseData || null);

  useEffect(() => {
    // If we received event data from navigation, set it immediately
    if (responseData) {
      console.log('IDVDocumentProcessStartConfirmationScreen - Received event data from navigation:', responseData);
      setScanData(responseData);
    }
  }, [responseData]);

  // Get guideline text based on IDV workflow
  const getGuidelineText = (): string => {
    const idvWorkflow = scanData?.idvWorkflow || 0;
    
    switch (idvWorkflow) {
      case 0:
        return 'Ensure you have good lighting and hold your document steady for IDV activation process.';
      case 2:
        return 'Additional device activation requires clear document scan. Position document within frame.';
      case 4:
        return 'Account recovery process - scan your identity document clearly for verification.';
      case 5:
        return 'Post-login document scan - ensure all text is visible and document is flat.';
      case 6:
        return 'KYC process document scan - hold document steady and avoid glare for best results.';
      case 13:
        return 'Agent KYC process - scan customer document clearly with proper lighting.';
      default:
        return 'Ensure you have good lighting and hold your document steady for IDV activation process.';
    }
  };

  // Handle scan button action
  const handleScanButtonAction = async () => {
    try {
      setIsProcessing(true);
      setError('');
      console.log('IDVDocumentProcessStartConfirmationScreen - Starting IDV document scan process...');
      
      // Use the idvWorkflow from the event data
      const idvWorkflow = scanData?.idvWorkflow || 0;
      
      // Call the API to confirm starting the document scan process
      const response = await RdnaService.setIDVDocumentScanProcessStartConfirmation(true, idvWorkflow);
      
      console.log('IDVDocumentProcessStartConfirmationScreen - API response:', response);
      
    } catch (error) {
      console.error('IDVDocumentProcessStartConfirmationScreen - Failed to start document scan:', error);
      setError('Failed to start document scan process');
      Alert.alert('Error', 'Failed to start document scan process');
    } finally {
      setIsProcessing(false);
    }
  };

  // Handle close/cancel action
  const handleClose = async () => {
    try {
      setIsProcessing(true);
      setError('');
      console.log('IDVDocumentProcessStartConfirmationScreen - Cancelling IDV document scan process...');
      
      // Use the idvWorkflow from the event data
      const idvWorkflow = scanData?.idvWorkflow || 0;
      
      // Call the API to cancel the document scan process
      const response = await RdnaService.setIDVDocumentScanProcessStartConfirmation(false, idvWorkflow);
      
      console.log('IDVDocumentProcessStartConfirmationScreen - Cancel response:', response);
      
    } catch (error) {
      console.error('IDVDocumentProcessStartConfirmationScreen - Failed to cancel document scan:', error);
      setError('Failed to cancel document scan process');
      Alert.alert('Error', 'Failed to cancel document scan process');
    } finally {
      setIsProcessing(false);
    }
  };

    return (
      <SafeAreaView style={styles.container}>
      <StatusBar backgroundColor="#2196F3" barStyle="light-content" />
      
      <View style={styles.wrap}>
        <View style={styles.contentContainer}>
          
          {/* Close Button */}
          <View style={styles.titleWrap}>
            <TouchableOpacity style={styles.closeButton} onPress={handleClose}>
              <Text style={styles.closeButtonText}>✕</Text>
          </TouchableOpacity>
        </View>

          {/* Main Content Area */}
          <View style={styles.mainContent}>
            
            {/* Loading Animation and Icon */}
            <View style={styles.iconContainer}>
              <ActivityIndicator 
                color="#2196F3" 
                style={styles.loadingSpinner} 
                size="large" 
              />
              <View style={styles.documentIcon}>
                <Text style={styles.documentIconText}>📋</Text>
                <Text style={styles.scanText}>SCAN</Text>
              </View>
            </View>

            {/* Separator */}
            <View style={styles.separatorView} />

            {/* Error Display */}
            {error && (
              <View style={styles.errorContainer}>
                <Text style={styles.errorText}>{error}</Text>
              </View>
            )}

            {/* Guidelines */}
            {getGuidelineText().length > 0 && (
              <View style={styles.row}>
                <Text style={styles.dot}>•</Text>
                <Text style={styles.textBody}>
                  {getGuidelineText()}
            </Text>
          </View>
            )}

            <View style={styles.row}>
              <Text style={styles.dot}>•</Text>
              <Text style={styles.textBody}>
                Position your document within the frame and ensure all corners are visible.
              </Text>
            </View>

            <View style={styles.row}>
              <Text style={styles.dot}>•</Text>
              <Text style={styles.textBody}>
                Avoid shadows, glare, and blurred images for best scan results.
              </Text>
            </View>

            {/* Scan Button */}
          <TouchableOpacity
              style={[styles.scanButton, isProcessing && styles.buttonDisabled]}
              onPress={handleScanButtonAction}
              disabled={isProcessing}
          >
              <Text style={styles.scanButtonText}>
                {'Scan Document'}
              </Text>
          </TouchableOpacity>

          </View>
        </View>
        </View>
      </SafeAreaView>
    );
};

export default IDVDocumentProcessStartConfirmationScreen;

2. IDV Confirm Document Details Screen

Create the enhanced document details confirmation screen with comprehensive analysis and recapture functionality:

// src/tutorial/screens/idv/IDVConfirmDocumentDetailsScreen.tsx

import React, { useState, useEffect } from 'react';
import {
  View,
  Text,
  ScrollView,
  TouchableOpacity,
  Image,
  StyleSheet,
  Alert,
  SafeAreaView,
  StatusBar,
  Dimensions,
  Modal,
  Platform,
} from 'react-native';
import RdnaService from '../../../uniken/services/rdnaService';
import type { RDNAIDVAdditionalDocumentScanData } from '../../../uniken/types/rdnaEvents';

interface Props {
  route: {
    params: {
      title: string;
      documentDetails: RDNAIDVAdditionalDocumentScanData;
      isAdditionalDocScan?: boolean;
    };
  };
  navigation: any;
}

const { width: SCREEN_WIDTH, height: SCREEN_HEIGHT } = Dimensions.get('window');

const IDVConfirmDocumentDetailsScreen: React.FC<Props> = ({ route, navigation }) => {
  const { title, documentDetails, isAdditionalDocScan } = route.params;
  const [isLoading, setIsLoading] = useState(false);
  
  // Collapsible states for comprehensive document analysis
  const [isDocumentImagesCollapsed, setIsDocumentImagesCollapsed] = useState(false);
  const [isIdentityDataCollapsed, setIsIdentityDataCollapsed] = useState(false);
  const [isChecksPerformedCollapsed, setIsChecksPerformedCollapsed] = useState(false);
  const [isErrorListCollapsed, setIsErrorListCollapsed] = useState(false);
  const [isWarningListCollapsed, setIsWarningListCollapsed] = useState(false);
  const [isNFCStatusCollapsed, setIsNFCStatusCollapsed] = useState(false);
  const [isOverallStatusCollapsed, setIsOverallStatusCollapsed] = useState(false);
  
  // Modal states for detailed check information
  const [selectedCheckDetail, setSelectedCheckDetail] = useState<any>(null);
  const [modalVisible, setModalVisible] = useState(false);

  const responseJson = isAdditionalDocScan ? 
    (documentDetails as any).idvResponse : 
    (documentDetails as any).response_data;

  /**
   * Handle document confirmation - navigates to Dashboard
   */
  const handleConfirm = async (isConfirm: boolean) => {
    try {
    setIsLoading(true);
      console.log('IDVConfirmDocumentDetailsScreen - Confirming document details:', isConfirm);
      
      // Navigate to Dashboard screen after successful confirmation
      console.log('IDVConfirmDocumentDetailsScreen - Document confirmed, navigating to Dashboard');
      navigation.navigate('DrawerNavigator', {
        screen: 'Dashboard'
      });
      
    } catch (error) {
      console.error('IDVConfirmDocumentDetailsScreen - Failed to confirm document details:', error);
      Alert.alert('Error', 'Failed to confirm document details. Please try again.');
    } finally {
      setIsLoading(false);
    }
  };

  /**
   * Handle document recapture - initiates new document scan
   */
  const handleRecapture = async () => {
    try {
      setIsLoading(true);
      console.log('IDVConfirmDocumentDetailsScreen - Initiating recapture for additional document scan');
      
      // Call the initiateIDVAdditionalDocumentScan API to restart the document scan process
      await RdnaService.initiateIDVAdditionalDocumentScan('Document Recapture');
      
      console.log('IDVConfirmDocumentDetailsScreen - Recapture initiated successfully');
      
    } catch (error) {
      console.error('IDVConfirmDocumentDetailsScreen - Failed to initiate recapture:', error);
      Alert.alert('Error', 'Failed to initiate document recapture. Please try again.');
    } finally {
      setIsLoading(false);
    }
  };

  const renderCollapsibleSection = (
    title: string,
    isCollapsed: boolean,
    setCollapsed: (collapsed: boolean) => void,
    children: React.ReactNode
  ) => (
    <View style={styles.sectionContainer}>
      <TouchableOpacity
        style={styles.sectionHeader}
        onPress={() => setCollapsed(!isCollapsed)}
      >
        <Text style={styles.sectionTitle}>{title}</Text>
        <Text style={styles.expandIcon}>{isCollapsed ? '▼' : '▲'}</Text>
      </TouchableOpacity>
      {!isCollapsed && (
        <View style={styles.sectionContent}>
          {children}
        </View>
      )}
    </View>
  );

  return (
    <SafeAreaView style={styles.safeArea}>
      <StatusBar barStyle="dark-content" backgroundColor="#f8f9fa" />
      <ScrollView style={styles.container}>
        <CloseButton 
          onPress={async () => {
            await handleConfirmDocumentDetails(false);
          }}
          disabled={isLoading}
        />
        
        <View style={styles.content}>
          <Text style={styles.title}>{title}</Text>
          <Text style={styles.subtitle}>
            Please review the extracted information from your document
          </Text>

          {/* Identity Data Section */}
          {renderCollapsibleSection(
            'Identity Information',
            isIdentityDataCollapsed,
            setIsIdentityDataCollapsed,
            <View style={styles.identityData}>
              <View style={styles.dataRow}>
                <Text style={styles.dataLabel}>Full Name:</Text>
                <Text style={styles.dataValue}>
                  {documentDetails.extractedData?.fullName || 'Not Available'}
                </Text>
              </View>
              <View style={styles.dataRow}>
                <Text style={styles.dataLabel}>Date of Birth:</Text>
                <Text style={styles.dataValue}>
                  {documentDetails.extractedData?.dateOfBirth || 'Not Available'}
                </Text>
              </View>
              <View style={styles.dataRow}>
                <Text style={styles.dataLabel}>Document Number:</Text>
                <Text style={styles.dataValue}>
                  {documentDetails.documentNumber || 'Not Available'}
                </Text>
              </View>
              <View style={styles.dataRow}>
                <Text style={styles.dataLabel}>Document Type:</Text>
                <Text style={styles.dataValue}>
                  {documentDetails.documentType || 'Not Available'}
                </Text>
              </View>
              <View style={styles.dataRow}>
                <Text style={styles.dataLabel}>Expiry Date:</Text>
                <Text style={styles.dataValue}>
                  {documentDetails.extractedData?.expiryDate || 'Not Available'}
                </Text>
              </View>
            </View>
          )}

          {/* Validation Results Section */}
          {renderCollapsibleSection(
            'Validation Results',
            isValidationResultsCollapsed,
            setIsValidationResultsCollapsed,
            <View style={styles.validationResults}>
              <View style={styles.validationRow}>
                <Text style={styles.validationLabel}>Overall Status:</Text>
                <Text style={[
                  styles.validationValue, 
                  documentDetails.validationStatus === 'PASSED' ? styles.passedText : styles.failedText
                ]}>
                  {documentDetails.validationStatus || 'Processing'}
                </Text>
              </View>
              <View style={styles.validationRow}>
                <Text style={styles.validationLabel}>Document Authenticity:</Text>
                <Text style={styles.validationValue}>
                  {documentDetails.authenticityScore ? `${documentDetails.authenticityScore}%` : 'N/A'}
                </Text>
              </View>
              <View style={styles.validationRow}>
                <Text style={styles.validationLabel}>Text Recognition:</Text>
                <Text style={styles.validationValue}>
                  {documentDetails.ocrConfidence ? `${documentDetails.ocrConfidence}%` : 'N/A'}
                </Text>
              </View>
            </View>
          )}

          <View style={styles.buttonContainer}>
            <Button
              title="Confirm Details"
              onPress={() => handleConfirmDocumentDetails(true)}
              loading={isLoading}
              disabled={isLoading}
              style={styles.confirmButton}
            />
            
            <Button
              title="Cancel Verification"
              onPress={() => handleConfirmDocumentDetails(false)}
              disabled={isLoading}
              variant="secondary"
              style={styles.cancelButton}
            />
          </View>
        </View>
      </ScrollView>
    </SafeAreaView>
  );
};

// Styles implementation continues...
const styles = StyleSheet.create({
  safeArea: {
    flex: 1,
    backgroundColor: '#f8f9fa',
  },
  container: {
    flex: 1,
  },
  content: {
    flex: 1,
    padding: 20,
    paddingTop: 80,
  },
  title: {
    fontSize: 28,
    fontWeight: 'bold',
    color: '#2c3e50',
    textAlign: 'center',
    marginBottom: 8,
  },
  subtitle: {
    fontSize: 16,
    color: '#7f8c8d',
    textAlign: 'center',
    marginBottom: 30,
  },
  sectionContainer: {
    backgroundColor: '#fff',
    borderRadius: 12,
    marginBottom: 16,
    elevation: 2,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.1,
    shadowRadius: 4,
  },
  sectionHeader: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    padding: 16,
    borderBottomWidth: 1,
    borderBottomColor: '#ecf0f1',
  },
  sectionTitle: {
    fontSize: 18,
    fontWeight: '600',
    color: '#2c3e50',
  },
  expandIcon: {
    fontSize: 16,
    color: '#3498db',
  },
  sectionContent: {
    padding: 16,
  },
  identityData: {
    gap: 12,
  },
  dataRow: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    paddingVertical: 8,
    borderBottomWidth: 1,
    borderBottomColor: '#ecf0f1',
  },
  dataLabel: {
    fontSize: 14,
    color: '#7f8c8d',
    flex: 1,
  },
  dataValue: {
    fontSize: 14,
    fontWeight: '500',
    color: '#2c3e50',
    flex: 2,
    textAlign: 'right',
  },
  validationResults: {
    gap: 12,
  },
  validationRow: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    paddingVertical: 8,
  },
  validationLabel: {
    fontSize: 14,
    color: '#7f8c8d',
    flex: 1,
  },
  validationValue: {
    fontSize: 14,
    fontWeight: '600',
    flex: 1,
    textAlign: 'right',
  },
  passedText: {
    color: '#27ae60',
  },
  failedText: {
    color: '#e74c3c',
  },
  buttonContainer: {
    gap: 12,
    marginTop: 30,
  },
  confirmButton: {
    backgroundColor: '#27ae60',
  },
  rescanButton: {
    backgroundColor: '#f39c12',
  },
  cancelButton: {
    backgroundColor: '#95a5a6',
  },
});

export default IDVConfirmDocumentDetailsScreen;

3. IDV Biometric Opt-in Consent Screen(Optional)

Create a comprehensive biometric consent screen with proper UI and challenge mode handling:

// src/tutorial/screens/idv/IDVBiometricOptInConsentScreen.tsx

import React, { useState, useEffect } from 'react';
import { 
  View, 
  Text, 
  StyleSheet, 
  SafeAreaView, 
  Alert, 
  StatusBar, 
  Platform,
  Dimensions,
  TouchableOpacity
} from 'react-native';
import { useRoute } from '@react-navigation/native';
import type { RouteProp } from '@react-navigation/native';
import RdnaService from '../../../uniken/services/rdnaService';
import type { RDNAGetIDVBiometricOptInConsentData } from '../../../uniken/types/rdnaEvents';
import type { RootStackParamList } from '../../navigation/AppNavigator';

const { width: SCREEN_WIDTH, height: SCREEN_HEIGHT } = Dimensions.get('window');

type IDVBiometricOptInConsentScreenRouteProp = RouteProp<RootStackParamList, 'IDVBiometricOptInConsentScreen'>;

const IDVBiometricOptInConsentScreen: React.FC = () => {
  const route = useRoute<IDVBiometricOptInConsentScreenRouteProp>();
  
  // Extract parameters passed from SDKEventProvider
  const {
    title = 'Save Template',
    userDetails,
  } = route.params || {};

  const [isProcessing, setIsProcessing] = useState<boolean>(false);
  const [error, setError] = useState<string>('');
  const [biometricOptInData, setBiometricOptInData] = useState<RDNAGetIDVBiometricOptInConsentData | null>(userDetails || null);

  useEffect(() => {
    if (userDetails) {
      console.log('IDVBiometricOptInConsentScreen - Received biometric opt-in data:', userDetails);
      setBiometricOptInData(userDetails);
    }
  }, [userDetails]);

  const handleConsentAction = async (isOptIn: boolean) => {
    try {
      setIsProcessing(true);
      setError('');
      console.log('IDVBiometricOptInConsentScreen - Processing biometric opt-in consent:', isOptIn);
      
      const challengeMode = biometricOptInData?.challengeMode || 0;
      
      // Call the setIDVBiometricOptInConsent API
      const response = await RdnaService.setIDVBiometricOptInConsent(isOptIn, challengeMode);
      
      console.log('IDVBiometricOptInConsentScreen - API response:', response);
      
      // Show success message based on action
      const message = isOptIn 
        ? 'Biometric template storage approved!' 
        : 'Biometric template storage denied.';
      console.log('IDVBiometricOptInConsentScreen - ' + message);
      
    } catch (error) {
      console.error('IDVBiometricOptInConsentScreen - Failed to process biometric opt-in consent:', error);
      setError('Failed to process biometric consent');
      Alert.alert('Error', 'Failed to process biometric consent. Please try again.');
    } finally {
      setIsProcessing(false);
    }
  };

  const getGuidelineTexts = () => {
    const challengeMode = biometricOptInData?.challengeMode || 0;
    
    switch (challengeMode) {
      case 10:
        return {
          text1: 'Your biometric template will be used for enhanced security verification.',
          text2: 'This allows for faster and more secure authentication in future sessions.',
          actionText: 'Approve'
        };
      case 13:
        return {
          text1: 'Agent KYC biometric template will be stored securely for verification purposes.',
          text2: 'This enables enhanced security for agent-assisted transactions.',
          actionText: 'Approve'
        };
      default:
        return {
          text1: 'Your biometric template will be securely stored for identity verification.',
          text2: 'This enables faster authentication and enhanced security for your account.',
          actionText: 'Approve'
        };
    }
  };

  const guidelines = getGuidelineTexts();
  const challengeMode = biometricOptInData?.challengeMode || 0;

  return (
    <SafeAreaView style={styles.container}>
      <StatusBar backgroundColor="#2196F3" barStyle="light-content" />
      
      <View style={styles.wrap}>
        <View style={styles.contentContainer}>
          
          {/* Close Button */}
          <View style={styles.titleWrap}>
            <TouchableOpacity style={styles.closeButton} onPress={() => {}}>
              <Text style={styles.closeButtonText}>✕</Text>
            </TouchableOpacity>
          </View>

          {/* Main Content Area */}
          <View style={styles.mainContent}>
            
            {/* App Logo placeholder */}
            <View style={styles.logoContainer}>
              <View style={styles.logoPlaceholder}>
                <Text style={styles.logoText}>🔐</Text>
              </View>
            </View>

            {/* Title */}
            <View style={styles.titleContainer}>
              <Text style={styles.modalTitle}>
                {challengeMode === 13 ? 'Set up Photo ID' : 'Set up Biometric ID'}
              </Text>
            </View>
            
            {/* Divider */}
            <View style={styles.border} />

            {/* Guidelines Text */}
            <Text style={styles.guidelineText}>
              {guidelines.text1} REL-ID {guidelines.text2}
            </Text>

            {/* Divider */}
            <View style={styles.border} />

            {/* Error Display */}
            {error && (
              <View style={styles.errorContainer}>
                <Text style={styles.errorText}>{error}</Text>
              </View>
            )}

            {/* Action Buttons */}
            <View style={styles.bottomButtons}>
              {/* Reject Button */}
              <TouchableOpacity
                style={[styles.actionButton, styles.rejectButton]}
                onPress={() => handleConsentAction(false)}
                disabled={isProcessing}
              >
                <Text style={styles.actionButtonText}>
                  {isProcessing ? 'Processing...' : 'Reject'}
                </Text>
              </TouchableOpacity>
              
              {/* Approve Button */}
              <TouchableOpacity
                style={[styles.actionButton, styles.approveButton]}
                onPress={() => handleConsentAction(true)}
                disabled={isProcessing}
              >
                <Text style={styles.actionButtonText}>
                  {isProcessing ? 'Processing...' : 'Approve'}
                </Text>
              </TouchableOpacity>
            </View>

          </View>
        </View>
      </View>
    </SafeAreaView>
  );
};

export default IDVBiometricOptInConsentScreen;

Now let's integrate all IDV screens into your existing navigation structure following the established patterns.

Update AppNavigator with IDV Screens

Enhance your AppNavigator with proper IDV screen registration:

// src/tutorial/navigation/AppNavigator.tsx (IDV additions)

// Import IDV screens for Additional Document Scan functionality
import IDVConfirmDocumentDetailsScreen from '../screens/idv/IDVConfirmDocumentDetailsScreen';
import IDVDocumentProcessStartConfirmationScreen from '../screens/idv/IDVDocumentProcessStartConfirmationScreen';
import IDVBiometricOptInConsentScreen from '../screens/idv/IDVBiometricOptInConsentScreen';

// Import RDNA types for IDV
import type { 
  RDNAIDVAdditionalDocumentScanData, 
  RDNAGetIDVDocumentScanProcessStartConfirmationData, 
  RDNAGetIDVBiometricOptInConsentData 
} from '../../uniken/types/rdnaEvents';

// IDV Screen Parameter Interfaces
interface IDVConfirmDocumentDetailsScreenParams {
  title: string;
  documentDetails: RDNAIDVAdditionalDocumentScanData;
  isAdditionalDocScan?: boolean;
}

interface IDVDocumentProcessStartConfirmationScreenParams {
  eventName: string;
  eventData: RDNAGetIDVDocumentScanProcessStartConfirmationData;
  title: string;
  subtitle: string;
  responseData?: RDNAGetIDVDocumentScanProcessStartConfirmationData;
}

interface IDVBiometricOptInConsentScreenParams {
  title: string;
  userDetails: RDNAGetIDVBiometricOptInConsentData;
}

// Enhanced RootStackParamList for Additional Document Scan
export type RootStackParamList = {
  // ... existing screens ...
  
  // IDV Additional Document Scan Screens
  IDVConfirmDocumentDetailsScreen: IDVConfirmDocumentDetailsScreenParams;
  IDVDocumentProcessStartConfirmationScreen: IDVDocumentProcessStartConfirmationScreenParams;
  IDVBiometricOptInConsentScreen: IDVBiometricOptInConsentScreenParams;
};

// Stack Screen Registration in AppNavigator component
const AppNavigator = () => {
  return (
    <NavigationContainer ref={navigationRef}>
      <Stack.Navigator screenOptions={{headerShown: false}} initialRouteName="TutorialHome">
        {/* ... existing screens ... */}
        
        {/* IDV Additional Document Scan Screens */}
        <Stack.Screen 
          name="IDVConfirmDocumentDetailsScreen" 
          component={IDVConfirmDocumentDetailsScreen}
          options={{
            title: 'Confirm Document Details',
            headerShown: false,
          }}
        />
        
        <Stack.Screen 
          name="IDVDocumentProcessStartConfirmationScreen" 
          component={IDVDocumentProcessStartConfirmationScreen}
          options={{
            title: 'IDV Document Process Start Confirmation',
            headerShown: false,
          }}
        />
        
        <Stack.Screen 
          name="IDVBiometricOptInConsentScreen" 
          component={IDVBiometricOptInConsentScreen}
          options={{
            title: 'IDV Biometric Opt-In Consent',
            headerShown: false,
          }}
        />
      </Stack.Navigator>
    </NavigationContainer>
  );
};

Update SDKEventProvider Integration

Ensure your event provider properly handles IDV navigation:

// src/uniken/providers/SDKEventProvider.tsx (IDV handler registration)

useEffect(() => {
  // ... existing event handler registrations ...
  
  // Register IDV event handlers following VerifyAuthScreen pattern
  const handleGetIDVDocumentScanProcessStartConfirmation = useCallback(async (data: RDNAGetIDVDocumentScanProcessStartConfirmationData) => {
    console.log('SDKEventProvider - Get IDV document scan process start confirmation event received');
    console.log('SDKEventProvider - UserID:', data.userID);
    console.log('SDKEventProvider - IDV Workflow:', data.idvWorkflow);
    
    try {
      // Call getIDVConfig API before navigation (following actual implementation)
      console.log('SDKEventProvider - Calling getIDVConfig API before navigation');
      const configResponse = await rdnaService.getIDVConfig();
      console.log('SDKEventProvider - getIDVConfig response:', configResponse);
      
      // Navigate to the IDV document process start confirmation screen
      NavigationService.navigateOrUpdate('IDVDocumentProcessStartConfirmationScreen', {
        eventName: 'getIDVDocumentScanProcessStartConfirmation',
        eventData: data,
        title: 'Document Scan Information',
        subtitle: `Prepare to scan your identity document for user: ${data.userID}`,
        responseData: data,
      });
    } catch (error) {
      console.error('SDKEventProvider - Failed to get IDV config:', error);
      
      // Still navigate to screen even if getIDVConfig fails
      NavigationService.navigateOrUpdate('IDVDocumentProcessStartConfirmationScreen', {
        eventName: 'getIDVDocumentScanProcessStartConfirmation',
        eventData: data,
        title: 'Document Scan Information',
        subtitle: `Prepare to scan your identity document for user: ${data.userID}`,
        responseData: data,
      });
    }
  }, []);


  /**
   * Event handler for IDV additional document scan response
   */
  const handleIDVAdditionalDocumentScan = useCallback((data: RDNAIDVAdditionalDocumentScanData) => {
    console.log('🚀 SDKEventProvider - IDV additional document scan response event received');
    console.log('🚀 SDKEventProvider - Full data received:', JSON.stringify(data, null, 2));
    console.log('🚀 SDKEventProvider - Challenge mode:', data?.challengeMode);
    console.log('🚀 SDKEventProvider - Error code:', data?.error?.longErrorCode);
    console.log('🚀 SDKEventProvider - Status code:', data?.challengeResponse?.status?.statusCode);
    console.log('🚀 SDKEventProvider - Document version:', data?.idvResponse?.version);
    console.log('🚀 SDKEventProvider - Document type:', data?.idvResponse?.document_type);
    
    // Check if navigation is ready
    if (!NavigationService.isReady()) {
      console.error('🚀 SDKEventProvider - Navigation not ready for IDV additional document scan');
      return;
    }
    
    try {
      console.log('🚀 SDKEventProvider - Attempting to navigate to IDVConfirmDocumentDetailsScreen');
      if (data?.error?.longErrorCode === 0){
      // Navigate to the IDV document confirmation screen with additional document scan flag
      NavigationService.navigateOrUpdate('IDVConfirmDocumentDetailsScreen', {
        title: 'Confirm Additional Document Details',
        documentDetails: data,
        isAdditionalDocScan: true
      });
      } else{
        // Navigate to Dashboard for failed scans
        NavigationService.navigate('DrawerNavigator', {
          screen: 'Dashboard',
          params: ''
        });
      }
      
      console.log('🚀 SDKEventProvider - Successfully initiated navigation to IDVConfirmDocumentDetailsScreen');
      
    } catch (error) {
      console.error('🚀 SDKEventProvider - Failed to navigate to IDVConfirmDocumentDetailsScreen:', error);
    }
  }, []);

  const handleGetIDVBiometricOptInConsent = useCallback((data: RDNAGetIDVBiometricOptInConsentData) => {
    console.log('SDKEventProvider - Get IDV biometric opt-in consent event received');
    console.log('SDKEventProvider - UserID:', data?.userID);
    console.log('SDKEventProvider - Challenge mode:', data?.challengeMode);
    
    // Navigate to the IDV biometric opt-in consent screen
    NavigationService.navigateOrUpdate('IDVBiometricOptInConsentScreen', {
      title: 'Save Template',
      userDetails: data,
    });
  }, []);


  // Set IDV event handlers  
  eventManager.setGetIDVBiometricOptInConsentHandler(handleGetIDVBiometricOptInConsent);
  
  // Set Additional Document Scan handler (main functionality)
  console.log('🔧 SDKEventProvider - Setting IDV additional document scan handler');
  eventManager.setIDVAdditionalDocumentScanHandler(handleIDVAdditionalDocumentScan);
  console.log('🔧 SDKEventProvider - IDV additional document scan handler set successfully');

  console.log('SDKEventProvider - All IDV event handlers registered');
  
}, []);

Type Safety and Navigation Service

Ensure proper type safety across the IDV navigation flow:

// src/tutorial/navigation/NavigationService.ts (IDV navigation support)

export const NavigationService = {
  navigationRef,
  
  navigate: (name: keyof RootStackParamList, params?: any) => {
    if (navigationRef.isReady()) {
      navigationRef.navigate(name as never, params as never);
    }
  },
  
  navigateOrUpdate: (name: keyof RootStackParamList, params?: any) => {
    if (navigationRef.isReady()) {
      // Check if already on the target screen to prevent duplicate navigation
      const currentRoute = navigationRef.getCurrentRoute();
      if (currentRoute?.name === name) {
        console.log(`NavigationService - Already on ${name}, updating params`);
        navigationRef.setParams(params);
      } else {
        console.log(`NavigationService - Navigating to ${name}`);
        navigationRef.navigate(name as never, params as never);
      }
    }
  }
};

Let's test your IDV implementation with comprehensive scenarios to ensure proper functionality across the entire identity verification flow.

Test Scenario 1: Complete IDV Flow

Setup Requirements:

Test Steps:

  1. Additional Document Scan Trigger
    • Ensure user is logged in
    • From dashboard or any screen, call rdnaService.initiateIDVAdditionalDocumentScan('Testing Additional Document')
    • Wait for onIDVAdditionalDocumentScan event
  2. Enhanced Document Confirmation Screen
    • Verify IDVConfirmDocumentDetailsScreen appears with comprehensive interface
    • Review detailed document analysis with collapsible sections:
      • Document Details (front/back page images and metadata)
      • Identity Data (extracted information table with all fields)
      • Checks Performed (validation results with expandable details)
      • Error List (if any validation errors)
      • Warning List (if any validation warnings)
      • Overall NFC Status (NFC document status and scan results)
      • Overall Status (final document verification result)
  3. Document Recapture Testing
    • Test "Recapture" button functionality
    • Verify it calls initiateIDVAdditionalDocumentScan('Document Recapture')
    • Confirm new document scan process initiates
    • Verify enhanced analysis screen appears again with new data
  4. Final Confirmation
    • Tap "OK" button to confirm document details
    • Verify direct navigation to Dashboard screen
    • Test error handling for failed scans (navigation to Dashboard)
  5. Biometric Consent (Optional - if triggered by workflow)
    • Verify IDVBiometricOptInConsentScreen appears if triggered
    • Review basic biometric consent options
    • Choose consent option (Enable/Skip)

Expected Results:

Test Scenario 2: IDV Flow with Document Rescan

Test Steps:

  1. Follow steps 1-3 from Complete IDV Flow
  2. In Document Details Confirmation screen:
    • Review extracted data
    • Tap "Scan Different Document"
    • Verify additional scan workflow
  3. Complete remaining flow with new document
  4. Verify final authentication success

Expected Results:

Test Scenario 3: IDV Flow Cancellation Points

Test Steps:

  1. Cancel at Document Start
    • Navigate to IDVDocumentProcessStartConfirmationScreen
    • Tap "Cancel" button
    • Verify appropriate error handling
  2. Cancel at Document Confirmation
    • Complete document scan
    • In IDVConfirmDocumentDetailsScreen
    • Tap "Cancel Verification"
    • Verify flow termination
  3. Cancel at Document Review
    • Complete document capture flow
    • In IDVConfirmDocumentDetailsScreen
    • Tap "Close" or back button
    • Verify appropriate handling

Expected Results:

Test Scenario 4: Error Handling and Edge Cases

Test Steps:

  1. Poor Document Quality
    • Attempt scan with blurry/poor quality document
    • Verify error handling and user guidance
  2. Unsupported Document Type
    • Attempt scan with unsupported document
    • Verify appropriate error messages
  3. Network Connectivity Issues
    • Disable network during IDV flow
    • Verify graceful error handling
  4. Camera Permission Denied
    • Revoke camera permissions
    • Attempt to start IDV flow
    • Verify permission request handling

Expected Results:

Performance and Integration Testing

Test Requirements:

Prepare your IDV implementation for production deployment with these essential security, performance, and user experience considerations.

Security Implementation Checklist

Data Handling and Privacy

Authentication and Authorization

Performance Optimization

Resource Management

User Experience Optimization

Regulatory and Compliance Considerations

Document Recognition Compliance

// Actual IDV configuration structure from server (getIDVConfig() response)
const IDVConfigResponse = {
  "error": {
    "shortErrorCode": 0,
    "errorString": "Success",
    "longErrorCode": 0
  },
  "response": {
    "saveDebugLogs": true,
    "version": "3.0",
    "hologramCheckEnabled": true,
    "imageQualityChecksConfig": {
      "bounds": true,
      "screenCapture": true,
      "focus": true,
      "glare": true,
      "occlusion": true,
      "brightness": true,
      "perspective": true,
      "colorness": true,
      "resolution": true,
      "portraitPresence": true
    },
    "authenticityChecksEnabled": true,
    "supportedVersions": ["3.0"],
    "nfcScanEnabled": true,
    "useDefaultDatabase": true,
    "nfcScanTimeOut": 45,
    "saveCroppedImages": false,
    "authenticityChecksConfig": {
      "geometryCheck": true,
      "invisiblePersonalInfo": true,
      "photoEmbedding": true,
      "extendedOCR": true,
      "securityText": true,
      "opticallyVariableInk": true,
      "extendedMRZ": true,
      "multipleLaserImage": true,
      "portraitComparison": true,
      "electronicDeviceDetection": true,
      "hologram": true,
      "blackAndWhiteCopy": true,
      "dynaprint": true,
      "imagePatterns": true,
      "barcodeFormat": true
    },
    "isRawDataRequired": false,
    "imageQualityThresholds": {
      "dpiThreshold": 200,
      "angleThreshold": 8,
      "maxGlaringPart": 0.1,
      "documentPositionIndent": 80,
      "imgMarginPart": 0.07,
      "brightnessThreshold": 80
    }
  }
};

// Usage example - accessing configuration values:
const config = IDVConfigResponse.response;
const isNFCEnabled = config.nfcScanEnabled;
const imageQualityChecks = config.imageQualityChecksConfig;
const authenticityChecks = config.authenticityChecksConfig;

Privacy and Data Protection

Launch Readiness Checklist

Pre-Production Verification

Go-Live Requirements

Here's your complete reference implementation combining all the patterns and best practices covered in this codelab.

IDV Screen Implementation Showcase

The following images showcase the IDV screens from the sample application demonstrating the complete identity verification workflow:

IDV Configuration Settings Screen (Optional)

IDV Configuration Settings Screen

IDV Configuration management screen displaying server configuration including authenticity checks, image quality settings, and NFC capabilities. This screen and the setIDVConfig API are optional - the REL-ID SDK works with sensible defaults out of the box.

Document Scan Process Start Confirmation Screen

IDV Document Scan Process Start Confirmation Screen

Users receive clear instructions for optimal document capture with lighting guidelines and workflow-specific messaging (IDV workflows: 0=activation, 6=KYC, 13=agent KYC).

Document Details Confirmation Screen

IDV Document Details Confirmation Screen

Interactive review of extracted document information with collapsible sections for identity data, validation results, and document images.

Biometric Opt-in Consent Screen

IDV Biometric Opt-in Consent Screen

Users provide consent for biometric template storage with clear privacy information and opt-out options following compliance requirements.

Congratulations! You've successfully implemented comprehensive identity verification functionality with the REL-ID SDK.

🚀 What You've Accomplished

Complete IDV Integration - Full document scanning and facial recognition workflow implementing all 5 IDV screens
Event-Driven Architecture - Proper handling of complex IDV event chains with seamless navigation
Security Best Practices - Production-ready implementation with comprehensive error handling and compliance features
User Experience Excellence - Intuitive interfaces with clear guidance, real-time feedback, and accessibility support
Production Readiness - Monitoring, compliance, regulatory considerations, and deployment best practices

📈 Advanced IDV Features to Explore

Consider implementing these advanced features to enhance your IDV capabilities:

  1. Multi-Document Verification: Support for multiple document types per user
  2. Document Comparison: Cross-reference multiple identity documents
  3. Enhanced Liveness Detection: Advanced anti-spoofing measures
  4. Real-time Validation: Instant document authenticity checking
  5. Continuous Authentication: Ongoing identity verification during app usage

📚 Additional Resources

🔄 Integration with Other Flows

Your IDV implementation seamlessly integrates with:

🔐 You've mastered secure identity verification with REL-ID SDK!

Your implementation provides users with a comprehensive, secure identity verification experience while maintaining the highest security and compliance standards. Use this foundation to build trust and security into your applications with confidence.