8byte.ai
📙 Part 3 of 3 — Combined Architecture & Flow

8byte LOS
Full Platform Work Flow

The complete picture: how the frontend and backend work together, every user journey from start to finish, the full data flow, system architecture, and how every piece connects.

8
Loan Stages
9
User Roles
25+
External APIs
6+
Lending Brands
5
Payment Gateways
🎯

About the Platform

The complete picture in one place

8byte LOS (Loan Origination System) is a production-ready, multi-brand lending platform for Indian NBFCs and fintech companies. It manages the complete loan lifecycle — from a customer's first registration, through KYC and credit checks, to disbursement, repayment, and final closure — with full automation, multi-channel communication, and a comprehensive internal operations portal for lending staff.

👥 Two User Worlds

Customers interact via a web/mobile app (handled by the /web/ API). Partner staff (loan executives, collection agents, admins) interact via the React partner portal (the frontend we documented). These are completely separate authenticated systems.

🏷️ Multi-Brand Platform

A single codebase serves multiple lending brands simultaneously: Qualoan, PaisaPop, Salary4Sure, FastSalary, SalaryBolt, and more. Each brand has its own loan rules, theme, communication templates, staff, and settings — but shares the same infrastructure.

🔄 Full Lifecycle Coverage

From customer acquisition (UTM tracking, lead forms) → onboarding (KYC) → credit assessment (BRE, CIBIL) → approval → e-sign → disbursement → repayment → collections → closure. Every step is tracked, logged, and auditable.

🏗️

Full System Architecture

Every layer of the platform and how they connect

Client Layer

React 19 Partner Portal (Staff SPA) Customer Web/Mobile App Redux Toolkit State Axios API Client React Router v7 TailwindCSS + Framer Motion Acefone VoIP Widget FingerprintJS

API Layer — NestJS 10 on Port 4002 (PM2 Cluster × 2)

JWT Auth Guard Role Permission Guard Throttle Rate Limiter Validation Pipe (class-validator) Compression Middleware Helmet Security Headers 105 Controllers 174 Services Request/Response Interceptors BigInt Serializer Global Exception Filter

Auth & Identity

Web Auth (OTP) Partner Auth (Password) JWT + bcrypt Device Fingerprint Session Tracking

Loan Engine

Loan CRUD Status Machine Auto-Allocation Evaluation v1/v2 BRE Reloan Automation

Payment Engine

Razorpay Cashfree Paytring IDFC Disbursal ICICI Disbursal Autopay Mandate

Database

PostgreSQL Prisma ORM GIN/TRGM Indexes Migrations

Cache & Queues

Redis Cache RabbitMQ Jobs AWS SQS Audit AWS SQS NOC Trigger.dev

File Storage

AWS S3 Public AWS S3 Private Presigned URLs PDF Generation

External API Integrations (25+)

Digitap (KYC) Equifax (Credit) CIBIL (Credit) CIR Pro V2 (BRE) CART (BSA) Finbox (BSA) ScoreMe (BSA+Score) Account Aggregator Penny Drop Signzy (eSign) SignDesk (eSign) DigiLocker 2.0 EPFO/UAN Acefone (VoIP) Lendbox (CoLend) SendGrid/Brevo/Zepto MSG91/Gupshup/NimbusIT AiSensey (WhatsApp) Google Maps
🏷️

Multi-Brand Model

How one codebase serves many lending brands

Every route in the partner portal is scoped to a brandId: /:brandId/loans, /:brandId/dashboard, etc. The backend extracts this brandId from the URL, validates that the logged-in partner user has access to that brand, and then filters all database queries by that brandId. Two staff at different brands cannot see each other's data even if they use the same app.

🎨 Brand Isolation

Each brand has its own: logo, color theme, loan rules (min/max amounts, tenures, interest rates), evaluation criteria, email templates, SMS templates, partner staff, and customers. Complete data isolation at the database level via brandId foreign keys.

⚙️ Brand Config Flow

On login, the partner portal fetches brand config via GET /settings/brand. This is stored in the Redux brand slice. The ThemeProviderContext injects the brand's colors as CSS variables. All subsequent API calls include the brandId automatically.

🔐 Brand Access Control

A partner user can be assigned to one or multiple brands (stored in PartnerUserBrandRole). They log in once and can switch between their brands. The Super Admin can access all brands via the /admin portal without brand scoping.

👤

Complete Customer Journey

Every step from signup to loan closure

Customer Journey — Step by Step
1. Acquisition
Sees ad (UTM tracked)
Lands on brand website
Clicks Apply
UTM params saved to DB
2. Registration
Enters phone number
OTP sent via SMS
Verify OTP
User record created
JWT issued
3. KYC
Enter PAN
Digitap verifies PAN
Aadhaar OTP
Upload selfie + docs
Docs to S3
4. Employment
Enter employer details
Enter UAN
EPFO verification
Upload payslips
5. Bank
Add bank account
Penny drop verify
Upload bank statement
BSA analysis runs
6. Evaluation
Credit report fetched
BRE hard rules check
Evaluation scoring
Loan auto-allocated to executive
7. Approval
Credit executive reviews
Sanction manager approves
Sanction head confirms
Status → SANCTIONED
8. eSign
Agreement PDF generated
Sent to Signzy/SignDesk
Customer signs digitally
Webhook → SIGNED
9. Disbursement
Bank details re-verified
Transfer via IDFC/ICICI
Status → DISBURSED
Repayment timeline created
Confirmation SMS/Email
10. Repayment
Reminders 3 days before due
Customer pays via Razorpay/Cashfree
Outstanding updated
Receipt sent
11. Closure
All EMIs paid
Status → COMPLETED
NDC (No-Due Certificate) generated
Reloan eligibility check
🆔

KYC Verification Flow

Detailed flow of every identity verification step

1

PAN Verification

Customer enters PAN number → Frontend calls POST /web/kyc/verify-pan → Backend calls Digitap PAN API → Name, DOB fetched from PAN database → Saved to PanAadhaarVerification table → Customer's name pre-filled

2

Aadhaar OTP Verification

Customer enters Aadhaar number → POST /web/kyc/initiate-aadhaar-otpDigitap sends OTP to Aadhaar-linked mobile → Customer enters OTP → POST /web/kyc/submit-aadhaar-otp → Address + photo extracted from Aadhaar → Saved to User model

3

Document Upload

Customer uploads PAN card image, Aadhaar image, selfie → React Dropzone sends multipart form → Backend calls S3Service.uploadPrivate() → Returns S3 key → Creates Document record with type, S3 key, status=PENDING → Partner staff reviews and marks VERIFIED

4

Mobile Verification

Verify that phone number matches PAN records → Mobile-to-PAN API check → Also verifies address from mobile number via Mobile-to-Address provider → Saved to MobileToPanVerification

5

DigiLocker (Optional)

For enhanced verification, customer authorizes DigiLocker 2.0 → Official documents fetched directly from government → Stored in aadhaar_digi_locker_log → Bypasses manual document review

6

Bank Account + Penny Drop

Customer enters account number + IFSC → Backend calls Penny Drop API (sends ₹1 to account) → Verifies account holder name matches PAN name → Creates UserBankAccount with verified=true

7

Employment via EPFO

Customer enters UAN → Phone-to-UAN API verifies UAN belongs to customer's phone → UAN-to-Employment API fetches employment history from EPFO → Employer, salary, joining date extracted → Creates Employment record

📄

Loan Application Flow

From application submission to allocation

📋 Application Submission

1

Customer submits loan application

Enters desired loan amount and tenure on the web app. Frontend validates against brand's min/max rules before submitting.

2

Brand rules validation

Backend's brandRuleValidation service checks amount, tenure against brand config. Rejects if outside bounds.

3

Loan record created

Creates Loan record with status=APPLIED. Saves amount, tenure, userId, brandId.

4

Auto-allocation triggered

autoAllocation service assigns loan to an available loan executive using round-robin + workload balancing.

📊 Bank Statement Analysis

1

Customer uploads bank statement

PDF uploaded to S3 private bucket. S3 key saved to BankAccountStatement.

2

BSA provider called

Statement sent to CART, Finbox, or ScoreMe depending on brand config. Provider analyzes salary credits, EMI debits, balance trends.

3

BDA report stored

Analysis results saved to BdaReport. Available in customer detail view for loan executives to review.

4

Account Aggregator (optional)

RBI AA consent flow — customer authorizes bank data sharing directly. More accurate than PDF analysis.

🧮

Credit Assessment Flow

How the BRE and evaluation engine decide on a loan

Loan Applied
Status: APPLIED
Fetch Credit Report
CIBIL + Equifax
BRE Hard Rules
CIR Pro V2
Hard Rule Fails?
→ AUTO REJECTED
↓ All pass
Evaluation Engine
Score criteria items
BSA Results
Income, cash flow
Total Score
Weighted sum
Score ≥ Threshold?
→ AUTO SANCTIONED
↓ Below threshold / manual review
Credit Executive
Reviews application
Sanction Manager
First approval
Sanction Head
Final approval
SANCTIONED
Proceed to eSign

Sanction Approval Flow

How loan approval moves through internal hierarchy

Sanction Workflow — Role by Role
Credit Executive
Opens /:brandId/credit-executive
Reviews BSA report, evaluation score, bureau report
May override evaluation score
Forwards to Sanction Manager
Sanction Manager
Opens /:brandId/sanction-manager
Reviews all loan docs, credit exec notes
Can approve (with conditions) or reject
Forwards to Sanction Head
Sanction Head
Opens /:brandId/sanction-head
Final authority review
Approves → status SANCTIONED
Notification sent to customer
System (Backend)
Creates LoanStatusHistory entry
Generates loan agreement PDF
Sends for e-signature
SMS/Email: "Your loan is approved"
✍️

E-Signature Flow

Digital agreement signing via Signzy / SignDesk

1

Agreement PDF Generated

Backend uses PDFKit/Puppeteer to generate a loan agreement PDF with customer details, loan amount, tenure, interest rate, repayment schedule, T&C. Saved to S3 private bucket.

2

E-Sign Request Sent

Backend calls Signzy V3 or SignDesk API (based on brand config) with the PDF URL. Provider sends a signing link to the customer's registered mobile/email.

3

Customer Signs

Customer opens the link, reviews the agreement, signs with Aadhaar OTP-based e-signature. The signature is legally valid under India's IT Act.

4

Webhook Confirmation

Signzy/SignDesk sends a webhook to the backend with signing status. Backend updates Loan.agreementStatus = SIGNED, saves signed PDF S3 key, triggers disbursement workflow.

💸

Disbursement Flow

From signed agreement to money in customer's account

Disbursement Process
Loan Ops Staff
Opens /:brandId/loans-ops
Sees pending disbursement queue
Verifies bank details + penny drop
Approves disbursement
Backend API
Calls IDFC or ICICI Disbursement API
Bank transfer initiated
Creates PaymentDisbursalTransaction
Loan.status → DISBURSED
Post-Disbursement
RepaymentTimeline created (EMI schedule)
SMS: "Loan disbursed ₹X"
Ledger entry created
Autopay mandate offered
💼

Collection Flow

Repayment management from pre-due to closure

Active Loan
Disbursed, repaying
Pre-Collection
3-7 days before due
Reminders Sent
SMS + WhatsApp + Email
Customer Pays?
Via Razorpay/Cashfree
EMI Marked Paid
Timeline updated
↓ No payment
Overdue
Past due date
Collection Queue
Assigned to exec
Acefone Call
VoIP from portal
Follow-up Logged
Outcome recorded
↓ Persistent non-payment
Post-Collection
Escalated case
Collection Head
Reviews case
Settlement Offer
Reduced amount
Write-Off
If unrecoverable

📞 Acefone VoIP Integration in Collection

When a collection executive clicks "Call" on a loan in the portal, the AcefoneContext in the frontend initiates a VoIP call via the Acefone API. The call widget appears as an overlay. Backend creates a UserCall record. Call events (connected, ended, etc.) trigger UserCallEvent records. After the call, the recording URL is saved and linked to the customer's profile in the UserCallRecording table. Collection agents can replay recordings directly from the portal.

💳

Payment Processing Flow

How money flows through the system

1

Payment Initiated

Customer pays via Razorpay/Cashfree payment page (from customer app). OR collection agent triggers payment link from portal. Creates PaymentRequest record with PENDING status.

2

Gateway Processing

Payment gateway processes the transaction. Customer authorizes via UPI, card, or netbanking. Gateway holds the transaction in PROCESSING state.

3

Webhook Callback

Gateway sends a webhook to POST /partner/brand/:brandId/payment/webhook. Backend validates webhook signature. If SUCCESS: creates PaymentCollectionTransaction, updates Loan.outstandingAmount, marks EMI as paid in RepaymentTimeline.

4

Approval Queue (if applicable)

Certain payment types require manual approval. Loan Ops staff see these in the /:brandId/payment-approval queue. They review UTR number, amount, and approve or reject.

5

Ledger + Notifications

Creates LoanLedgerEntry for financial tracking. Sends payment receipt via SMS + email. If all EMIs paid: triggers loan closure flow → NDC generation → NOC email sent via SQS queue.

🔐

Authentication Flow (Both Sides)

Customer OTP auth vs Partner password auth

Customer Auth (OTP-based)

1

Enter phone number → POST /web/auth/register

2

Backend generates 6-digit OTP → saves to UserOtpVerification → sends via SMS (MSG91/Gupshup)

3

Enter OTP → POST /web/auth/verify-otp → OTP validated (5min TTL)

4

JWT issued → UserLoginToken created → tokens returned to customer app

Partner Auth (Password-based)

1

Enter email + password on login page

2

Backend fetches PartnerUser by email → bcrypt.compare(password, hash)

3

Device fingerprint registered → PartnerUserLoginLog created

4

JWT issued with roles+permissions+brandIds embedded → PartnerLoginToken stored → Redux updated

📢

Notification & Communication Flow

How messages reach customers and staff

Multi-Channel Communication Pipeline
Trigger
Cron job fires
API event (loan status change, payment received, etc.)
Manual trigger from portal
Queue
Job published to RabbitMQ
Job includes: userId, channel, templateId, params
Worker picks up job
Channel Select
SMS → Gupshup / MSG91 / Hub / NimbusIT
|
Email → SendGrid / Brevo / Zepto
|
WhatsApp → AiSensey
Delivery
Primary provider called
Failed? → Failover to next provider
Log delivery in DB
Create UserNotification record
🎯

Auto-Allocation Flow

How loans and customers are automatically assigned to staff

👤 Customer Auto-Allocation

When a new customer completes registration, user.autoAllocation.service finds an available loan executive by: checking brand assignment, current load, availability status. Creates LoanAllottedPartnerUser record. Executive gets notified.

📋 Loan Auto-Allocation

When a loan application is submitted, loan.autoAllocation.service assigns it using round-robin rotation among loan executives with capacity. Checks PartnerUnavailabilityDate to skip staff on leave.

💼 Collection Auto-Allocation

When a loan becomes overdue, collection.autoAllocation.service assigns it to a collection executive based on: geographic proximity, current collection load, and performance ratings from partner_user_rating_matrix.

🗺️

Complete Data Flow Map

Where data comes from and where it goes

📥 Inbound Data Sources

Customer web app inputs Partner portal actions Payment gateway webhooks E-sign webhooks (Signzy/SignDesk) Digitap KYC responses CIBIL/Equifax credit reports CART/Finbox BSA results EPFO employment data Penny drop verification Account Aggregator data Acefone call events

📤 Outbound Data Flows

API responses → React frontend KYC documents → S3 private Brand logos → S3 public Loan agreement PDFs → S3 + eSign SMS → Multiple providers Email → SendGrid/Brevo/Zepto WhatsApp → AiSensey Audit events → SQS Job payloads → RabbitMQ Disbursements → IDFC/ICICI Reports CSV → Client browser
🔒

Roles × Features Access Matrix

Who can access what in the partner portal

Feature Super Admin Admin Loan Exec Credit Exec Sanction Mgr Sanction Head Coll. Exec Coll. Mgr Coll. Head
Dashboard
Customer List
Loans List
Sanction Manager View
Credit Executive View
Collections
Pre-Collection
Write-Off Authority
Loan Ops
Settings
Reports
Staff Management
🔌

Integrations Map

Which external API is used at which stage

🆔 KYC Stage

Digitap — PAN verify Digitap — Aadhaar OTP DigiLocker 2.0 — Official docs Penny Drop — Bank verify Mobile-to-PAN — Fraud check Mobile-to-Address — Verify EPFO/UAN — Employment Google Maps — Geocoding

📊 Credit Assessment Stage

Equifax — Credit report CIBIL — Credit score CIR Pro V2 — BRE CART — Bank statement analysis Finbox — BSA (alternate) ScoreMe — Credit scoring + BDA Account Aggregator — Bank data

✍️ Approval & eSign Stage

Signzy V3 — e-Signature SignDesk — e-Signature (alt) PDFKit/Puppeteer — Agreement PDF AWS S3 — Document storage

💸 Disbursement Stage

IDFC Bank — Transfer ICICI Bank — Transfer (alt) Penny Drop — Final verify Lendbox — Co-lending

💳 Repayment/Collection Stage

Razorpay — Collection Cashfree — Collection (alt) Paytring — Collection (alt) Razorpay Autopay — Mandate Acefone — VoIP calls Stringee — Call center

📱 Communication (All Stages)

SMS Gateway Hub Gupshup MSG91 NimbusIT SendGrid Brevo Zepto AiSensey (WhatsApp)
🔒

Security Layers

Every security mechanism in the platform

🔑 Authentication

JWT access + refresh tokens bcrypt (12 salt rounds) OTP with 5min TTL Token blacklisting on logout

🛡️ Authorization

RBAC (9 roles) PBAC (25+ permissions) brandId isolation Route-level guards

🌐 Network Security

Helmet HTTP headers CORS whitelist Rate limiting (ThrottleGuard) HTTPS enforced

📦 Data Security

S3 private bucket encryption Presigned URLs (time-limited) 50MB upload limit Input validation (class-validator)

📱 Device & Session

Device fingerprinting (FingerprintJS) Activity session tracking Inactivity alerts Login logs

📝 Audit & Compliance

All API calls logged Audit events to AWS SQS User action tracking Webhook signature validation

Performance Architecture

How the platform handles scale

🚀 Frontend Performance

Vite build (code splitting) React 19 (concurrent features) lodash.debounce on search inputs Pagination on all lists Lazy loading of routes Redux for minimal re-renders

⚡ Backend Performance

PM2 cluster × 2 instances Redis caching (TTL-based) PostgreSQL GIN/TRGM indexes gzip compression Async queue processing BigInt serializer

📊 Database Performance

Prisma optimized queries GIN indexes for text search TRGM for fuzzy name matching Foreign key indexes Connection pooling

🔄 Async Performance

RabbitMQ decouples heavy operations AWS SQS for durable queues Trigger.dev for managed jobs Cron worker on separate process Graceful shutdown handling

🏁 Summary — The Complete 8byte LOS Platform

This platform is a full-stack, production-grade loan origination system that covers every aspect of the Indian NBFC lending process:

Multi-brand isolation Role-based access (9 roles) Complete KYC automation (10+ providers) Credit assessment (CIBIL + Equifax + BRE) Multi-gateway payments (5 gateways) Digital e-signature (Signzy + SignDesk) VoIP call center integration Multi-channel communication (8 providers) AWS cloud infrastructure Real-time dashboards Comprehensive audit logging Background job processing Auto-allocation algorithms PM2 cluster deployment

The React frontend and NestJS backend are tightly coupled via a well-defined REST API, with JWT authentication, brand scoping, and role-based access enforced at every layer — from the Redux store and React Router guards in the frontend, all the way down to Prisma database queries filtered by brandId on the backend.

🔗

Account Aggregation (AA) Flow

RBI-framework consent-based financial data fetch via FINDUIT / CART providers

Account Aggregation (AA) is an RBI-mandated framework that lets users share their bank statement / financial data with lenders through a regulated consent journey — without sharing credentials. 8byte integrates with AA providers (FINDUIT / CART) via a dedicated module.
1

Credit Executive Initiates AA

From the loan detail page, a credit exec clicks "Initiate Account Aggregation". The frontend calls POST /partner/brand/:id/aa/consent-request with userId + loanId. Backend creates an AAConsentRequest record with status PENDING.

2

Consent Link Sent to Customer

Provider (FINDUIT/CART) generates a consent URL and sends it to the customer via SMS/WhatsApp. The AA consent record stores consentId, txnId, and the redirect URL for tracking.

3

Customer Approves Consent

Customer opens the link on their phone, authenticates with their bank's AA app (e.g. PhonePe, Perfios), and approves sharing 6–12 months of bank statement data. Consent status updates to APPROVED via webhook.

4

Data Fetch & Analysis

Backend automatically fetches the financial data from the AA provider once consent is approved. The data is stored and the credit exec can view the Bank Statement Analysis (BSA) report inside the loan profile — salary credits, EMI obligations, spending patterns.

5

Credit Assessment Integration

AA data feeds into the CAM Calculator (average salary, obligations) and the overall credit decision. The consent request list is available via GET /partner/brand/:id/aa/consent-requests with pagination and status filtering.

Provider: FINDUIT / CART Consent-based (RBI AA Framework) AAConsentRequest DB model Webhook status update Feeds into CAM Calculator
📋

Lead Management Flow

Facebook Ad leads → CSV import → match to users → auto-process

Lead Management handles inbound leads from Facebook Ad campaigns. Admins/Sales download lead CSVs from Facebook Ads Manager and upload them to the portal. The system matches, deduplicates, and processes leads.
1

CSV Upload

Admin or Sales team downloads the leads CSV from Facebook Ads Manager and uploads it via POST /partner/brand/:id/lead-forms/upload (multipart/form-data). Backend parses rows and stores each as a LeadForm record with status PENDING.

2

Deduplication Check

On upload, the system checks for duplicate entries (same phone/email within the same brand). Duplicates are marked with status DUPLICATE and excluded from further processing.

3

Sync / Process

Staff trigger sync via POST /partner/brand/:id/lead-forms/sync. The backend attempts to match each PENDING lead to an existing platform user by phone number. Matched leads get PROCESSED status; unmatched or errored leads get FAILED with an error message.

4

View & Filter

The Leads page shows paginated lead forms with search, status filter (PENDING / PROCESSED / FAILED / DUPLICATE), and stats cards (total / pending / processed / failed / duplicates). Staff can drill into each lead to see campaign info (ad ID, ad set, form name) and lead responses (salary, PAN, employment type).

5

Export & Bulk Delete

Leads can be exported as CSV (GET /lead-forms/export) for external use. Bulk delete is available via DELETE /lead-forms/bulk with an array of IDs. Organic leads (isOrganic=true) are tracked separately from paid campaign leads.

Source: Facebook Ads CSV upload → parse → store Status: PENDING / PROCESSED / FAILED / DUPLICATE LeadForm DB model Campaign tracking (adId, adsetId, campaignId)
🧮

CAM Calculator Flow

Credit Appraisal Memo — how credit executives assess loan eligibility

CAM (Credit Appraisal Memo) is the credit underwriting worksheet filled by a credit executive to formally compute the customer's loan eligibility. It captures salary data, FOIR (Fixed Obligation to Income Ratio), recommended loan amount, and repayment projections.
1

Open CAM Form

Credit executive opens the loan profile and navigates to the CAM Calculator tab. The frontend fetches any existing CAM via GET /loans/cam-calculator/:loanId — if one exists, the form is pre-populated.

2

Enter Salary Data

Exec enters up to 3 months of salary credit dates and amounts (salaryCreditDate1-3, salaryAmount1-3). The system auto-calculates avgSalary. The next pay date (nextPayDate) is also captured for disbursement planning.

3

Compute Eligibility

Based on avg salary and existing obligations (obligations), the system computes: eligibleFoir (allowed FOIR%), foirAchieved (current FOIR%), proposedFoir (after new loan), eligibleLoan (max loan based on FOIR), and roi (rate of interest).

4

Set Recommended Amount

Exec enters loanRecommended (which may differ from the customer's requested loanApplied). Disbursal date, repayment date, and tenure are also set. The repaymentData JSON captures the full EMI/repayment schedule.

5

Save & Submit

On save, the frontend calls POST /loans/brand/:brandId/cam-calculator/save. Backend upserts the CAMCalculator record linked to loanId + userId + partnerUserId. The saved CAM becomes part of the loan file reviewed by sanction managers.

Role: Credit Executive CAMCalculator DB model Fields: avgSalary, FOIR, eligibleLoan, ROI Linked to loanId + userId Feeds into sanction decision

Reminder Scheduling Flow

How staff create, schedule, and track customer reminders

Reminders are targeted, scheduled messages sent to specific customers through a chosen channel (SMS, WhatsApp, Email) at a future time. They're created by collection or ops staff and tracked centrally in the Reminders module.
1

Create Reminder

Staff opens the Reminders page and clicks "Create Reminder". They select a user (customer), choose a channel (SMS / WhatsApp / Email), pick a message template (templateCode), set a future scheduledAt timestamp, and optionally fill template variables in the payload map.

2

Store in DB

The frontend calls POST /partner/brand/:id/user-reminders. Backend creates a UserReminder record with status PENDING. The record stores userId, channel, templateCode, scheduledAt, and payload.

3

Cron Job Dispatch

A background cron runs every minute (@Cron(CronExpression.EVERY_MINUTE)) and polls for reminders where scheduledAt ≤ now and status = PENDING. It dispatches the message via the appropriate provider (MSG91, Gupshup for SMS; AiSensey for WhatsApp; SendGrid for Email) using the template code.

4

Status Update

After dispatch attempt, status updates to SENT (success) or FAILED (error). If a providerMessageId was specified during creation, it's stored for delivery tracking. Every status change is audit-logged.

5

Monitor & Audit

Staff views all reminders via GET /partner/brand/:id/user-reminders with filters: channel, status, date range, search. The Audit Log for each reminder (GET /user-reminders/:id/audit-logs) shows every state transition with timestamps and actor.

Channels: SMS / WhatsApp / Email UserReminder DB model Status: PENDING → SENT / FAILED Cron-based dispatch Full audit log per reminder
📞

Acefone VoIP Click-to-Dial Flow

End-to-end flow: staff initiates a call to a customer from the partner portal

Acefone (and Stringee as secondary) is the VoIP provider integrated into the partner portal. Staff can make calls directly from any loan/user profile without leaving the browser. Calls are logged automatically with duration, disposition, and call recording links.
1

Brand Enables Dialer

Admin enables dialer via Brand Settings → Acefone configuration (API credentials, extension numbers). The AcefoneDialerProvider in the React app wraps the entire application and initializes the dialer SDK on mount.

2

Staff Clicks Call Button

On any user/loan profile page, staff clicks the phone icon next to the customer's number. The useAcefoneDialer hook calls initiateCall() which posts to /acefone/dialer/initiate with userId, partnerUserId, brandId, and optional loanId.

3

Acefone API Call

The backend forwards the click-to-call request to Acefone's API using the configured credentials. Acefone bridges the call — first calling the agent's extension, then dialing the customer when the agent answers.

4

Call Logs Auto-Saved

After the call ends, Acefone sends a webhook to POST /acefone/dialer/outbound. Backend stores the call log — duration, call status (answered/missed/busy), recording URL — linked to the user/loan.

5

View History

Call logs are viewable per user (GET /acefone/dialer/user/:userId/calls) and per partner agent (GET /acefone/dialer/partner/:partnerUserId/calls). Individual call details via GET /acefone/dialer/call/:callId. Stats per user/agent via the /stats endpoints.

Provider: Acefone (primary) / Stringee (secondary) Click-to-call from portal Auto call-log via webhook AcefoneDialerProvider context CDR reporting
📊

Report Generation Flow

How reports are generated, what types exist, and how they're exported

The Reports module provides data exports for analytics, compliance, and collections follow-up. All reports are date-range filtered and available as both paginated views and CSV downloads. Reports are restricted to Admin / Super Admin roles.
The backend exposes 29 report types across three categories: User/Loan, Collection, and Marketing/Credit.

📋 User & Loan Reports

master-report — full user+loan dump (PAN, Aadhaar, employment, bank, references, all loan statuses).

disbursed-loan-report, non-disbursed-loan-report, disburse-non-disburse-report — disbursement tracking.

active-loans-by-due-date-report, completed-loan-with-no-repet-report, loan-close-report, outstanding-data-report, reject-report, total-approve-sanction-report, affiliate-report, login-sessions-report.

💼 Collection Reports

master-collection-report — overdue loans, amounts, agent assignments.

collection-loan-report, collection-due-report, collection-loan-report-by-approved-date — per-loan collection views.

collection-allocation-executive-report, credit-executive-allocation-report, collection-remarks-report, total-recovery-report, field-visit-report.

📣 Marketing & Credit Reports

marketing-report, internal-marketing-report, internal-marketing-analysis-report — lead funnel and campaign data.

daily-marketing-mis-report — daily MIS snapshot.

lead-total-report, cic-report (CIBIL/Equifax bureau pulls), equifax-credit-report, transunion-report.

1

Select Report Type & Date Range

Admin opens the Reports page, selects report type from dropdown (e.g. master-report, marketing-report, collection-loan-report, disbursed-loan-report), and sets fromDate / toDate. There are 29 report types total.

2

Fetch Data

Frontend calls GET /partner/brand/:id/report/:reportType?fromDate=&toDate=. Backend queries the DB with date filters and returns typed arrays — MasterReportUser[], MarketingReportItem[], CompletedNoRepaymentReportItem[], or BaseReportItem[] for other types.

3

Display & Export

Data renders in a table. Staff can export as CSV via GET /report/:reportType/csv or download via GET /report/:reportType/download. Both return a stream — browser triggers file download. The master report also supports POST /master-report/email for email delivery of large datasets.

29 Report Types Date-range filtered CSV + download export Admin / Super Admin only Streaming response for large datasets