# Architecture Overview

## System Overview

The UBI Beneficiary system enables beneficiaries to manage their benefit applications through UBI / ONEST Network protocol. It consists of four main parts:<br>

1. **Beneficiary UI**: React frontend for beneficiaries to register, upload documents, and manage benefit application
2. **Beneficiary Backend**: NestJS backend handling business logic, authentication, and data management
3. **External Services**: Wallet services , UBI / ONEST Network , Verification and Eligibility SDKs for document processing and benefit eligibility checking&#x20;

## **1. High Level Architecture Diagram**

{% @mermaid/diagram content="graph TB
subgraph "Frontend"
UI\[Beneficiary UI <br/>React + TypeScript]
style UI fill:#e1f5fe,stroke:#01579b
end
subgraph "External Services"
VER\[Verification SDK<br/>Document Verification]
ELIG\[Eligibility SDK<br/>Benefit Eligibility]
EXT\[External Services<br/>Wallet + Document APIs]
UBI\_ONEST\[UBI / ONEST Network]
style VER fill:#e0f2f1,stroke:#00695c
style ELIG fill:#e0f2f1,stroke:#00695c
style EXT fill:#fce4ec,stroke:#c2185b
style UBI\_ONEST fill:#f1f8e9,stroke:#689f38
end

```
subgraph "Backend"
    MW[Beneficiary Backend<br/>NestJS API]
    DB[(PostgreSQL<br/>Database)]
    KC[Keycloak<br/>Authentication]
    H[Hasura<br/>GraphQL Engine]
    style MW fill:#fff8e1,stroke:#ffa000
    style DB fill:#e8f5e9,stroke:#2e7d32
    style KC fill:#fff3e0,stroke:#f57c00
    style H fill:#e3f2fd,stroke:#1976d2
end



UI --> MW
MW --> DB
MW --> KC
MW --> H
MW --> VER
MW --> ELIG
MW --> EXT
MW --> UBI_ONEST
H --> DB
```

" %}

## **2. Sequence Diagrams**

### 2.1 Registration Flow : Registration with Wallet Integration

{% @mermaid/diagram content="sequenceDiagram
participant User as User
participant Frontend as Beneficiary Frontend
participant Backend as Beneficiary Backend API
participant Keycloak as Keycloak
participant Database as PostgreSQL Database
participant Wallet as Wallet Service

```
Note over User, Wallet: Step 1: User Input and Frontend Validation
User->>Frontend: Enter firstName, lastName, phoneNumber, password
Frontend->>Frontend: Validate mobile format (10 digits, 6-9 start)
Frontend->>Frontend: Validate password (min 8 chars, complexity)
Frontend->>Frontend: Validate password confirmation match
Frontend->>Frontend: Generate username: firstName_lastNameInitial_last4DigitsOfMobile

alt Validation Failed
    Frontend->>User: Show validation error toast
else Validation Passed
    Note over User, Wallet: Step 2: API Call and Initial Processing
    Frontend->>Backend: POST /auth/register_with_password<br/>{firstName, lastName, phoneNumber, password}
    
    Note over User, Wallet: Step 3: Backend Data Preparation
    Backend->>Backend: Prepare Keycloak user data<br/>{enabled: true, firstName, lastName, username, credentials, attributes, groups}
    
    Note over User, Wallet: Step 4: Keycloak Integration
    Backend->>Keycloak: getAdminKeycloakToken()
    Keycloak-->>Backend: Admin token
    
    alt Admin Token Failed
        Backend->>Frontend: 500 Internal Server Error
        Frontend->>User: Show error toast
    else Admin Token Success
        Backend->>Keycloak: POST /admin/realms/{realm}/users<br/>{userData with credentials}
        Keycloak-->>Backend: User created (keycloak_id in headers)
        
        alt Keycloak Registration Failed
            Backend->>Frontend: Keycloak error response
            Frontend->>User: Show error toast
        else Keycloak Registration Success
            Note over User, Wallet: Step 5: Database Storage
            Backend->>Backend: Extract keycloak_id from response
            Backend->>Backend: Prepare user data with keycloak_id
            Backend->>Database: createKeycloakData()<br/>{firstName, lastName, phoneNumber, sso_provider: 'keycloak', sso_id: keycloak_id, walletToken: null}
            Database-->>Backend: User record created
            
            alt Database Insert Failed
                Backend->>Keycloak: deleteUser(keycloak_id)
                Keycloak-->>Backend: User deleted
                Backend->>Frontend: 500 Internal Server Error
                Frontend->>User: Show error toast
            else Database Insert Success
                Note over User, Wallet: Step 6: Wallet Service Integration
                Backend->>Backend: Prepare wallet onboarding data<br/>{firstName, lastName, phone, password, username}
                Backend->>Wallet: POST /api/wallet/onboard<br/>{walletData}
                
                alt Wallet Onboarding Failed
                    Note over User, Wallet: Rollback Scenario
                    Backend->>Database: deleteUser(userId)
                    Database-->>Backend: User deleted
                    Backend->>Keycloak: deleteUser(keycloak_id)
                    Keycloak-->>Backend: User deleted
                    Backend->>Frontend: 502 Bad Gateway<br/>"Wallet onboarding failed, registration rolled back"
                    Frontend->>User: Show error toast
                else Wallet Onboarding Success
                    Wallet-->>Backend: Wallet token
                    Backend->>Database: Update user with wallet token
                    Database-->>Backend: User updated
                    
                    Note over User, Wallet: Step 7: Success Response
                    Backend->>Backend: Prepare success response<br/>{user, userName, walletOnboarded: true}
                    Backend->>Frontend: 200 OK<br/>{statusCode: 200, message: "User created successfully", data: {user, userName, walletOnboarded: true}}
                    Frontend->>User: Show success toast<br/>"Registration successful. Username: {userName}"
                    Frontend->>Frontend: Navigate to /signin
                end
            end
        end
    end
end

Note over User, Wallet: Error Handling Scenarios
Note over Frontend: Mobile Validation Errors:<br/>- Empty: "Mobile number is required"<br/>- Length: "Must be exactly 10 digits"<br/>- Format: "Must start with 6-9"
Note over Frontend: Password Validation Errors:<br/>- Empty: "Password is required"<br/>- Length: "Must be at least 8 characters"<br/>- Complexity: "Must contain uppercase, lowercase, number, special char"
Note over Frontend: Password Match Error:<br/>- "Passwords do not match"
Note over Backend: Backend Error Responses:<br/>- 400: Invalid mobile format<br/>- 409: Mobile already exists<br/>- 500: Internal server error<br/>- 502: Wallet service failure

Note over User, Wallet: Technical Implementation Details
Note over Frontend: Username Generation Pattern:<br/>firstName_lastNameInitial_last4DigitsOfMobile (lowercase)
Note over Backend: Keycloak User Data Structure:<br/>{enabled: true, firstName, lastName, username, credentials: [{type: "password", value: password, temporary: false}], attributes: {phoneNumber: [phoneNumber]}, groups: ["default"]}
Note over Backend: Database User Entity:<br/>{firstName, lastName, email, phoneNumber, sso_provider: "keycloak", sso_id: keycloak_id, walletToken, created_at}
Note over Backend: Wallet Onboard Request:<br/>{firstName, lastName, phone, password, username}
Note over Backend: Security Features:<br/>- HTTPS communication<br/>- Request ID generation (UUID)<br/>- SSL verification<br/>- 30-second timeout for wallet API<br/>- Secure password transmission
```

" %}

### 2.2 Document Upload and Profile Update Flow

{% @mermaid/diagram content="sequenceDiagram
participant User as User
participant Frontend as Frontend (React PWA)
participant Backend as Backend API (NestJS)
participant Database as PostgreSQL Database
participant VCAPI as External VC Verification API
participant Wallet as E-Wallet Service
participant Dhiway as Dhiway API
participant Watcher as Watcher Services
participant ProfilePopulator as Profile Populator Service

```
Note over User, ProfilePopulator: Method 1: QR Code Scanning and Document Import

rect rgb(240, 248, 255)
    Note over User, ProfilePopulator: Step 1: Document Selection and QR Scanning
    User->>Frontend: Navigate to document upload screen
    Frontend->>Backend: GET /users/documents (fetch available document types)
    Backend-->>Frontend: Document types list
    Frontend->>User: Display document selection UI
    User->>Frontend: Select document type to upload
    Frontend->>Frontend: Open QR code scanner modal
    Frontend->>Frontend: Request camera permission
    Frontend->>Frontend: Start QR code scanning
    User->>Frontend: Present QR code to camera
    Frontend->>Frontend: Detect QR code containing VC URL
end

rect rgb(240, 255, 240)
    Note over User, ProfilePopulator: Step 2: VC Data Fetching and Validation
    Frontend->>Frontend: Extract VC URL from scanned QR code
    Frontend->>Backend: POST /users/fetch-vc-json {url: VC_URL}
    Backend->>Dhiway: Fetch credential data from VC URL
    Dhiway-->>Backend: VC JSON data
    Backend-->>Frontend: {url: VC_URL, vcData: VC_JSON}
    Frontend->>Frontend: Validate credential schema
    Frontend->>Frontend: Match document type with selected type
    Frontend->>Frontend: Prepare document payload:<br/>{doc_name, doc_type, doc_subtype, doc_data: VC_JSON, imported_from: "QR Code", doc_datatype: "Application/JSON", doc_data_link: VC_URL}
end

rect rgb(255, 248, 240)
    Note over User, ProfilePopulator: Step 3: Document Upload and Processing
    Frontend->>Backend: POST /users/wallet/user_docs [documentPayload]
    Backend->>Backend: Validate user authentication token
    Backend->>VCAPI: Verify document with external VC API
    VCAPI-->>Backend: Verification result (success/failure)
    
    alt VC Verification Failed
        Backend->>Frontend: 400 Bad Request - Document verification failed
        Frontend->>User: Show error toast
    else VC Verification Success
        Backend->>Database: Save document with encrypted doc_data
        Database-->>Backend: Document saved with doc_id
        Backend->>Backend: Write document data to user-specific JSON file
    end
end

rect rgb(248, 240, 255)
    Note over User, ProfilePopulator: Step 4: Watcher Registration (QR Code)
    Backend->>Backend: Check if imported_from is "QR Code"
    Backend->>Dhiway: POST /api/watch<br/>{identifier: extracted_from_doc_data_link, recordPublicId: from_URL_path, email: watcher_email, callbackUrl: backend_callback_endpoint}
    Dhiway-->>Backend: Watcher registration confirmed
    Backend->>Database: Update document with watcher information
    Database-->>Backend: Document updated
end

rect rgb(255, 240, 240)
    Note over User, ProfilePopulator: Step 5: Profile Update Trigger
    Backend->>ProfilePopulator: updateProfile(userId)
    ProfilePopulator->>Database: Fetch user documents
    Database-->>ProfilePopulator: User documents
    ProfilePopulator->>ProfilePopulator: Extract profile fields from document data
    ProfilePopulator->>Database: Update user profile fields
    Database-->>ProfilePopulator: Profile updated
    ProfilePopulator-->>Backend: Profile update completed
    Backend->>Frontend: 200 OK - Document uploaded successfully
    Frontend->>Frontend: Refresh user data and documents
    Frontend->>User: Show success toast - "Document uploaded successfully"
    Frontend->>Frontend: Close scanner modal
end

Note over User, ProfilePopulator: Method 2: E-Wallet Document Import

rect rgb(240, 248, 255)
    Note over User, ProfilePopulator: Step 1: E-Wallet Connection
    User->>Frontend: Click "Import from Wallet" button
    Frontend->>Frontend: Validate wallet token and user data from localStorage
    Frontend->>Frontend: Load e-wallet iframe with embedded mode
    Frontend->>Wallet: Send authentication data via postMessage<br/>{type: "WALLET_AUTH", data: {walletToken, user, embeddedMode: true}}
    Wallet-->>Frontend: Wallet UI displayed with available documents
end

rect rgb(240, 255, 240)
    Note over User, ProfilePopulator: Step 2: Document Selection and Processing
    User->>Wallet: Select documents from wallet interface
    Wallet->>Frontend: Send VC data via postMessage<br/>{type: "VC_SHARED", data: {vcs: [VC_DATA_ARRAY]}}
    Frontend->>Frontend: Validate received VC data structure
    Frontend->>Frontend: Process each selected document:<br/>- Validate credential schema<br/>- Match document type with available types<br/>- Prepare upload payload with imported_from: "e-wallet"
end

rect rgb(255, 248, 240)
    Note over User, ProfilePopulator: Step 3: Document Upload and Verification
    Frontend->>Backend: POST /users/wallet/user_docs [batch_document_payloads]
    Backend->>Backend: Validate user authentication token
    loop For each document
        Backend->>VCAPI: Verify document with external VC API
        VCAPI-->>Backend: Verification result
        alt VC Verification Success
            Backend->>Database: Save document with encrypted doc_data
            Database-->>Backend: Document saved
            Backend->>Backend: Write document data to user files
        end
    end
end

rect rgb(248, 240, 255)
    Note over User, ProfilePopulator: Step 4: E-Wallet Watcher Registration
    Backend->>Backend: Check if imported_from is "e-wallet"
    loop For each e-wallet document
        Backend->>Wallet: POST /api/wallet/vcs/watch<br/>{vcPublicId: from_document_data, callbackUrl: backend_callback_endpoint}<br/>Authorization: Bearer token
        Wallet-->>Backend: Watcher registration confirmed
        Backend->>Database: Update document with watcher information
        Database-->>Backend: Document updated
    end
end

rect rgb(255, 240, 240)
    Note over User, ProfilePopulator: Step 5: Profile Update and Completion
    Backend->>ProfilePopulator: updateProfile(userId)
    ProfilePopulator->>Database: Fetch all user documents
    Database-->>ProfilePopulator: User documents
    ProfilePopulator->>ProfilePopulator: Extract and update user profile fields
    ProfilePopulator->>Database: Update user profile and custom fields
    Database-->>ProfilePopulator: Profile updated
    ProfilePopulator-->>Backend: Profile update completed
    Backend->>Frontend: 200 OK - Batch upload results
    Frontend->>Frontend: Refresh user data and documents
    Frontend->>User: Show upload status toast with results
    Frontend->>Frontend: Close wallet iframe
end

Note over User, ProfilePopulator: Watcher Callback Flow (Both Methods)

rect rgb(255, 255, 240)
    Note over User, ProfilePopulator: Step 1: Document Update Notification
    Watcher->>Watcher: Detect document update in external service
    Watcher->>Backend: POST /users/wallet-callback<br/>{identifier, message, type, recordPublicId}
end

rect rgb(240, 255, 255)
    Note over User, ProfilePopulator: Step 2: Document Update Processing
    Backend->>Database: Find documents matching recordPublicId
    Database-->>Backend: Matching documents
    Backend->>Backend: Validate callback data and document existence
    Backend->>Dhiway: Fetch updated document data
    Dhiway-->>Backend: Updated VC data
    Backend->>VCAPI: Re-verify updated document data
    VCAPI-->>Backend: Verification result
    Backend->>Database: Update document data in database
    Database-->>Backend: Document updated
    Backend->>Backend: Update document files
    Backend->>ProfilePopulator: Trigger profile re-population
    ProfilePopulator->>Database: Update user profile with new data
    Database-->>ProfilePopulator: Profile updated
end

Note over User, ProfilePopulator: Profile Update Process (Automated)

rect rgb(248, 255, 248)
    Note over User, ProfilePopulator: Step 1: Profile Population Trigger
    ProfilePopulator->>ProfilePopulator: Cron job runs every 5 minutes
    ProfilePopulator->>Database: Select users with unverified/outdated fields
    Database-->>ProfilePopulator: Users requiring profile updates
end

rect rgb(255, 248, 255)
    Note over User, ProfilePopulator: Step 2: Profile Data Extraction
    loop For each user
        ProfilePopulator->>Database: Fetch all user documents
        Database-->>ProfilePopulator: User documents
        ProfilePopulator->>ProfilePopulator: Process each document's VC data
        ProfilePopulator->>ProfilePopulator: Map document fields to user profile fields
        ProfilePopulator->>ProfilePopulator: Validate and format extracted data
        ProfilePopulator->>ProfilePopulator: Build comprehensive user profile
    end
end

rect rgb(255, 255, 248)
    Note over User, ProfilePopulator: Step 3: Database Update
    loop For each user
        ProfilePopulator->>Database: Update user table with extracted fields
        Database-->>ProfilePopulator: User profile updated
        ProfilePopulator->>Database: Update custom field values
        Database-->>ProfilePopulator: Custom fields updated
        ProfilePopulator->>Backend: Update user attributes in Keycloak
        Backend-->>ProfilePopulator: Keycloak updated
        ProfilePopulator->>Database: Mark fields as verified
        Database-->>ProfilePopulator: Verification status updated
    end
end

Note over User, ProfilePopulator: Error Handling Scenarios
Note over Frontend: QR Code Errors:<br/>- Invalid QR code format<br/>- Unsupported document type<br/>- Camera access denied
Note over Frontend: E-Wallet Errors:<br/>- Wallet authentication failure<br/>- Invalid VC data structure<br/>- Document type mismatch
Note over Backend: Backend Errors:<br/>- VC verification failure<br/>- Database storage failure<br/>- Watcher registration failure
Note over Backend: Profile Update Errors:<br/>- Profile population errors (logged but non-blocking)<br/>- Field mapping failures<br/>- Data validation errors

Note over User, ProfilePopulator: Technical Implementation Details
Note over Frontend: Document Payload Structure:<br/>{doc_name, doc_type, doc_subtype, doc_data, uploaded_at, imported_from, doc_datatype, doc_data_link}
Note over Backend: Database Schema:<br/>UserDoc: {doc_id, user_id, doc_type, doc_subtype, doc_name, imported_from, doc_path, doc_data_link, doc_data (encrypted), doc_verified, watcher_registered, watcher_email, watcher_callback_url}
Note over Backend: Security Features:<br/>- Document encryption using EncryptionTransformer<br/>- Authentication token validation<br/>- VC verification with external API<br/>- Origin validation for iframe communication<br/>- Secure wallet token handling
Note over Backend: API Endpoints:<br/>- POST /users/wallet/user_docs (batch upload)<br/>- POST /users/fetch-vc-json (VC data fetching)<br/>- POST /users/wallet-callback (watcher callbacks)<br/>- POST /api/watch (Dhiway watcher registration)<br/>- POST /api/wallet/vcs/watch (e-wallet watcher registration" %}
```

### 2.3 Benefit application submission flow

{% @mermaid/diagram content="sequenceDiagram
participant U as User
participant BA as Beneficiary App
participant BE as Beneficiary Backend
participant PB as Provider Backend

```
Note over U,PB: Benefit Application Flow

%% Step 1: User initiates application
U->>BA: Clicks "Apply" on benefit
BA->>BA: Validate prerequisites<br/>(documents, expiry, eligibility)

alt Prerequisites validation fails
    BA->>U: Show error dialog
else Prerequisites validation passes

    %% Step 2: Get benefit schema and details
    BA->>PB: GET /select<br/>{benefit_id}
    PB->>BA: Return benefit details<br/>+ form schema

    %% Step 3: Build form on beneficiary side
    BA->>BA: Generate form from schema<br/>Prefill with user profile data
    BA->>U: Display form<br/>(prefilled with user data)

    %% Step 4: User completes form
    U->>BA: Fill form fields
    U->>BA: select documents
    U->>BA: Submit form

    %% Step 5: Form validation and create application
    BA->>BA: Validate form data
    alt Validation fails
        BA->>U: Show validation errors
    else Validation passes
        %% Step 6: Create application on beneficiary side
        BA->>BE: Create application<br/>(status: "initiated")
        BE->>BA: Application created

        %% Step 7: Initialize with provider
        BA->>PB: POST /init<br/>{benefit_id, form_data, VCs}
        PB->>BA: Application created on provider side

        %% Step 8: Confirm and get order ID
        BA->>PB: POST /confirm<br/>{application_id}
        PB->>BA: Return order_id

        %% Step 9: Update application with order ID
        BA->>BE: Update application<br/>(order_id, status: "submitted")
        BE->>BA: Application updated
        BA->>U: Show success message<br/>with order ID
    end
end

%% Form resubmission flow
Note over BA,PB: Form Resubmission Flow
alt User resubmits form
    U->>BA: Modify and resubmit form
    BA->>PB: POST /update<br/>{application_id, updated_data}
    PB->>BA: Application updated
    BA->>U: Show update confirmation
end

%% Error handling flows
Note over BA,PB: Error Scenarios
alt Network/Service Failure
    PB-->>BA: Error response
    BA->>U: Show error message
end

alt Eligibility Issues
    PB-->>BA: Ineligible response
    BA->>U: Show eligibility reasons
end" %}
```
