About Backend
The engine that powers the entire loan origination system
🏗️ Architecture Pattern
Modular monolith using NestJS's module system. Each domain (loans, payments, KYC) is a self-contained module with its own controller, service, and DTOs. Modules import each other as needed. Two PM2 processes: the main API server and a dedicated cron worker.
🌐 API Design
RESTful API versioned at /api/v1/. Three main namespaces: /web/ for customer-facing endpoints, /partner/brand/:brandId/ for internal staff, and /admin/ for super admins. All secured with JWT guards.
🔄 Multi-Brand Support
Every partner API call includes a brandId in the URL. The backend uses this to filter data, apply brand-specific rules (loan amounts, interest rates, evaluation criteria), and dispatch brand-specific communications.
⚡ Async Processing
Heavy operations (reminder dispatch, audit logging, PDF generation, NOC emails) are offloaded to message queues (RabbitMQ/AWS SQS) and processed by background workers asynchronously — keeping API responses fast.
Tech Stack
Every technology, library and tool in the backend
🏗️ Core Framework
NestJS provides the module system, DI container, lifecycle hooks, and decorators. TypeScript enforces strong typing across all 171+ services and 170+ DTOs.
🗄️ Database & ORM
Prisma as the type-safe ORM with schema-first approach. All models defined in schema.prisma. Custom GIN/TRGM indexes for full-text search. Migrations managed via Prisma CLI.
🔐 Authentication
JWT for stateless authentication with access + refresh token pattern. bcrypt for password hashing with 12 salt rounds. Passport strategies for both web (OTP) and partner (password) auth.
⚡ Caching
Redis for response caching of expensive DB queries. Custom @CacheResponse(ttl) decorator on controller methods. Cache invalidated on data mutations.
📬 Message Queues
RabbitMQ for internal job queues (reminders, notifications). AWS SQS for audit logs and NOC (No-Objection Certificate) email queues. Workers process jobs asynchronously.
📅 Task Scheduling
Trigger.dev for managed background jobs with retries, monitoring, and scheduling. NestJS Schedule for simple recurring cron jobs (daily reports, reminder dispatch).
📄 PDF Generation
PDFKit for programmatic PDF creation. Playwright/Puppeteer for HTML-to-PDF rendering (loan agreements, NDC certificates, repayment schedules).
🌐 HTTP & Validation
Axios for outgoing HTTP requests to 25+ external APIs. class-validator for DTO validation on every request. Helmet for security headers. Compression middleware for gzip responses.
NestJS Module System
How modules are organized and interact
AppModule at the root imports all feature modules. Modules declare providers they export so other modules can inject them.
📦 Module Anatomy
Each NestJS module has:
Example: LoansModule → LoansController handles HTTP routes, LoansService handles business logic, CreateLoanDto validates incoming data, PrismaService accesses the database.
🔗 Dependency Injection
NestJS's DI container manages service instantiation. A service can inject any other service by declaring it in the constructor:
Authentication & Guards
How the backend protects every endpoint
👤 Web Auth (Customers)
👔 Partner Auth (Staff)
🛡️ Guards
AuthGuard: Validates JWT token. Rejects with 401 if missing or expired. Attaches decoded user to request.user.
RolePermissionGuard: Reads @RequireRoleOrPermission() decorator on the route. Checks if the authenticated user's roles/permissions match. Rejects with 403 if not.
🏷️ Key Decorators
@GetPartnerUser() is a parameter decorator that extracts the authenticated partner user from the request, making it available directly in the controller method.
Database Schema (Prisma)
Core models and their relationships
prisma/schema.prisma. PostgreSQL is the database. Prisma generates fully-typed client code. Custom GIN TRGM indexes are added for full-text search on name/phone/PAN fields.
User
PartnerUser
Loan
PaymentCollectionTransaction
Brand
Document
RepaymentTimeline
PartnerUserActivitySession
BrandConfig (feature flags per brand)
UserDetails
UserBankAccount
LoanAgreement
LoanComment
CAMCalculator
AAConsentRequest
LeadForm
UserReminder
BrandProvider
BrandCard
Notification
Web (Customer) API Endpoints
All endpoints under /api/v1/web/
| Method | Endpoint | Purpose |
|---|---|---|
| POST | /web/auth/register | Register new customer, send OTP |
| POST | /web/auth/login | Login with phone (OTP flow) |
| POST | /web/auth/verify-otp | Verify OTP, receive JWT |
| POST | /web/auth/resend-otp | Resend OTP |
| POST | /web/auth/refresh-token | Refresh JWT token |
| POST | /web/auth/logout | Invalidate tokens |
| POST | /web/kyc/verify-pan | Verify PAN via Digitap |
| POST | /web/kyc/initiate-aadhaar-otp | Start Aadhaar verification |
| POST | /web/kyc/submit-aadhaar-otp | Complete Aadhaar verification |
| POST | /web/kyc/verify-mobile | Mobile OTP verification |
| GET | /web/kyc/documents | List uploaded documents |
| POST | /web/kyc/upload-document | Upload KYC document to S3 |
| POST | /web/personal-details/update | Update personal info |
| GET | /web/personal-details | Get personal details |
| POST | /web/employment/add | Add employment record |
| POST | /web/employment/verify-uan | Verify UAN via EPFO |
| POST | /web/bank/add-account | Add bank account |
| POST | /web/bank/verify | Penny drop verification |
| POST | /web/bank/upload-statement | Upload bank statement |
| GET | /web/loans | Get customer's loans |
| GET | /web/loans/:loanId | Get specific loan details |
Partner API Endpoints
All endpoints under /api/v1/partner/brand/:brandId/
📋 Loans
| Method | Endpoint (relative) |
|---|---|
| GET | /loans |
| GET | /loans/:loanId |
| POST | /loans/:loanId/status |
| POST | /loans/:loanId/update-with-reasons |
| POST | /loans/:loanId/force-bypass-reports |
| POST | /loans/:loanId/generate-ndc |
| GET | /loans/disbursed-amount |
| GET | /loans/unallocated |
💼 Collections
| Method | Endpoint (relative) |
|---|---|
| GET | /collection |
| GET | /collection/pre |
| GET | /collection/post |
| POST | /collection/:loanId/repayment-timeline |
| POST | /collection/:loanId/settlement |
| POST | /collection/:loanId/writeoff |
| POST | /collection/allocate |
👥 Customers
| Method | Endpoint (relative) |
|---|---|
| GET | /customers |
| GET | /customers/:userId |
| POST | /customers/:userId/allocate |
| POST | /customers/:userId/reloan |
| GET | /customers/unallocated |
| POST | /customers/:userId/status |
💳 Payments
| Method | Endpoint (relative) |
|---|---|
| GET | /payment |
| POST | /payment/process |
| POST | /payment/autopay |
| GET | /payment/approval |
| POST | /payment/approve/:id |
| POST | /payment/reject/:id |
📊 Dashboard
| Method | Endpoint (relative) |
|---|---|
| GET | /dashboard/stats |
| GET | /dashboard/summary |
| GET | /dashboard/users-by-subdomain |
| GET | /dashboard/collection-analysis |
| GET | /dashboard/disbursement-analysis |
| GET | /dashboard/partner-user-leads-stats |
👔 Partner Users
| Method | Endpoint (relative) |
|---|---|
| GET | /user |
| POST | /user/create |
| PUT | /user/:userId/update |
| DELETE | /user/:userId |
| POST | /user/:userId/allocate-loans |
| POST | /user/generate-secure-code |
| GET | /user/audit-logs |
⚙️ Settings
| Method | Endpoint (relative) |
|---|---|
| GET | /settings/brand |
| PUT | /settings/brand |
| GET | /settings/evaluation-items |
| PUT | /settings/evaluation-items |
| GET | /settings/loan-rules |
| POST | /settings/loan-rules |
| GET | /settings/targets |
| GET | /settings/appearance |
📊 Reports & Search
| Method | Endpoint (relative) |
|---|---|
| GET | /report/:reportType |
| GET | /report/:reportType/csv |
| GET | /report/:reportType/download |
| GET | /reports/login-logs |
| POST | /global-search |
| GET | /completed |
| GET | /completed/settled |
| GET | /completed/writeoff |
Admin API Endpoints
Super admin only — /api/v1/admin/
| Method | Endpoint | Purpose |
|---|---|---|
| GET | /admin/users | List all partner users across all brands |
| POST | /admin/users/create | Create partner user (any brand) |
| PUT | /admin/users/:userId | Update any partner user |
| GET | /admin/settings | Platform-wide settings |
| PUT | /admin/settings/brand/:brandId | Configure any brand |
| POST | /admin/brands | Create new lending brand |
Loans Service (Core)
The central business logic of the platform
🔄 Loan Lifecycle States
⚡ Auto-Allocation
When a new loan application comes in, the autoAllocation service automatically assigns it to an available loan executive based on:
📧 Email Reminder System
The loan.email.reminder.service and email.reminder.config.service handle automated email reminders for:
♻️ Reloan Automation
The reloan.automation.service identifies customers eligible for a new loan (completed previous loan, good repayment history). It automatically creates a pre-populated loan application and notifies the customer.
Payment Service
Multi-gateway payment orchestration
payment.service acts as an abstraction layer over 5 payment gateways. It decides which gateway to use based on brand config and payment type, handles gateway-specific request formatting, processes webhook callbacks, and updates the loan/transaction records atomically.
Razorpay
Card, UPI, netbanking, wallet. Primary collection gateway. Handles subscriptions for autopay.
CollectionCashfree
Alternate collection gateway. Used as fallback or for specific brands.
CollectionPaytring
Additional payment option gateway for certain brands.
CollectionIDFC Bank
Bank transfer disbursement. Used to send loan amount directly to customer's account.
DisbursementICICI Bank
Alternative bank transfer disbursement gateway.
DisbursementRazorpay Autopay
Recurring mandate creation. Monthly automatic collection from customer accounts.
AutopayEvaluation & Business Rules Engine
Automated loan decisioning
📊 Evaluation Engine
When a loan application is submitted, the evaluation engine scores the application against configured criteria:
Each criterion has a configured weight. The total score determines if the loan auto-approves, auto-rejects, or goes to manual review. V2 adds more sophisticated ML-inspired scoring.
⚡ Business Rules Engine (BRE)
The BRE runs against third-party credit reports (CIR Pro V2, Equifax) and applies brand-configured hard rules:
If any hard rule fails, the loan is auto-rejected. If all pass, it proceeds to the evaluation engine. Admins can configure thresholds per brand.
Communication Service
Multi-channel messaging with provider failover
📱 SMS Providers
Used for OTP delivery, payment reminders, disbursement alerts, and collection follow-ups.
📧 Email Providers
Used for loan agreements, payment receipts, reminder emails, and NOC (No-Objection Certificate) delivery.
💬 WhatsApp Provider
Rich message templates for payment reminders, loan status updates, and document collection requests via WhatsApp Business API.
Queue System & Background Workers
Async job processing pipeline
🐇 RabbitMQ Jobs
Internal message broker for high-frequency, low-latency jobs:
Producer: API server publishes jobs. Consumer: reminder-worker process dequeues and sends messages. Failed jobs are retried with exponential backoff.
☁️ AWS SQS Queues
AWS-managed queues for critical, durable jobs:
SQS provides durability guarantees and dead-letter queues. audit-logs-worker processes audit events. NOC emails sent after loan closure.
⏰ Cron Jobs
The dedicated cron worker PM2 process runs scheduled tasks:
🎯 Trigger.dev Jobs
Managed background jobs with built-in retry, monitoring, and scheduling:
Redis Caching Layer
Performance optimization via response caching
Redis is used to cache expensive database queries. The custom @CacheResponse(ttl) decorator is applied to controller endpoints. The cache key is derived from the endpoint path + query parameters + brandId. Cache is invalidated when underlying data changes.
Cached Endpoints
Cache Invalidation
AWS Services
Cloud infrastructure used by the backend
S3 — Public Bucket
Brand logos, public documents, blog images. Publicly accessible via CDN URLs.
S3 — Private Bucket
KYC documents (PAN, Aadhaar, selfies), bank statements, payslips. Accessed via time-limited presigned URLs only.
SQS — Audit Queue
All API actions are logged as events to this queue. Processed by the audit-logs worker for compliance.
SQS — NOC Queue
No-Objection Certificate dispatch queue. Ensures NDC emails are reliably sent after loan closure.
External API Integrations
All 25+ third-party services integrated
Digitap
Aadhaar OTP-based verification, PAN card verification, mobile-to-PAN lookup, pan-details-plus.
KYCEquifax
Credit bureau report pull. Provides credit score, payment history, inquiry history, account details.
Credit BureauCIBIL
India's primary credit information company. Credit score and full report for loan decisioning.
Credit BureauCIR Pro V2
Advanced credit assessment with bureau data. Powers the Business Rules Engine decisions.
BRECART
Bank statement analysis. Analyzes PDF bank statements to extract cash flows, salary credits, EMI debits.
BSAFinbox
Financial analysis from bank data. Alternative bank statement analysis provider.
BSAScoreMe
Credit scoring and BDA (Business Data Analytics) reports. Advanced financial scoring.
Credit ScoreAccount Aggregator
RBI-mandated AA framework. Consent-based bank data sharing directly from banks.
Bank DataPenny Drop
Re-verify bank account by sending ₹1 and checking recipient name match before disbursement.
Bank VerifySignzy V3
Digital e-signature for loan agreements. Sends agreement PDF, customer signs, webhook confirms.
eSignSignDesk
Alternative e-signature provider. Same workflow as Signzy with different API.
eSignDigiLocker 2.0
Government document verification platform. Fetch official Aadhaar, PAN, driving license from DigiLocker.
DocsEPFO / UAN
Phone-to-UAN lookup and UAN-to-employment history from EPFO provident fund records.
EmploymentAcefone
VoIP telephony API. Click-to-call, call recording, agent management for collection teams.
VoIPGoogle Maps / Geocoding
Convert user addresses to GPS coordinates. Verify address plausibility. Field visit routing.
LocationLendbox
Partner lender API. Loan creation, disbursement, repayment sync for co-lending arrangements.
Co-lendingMobile to Address
Verify physical address from mobile number for fraud prevention.
VerifyTrigger.dev
Background job scheduling platform with dashboard, retries, and observability.
JobsDeployment & Process Management
PM2 configuration and server setup
⚙️ PM2 Processes
los-backend-api
los-backend-cron-worker
🏗️ Server Configuration
Environment: .env.development and .env.production files. ConfigModule loads env vars and makes them injectable via ConfigService. BigInt serializer interceptor handles large number serialization to JSON.
Partner API — Additional Endpoint Groups
API groups not covered in the main partner API section
🏦 Account Aggregation (AA)
| Method | Endpoint |
|---|---|
| POST | /aa/consent-request |
| POST | /aa/consent-request/manual |
| GET | /aa/consent-request/:id |
| GET | /aa/user/:userId/consent-requests |
| GET | /aa/consent-request/:id/data-sessions |
| POST | /aa/consent-request/:id/status |
| POST | /aa/user/:userId/send-consent-email |
| POST | /aa/user/:userId/generate-consent-url |
| POST | /aa/fetch-periodic-data |
| POST | /aa/webhook (AA provider callbacks) |
⏰ User Reminders
| Method | Endpoint (relative to /partner/brand/:brandId/) |
|---|---|
| GET | /user-reminders |
| POST | /user-reminders |
| GET | /user-reminders/:id/audit-logs |
| GET | /user-reminders/dashboard-metrics/view |
| POST | /user-reminders/dashboard-metrics/refresh |
✅ Completed Loans
| Method | Endpoint (relative to /partner/brand/:brandId/) |
|---|---|
| GET | /completed (all terminal loans) |
| GET | /completed/closed |
| GET | /completed/settled |
| GET | /completed/writeoff |
📬 Lead Forms
| Method | Endpoint (relative to /partner/brand/:brandId/) |
|---|---|
| POST | /lead-forms/upload (multipart CSV) |
| GET | /lead-forms |
| GET | /lead-forms/stats |
| POST | /lead-forms/sync |
| DELETE | /lead-forms/bulk |
| GET | /lead-forms/:id |
| PATCH | /lead-forms/:id/status |
| GET | /lead-forms/export (CSV blob) |
🧮 CAM Calculator
| Method | Endpoint |
|---|---|
| POST | /loans/brand/:brandId/cam-calculator/save |
| GET | /loans/cam-calculator/:loanId |
| GET | /loans/user/:userId/brand/:brandId/cam-calculators |
| DELETE | /loans/cam-calculator/:loanId |
📞 Acefone Dialer
| Method | Endpoint |
|---|---|
| POST | /acefone/dialer/initiate |
| GET | /acefone/dialer/user/:userId/calls |
| GET | /acefone/dialer/partner/:partnerUserId/calls |
| GET | /acefone/dialer/call/:callId |
| PATCH | /acefone/dialer/call/:callId/end |
| GET | /acefone/dialer/user/:userId/stats |
| GET | /acefone/dialer/partner/:partnerUserId/stats |
📊 Reports (all types)
| Method | Endpoint (relative to /partner/brand/:brandId/) |
|---|---|
| GET | /report/master-report?fromDate&toDate |
| GET | /report/marketing-report?fromDate&toDate |
| GET | /report/completed-no-repayment-report?fromDate&toDate |
| GET | /report/:reportType/csv (CSV export) |
| GET | /report/:reportType/download |
⚙️ Settings Sub-Routes
| Method | Sub-path (under /settings/) |
|---|---|
| GET/PUT | /appearance |
| GET/POST/DELETE | /blocklist |
| GET/POST/PUT/DELETE | /brand-cards |
| GET/POST/PUT/DELETE | /brand-bank-accounts |
| GET/POST/PUT/DELETE | /brand-providers |
| GET/POST/DELETE | /non-repayment-dates |
| GET/POST/DELETE | /partner-unavailability-dates |
| GET/PUT | /brand-paths |
| GET/POST/PUT/DELETE | /blogs |
| GET/POST/PUT/DELETE | /brand-coupons |
| GET/POST/PUT/DELETE | /reloan-configs |
| GET/POST/PUT/DELETE | /brand-status-reasons |
| GET/POST/PUT/DELETE | /brand-rating-matrix |
| GET/POST/PUT/DELETE | /partner-user-rating-matrix |
Settings Module — 20 Sub-Modules
All setting sub-modules under app/partner/settings/
settings parent module at app/partner/settings/ is a large composite module with 20 sub-modules, each handling a distinct configuration domain for a brand. All routes require ADMIN permission and are brand-scoped.🎨 Appearance
Manages brand theme: primary/secondary colors, font family, logo URL, dark mode, rounded corners, full color token set (hover, active, focus, light, contrast variants). Injected as CSS variables by the frontend.
🚫 Blocklist
Manage PAN / Aadhaar / phone blocklist. Any loan application matching a blocked identifier auto-rejects at BRE stage. CRUD operations with reason logging.
🃏 Brand Cards
Card product configurations shown to customers. Each card has type, eligibility criteria, credit limit, and interest rates. BrandCard model — this model was completely missing from the database documentation.
🏦 Brand Bank Accounts
Brand's own bank accounts for disbursement and repayment. IFSC, account number, beneficiary name, account type. Multiple accounts supported per brand (e.g., IDFC for disbursement, Razorpay settlement for collection).
📝 Brand Blogs
Blog content management for the customer-facing web app. Title, body (markdown/HTML), featured image S3 key, published flag, and SEO metadata. Fetched by the customer web app to display educational content.
🎫 Brand Coupons
Discount coupons applied to loan processing fees or interest. Coupon code, discount type (flat/percent), discount value, max uses, expiry, and eligible product types.
📋 Brand Evaluation Items
Criteria used by the evaluation engine. Each item has: name, weight, threshold value, pass/fail logic, and whether it's a hard reject or soft flag. Supports both V1 and V2 evaluation engines.
📅 Brand Non-Repayment Dates
Public holidays and bank non-working days. When a due date falls on one of these days, the backend shifts the due date automatically. Affects NDC generation and overdue detection.
🔗 Brand Policy Links
T&C URL, privacy policy URL, FAQ URL. These are embedded in loan agreements and shown during customer onboarding. Brand-level overrides of the platform defaults.
🔌 Brand Provider
Third-party provider registry per brand. Type (SMS/EMAIL/WHATSAPP/ESIGN/BSA/CREDIT_BUREAU/AA/DIALER), provider name, isPrimary, isActive, isDisabled, and a JSON config blob with provider-specific API keys and settings. The communication service reads this to route to the correct provider.
🔄 Brand Reloan Configs
Rules for when a customer is eligible for a reloan: minimum days since last loan closure, minimum repayment rating, maximum active loans, and auto-create flag (auto-generate reloan application).
❌ Brand Status Reasons
Brand-customized rejection/status change reasons shown in the partner portal dropdowns. Each reason has a code, display label, and the loan statuses it applies to (REJECTED, WRITTEN_OFF, SETTLED, etc.).
⭐ Brand Rating Matrix
Brand-level customer scoring matrix. Criteria with weights and score ranges. Used to compute an overall customer rating that influences auto-allocation priority and reloan eligibility.
🏖️ Partner Unavailability Dates
Days when partner operations are paused (internal holidays, system maintenance). Auto-allocation, reminder scheduling, and cron-based tasks skip these dates.
⭐ Partner User Rating Matrix
Individual staff performance matrix. Tracks collection recovery rates, TAT, conversion ratios. Used for performance reviews and manager-level dashboards. Separate from the brand-level rating matrix.
📏 Loan Rules
Product configuration: min/max loan amount, tenure options, interest rate (flat/reducing), processing fee (flat/percent), risk category mapping. Multiple rules per brand for different product types.
🎯 Brand Targets
Monthly/quarterly targets at brand, team, and individual levels: disbursement amount targets, collection recovery targets, new customer targets. Used in dashboard performance widgets.
⚙️ General / Brand Config
Master brand configuration via UpdateBrandConfigDto: salary threshold, rejection duration, bank statement months, e-sign settings, section manager info, all version flags (dashboard/loan-ops/collection), CAM requirement, AA flag, field visit, auto-allocation type, age limits, central dedup, etc.
KYC & Document Service
Customer identity verification pipeline
onboardingStep enum. The brand's BrandConfig controls which steps are mandatory. Steps: PAN → Aadhaar → Mobile → Selfie → Bank Account (penny drop) → Employment → Bank Statement → Evaluation.🆔 PAN Verification
Customer enters PAN. Backend calls Digitap pan-details-plus API. Returns name, DOB, type (Individual/Company). PAN is stored and marked verified. If isAadhaarNumberRequired flag is set, the name from PAN must match Aadhaar name.
🏛️ Aadhaar Verification
OTP-based e-KYC via Digitap. Step 1: initiate-aadhaar-otp sends OTP to Aadhaar-linked mobile. Step 2: submit-aadhaar-otp validates OTP, returns masked Aadhaar details (name, address, DOB, photo). Address auto-filled from Aadhaar response.
📱 Mobile Verification
Separate OTP verification for the phone number used to register. Uses the mobile-verification module via EPFO / telecom APIs. Required for brands with isAlternateNumber enabled.
📋 Document Upload
All documents uploaded to S3 private bucket via pre-signed URLs. Document types: PAN_CARD, AADHAAR_FRONT, AADHAAR_BACK, SELFIE, SALARY_SLIP, BANK_STATEMENT, OTHER. Status: PENDING → VERIFIED / REJECTED. Partner can verify or reject with reason.
💰 Penny Drop
After customer adds bank account, a ₹1 transfer is initiated via Razorpay / external penny drop API. The beneficiary name returned is matched against the customer's name. If matched, account is marked isPennyDropVerified = true. Required before disbursement.
🏢 Employment Verification
Customer enters employer name, UAN, monthly salary. Backend calls EPFO via phoneToUan → uanToEmployment chain to fetch employment history, current employer, and salary credits. Employment is verified against EPFO records.
E-sign Service
Digital loan agreement signing via Signzy / SignDesk
features/esign/esign.controller.ts. The brand's primary e-sign provider is configured in BrandProvider. Agreement PDF is generated with brand header/footer, customer details, and loan terms, then sent to the e-sign provider's docket system.📄 Agreement Generation
When a loan is sanctioned, the backend generates the loan agreement PDF using Playwright/Puppeteer from an HTML template. The template uses brand-configured header/footer text from BrandConfig.loanAgreementHeader/Footer. The PDF is stored in S3 private bucket.
✍️ E-sign Initiation
The generated PDF is sent to Signzy V3 or SignDesk (based on brand's provider config). A docket is created with signatories (customer). The customer receives an SMS/email with the signing link. Docket ID stored in LoanAgreement.docketId.
🔔 Webhook Callback
When the customer signs (or the docket expires), the e-sign provider sends a webhook to /webhook/esign. The webhook handler: validates signature, updates LoanAgreement.status, stores the signed PDF S3 key, and triggers loan status transition to AGREEMENT_SIGNED. NOC email queued to SQS.
📋 E-sign Config
Per brand: esignDocketTitle, esignExpiryDayCount, esignFinalCopyRecipients (email list for final signed copy), esignNotificationEmailList (CC list). Configured in BrandConfig via General Settings.
Webhook Handler
Inbound callbacks from payment gateways and e-sign providers
core/webhooks/webhook.controller.ts. All webhook endpoints are public (no JWT required) but verify provider signatures via HMAC/secret. Each provider has its own signature validation logic.💳 Razorpay Webhook
Receives payment.captured, payment.failed, subscription.charged, subscription.cancelled events. On payment.captured: creates PaymentCollectionTransaction, updates loan outstanding, checks if fully repaid → triggers COMPLETED status. Signature verified via Razorpay webhook secret.
💰 Cashfree Webhook
Receives payment success/failure events from Cashfree gateway. Same post-processing as Razorpay: transaction creation, outstanding update, status check. Signature verified via Cashfree's HMAC-SHA256.
✍️ E-sign Webhook
Receives signing completion or expiry events from Signzy/SignDesk. On completion: downloads signed PDF, stores in S3, updates LoanAgreement.status = SIGNED, moves loan to AGREEMENT_SIGNED. On expiry: marks agreement as EXPIRED, alerts partner via notification.
🏦 AA Webhook (external/aa/aa.webhook.controller.ts)
Receives consent status updates from the AA provider (FINDUIT/CART). On consent approval: updates AAConsentRequest.consentStatus, triggers fetchPeriodicData to pull bank statement data. On revocation: marks consent as REVOKED.
Notification Service
In-app notifications for partner staff
features/notification/notification.controller.ts. Notifications are created server-side on business events and stored in the Notification table. Partner users poll the notification endpoint or receive real-time updates.📋 Notification Types
Notifications are created for: new loan application assigned, payment received on your loan, loan status changed, customer document uploaded, system alerts (partner user inactivity, version update). Each notification carries metadata JSON with deep-link data (loanId, userId) for frontend navigation.
🔔 API Endpoints
GET /notifications — fetch unread count + list for the authenticated partner user. PATCH /notifications/:id/read — mark single notification as read. PATCH /notifications/read-all — bulk mark all as read. DELETE /notifications/:id — dismiss. Supports pagination with ?page&limit.
Activity Tracking Service
Partner user session and activity monitoring
app/partner/activity-tracking/partner.activity-tracking.controller.ts. Tracks partner user activity to detect inactivity, measure engagement, and support compliance audits.📡 Activity Ping
Frontend's ActivityTrackerContext sends periodic pings (on mouse move, keypress, scroll). Backend receives these at the activity-tracking endpoint, updates PartnerUserActivitySession.lastActiveAt. If gap between pings exceeds threshold, the session is marked idle. Idle detection triggers alert to managers.
📋 Session Logging
Each login creates a new PartnerUserActivitySession record with loginAt. On logout, logoutAt is set. Admins can query session history to see when each staff member was active, total session durations, and idle periods. Used for compliance and productivity tracking.
ScoreMe BDA Service
Bureau Data Analysis for enhanced credit scoring
features/scoreMeBda/scoreMeBda.controller.ts. ScoreMe is a credit analytics provider that augments standard bureau data (CIBIL/Equifax) with additional behavioural scoring models.When triggered (manually by credit executive or automatically post-evaluation), the backend calls ScoreMe's BDA API with the customer's PAN and bureau data. ScoreMe returns an enhanced report including:
Results are stored against the customer and shown in the Credit Report tab of the customer detail page. The BDA report is accessible via the scoreMeBDA.ts frontend API service.
Lendbox Co-lending Feature
14 controllers for the Lendbox partner lender integration
features/Lendbox/controllers/. Lendbox is a co-lending marketplace. When a brand participates in Lendbox co-lending, certain loans are originated through Lendbox's platform. The integration has 14 dedicated controllers covering the full Lendbox loan lifecycle.📋 Lendbox Controllers
🔄 Lendbox Flow
1. Loan creation — send borrower data to Lendbox, receive Lendbox borrower ID. 2. Document upload — upload KYC docs to Lendbox system. 3. E-sign — Lendbox-managed e-sign flow. 4. Disbursal UTR — receive bank transfer reference from Lendbox. 5. Repayment — wallet orders and transaction status sync. 6. Foreclosure — compute foreclosure amount. 7. NOC — download no-objection certificate from Lendbox on loan closure. All callbacks come via lendbox-credit-order-callback.
API Key Management
External system access keys for the LOS platform
features/api-key/api-key.controller.ts. Allows brands to issue API keys for external systems (e.g., their own mobile apps, partner integrations) to call the LOS backend with brand-scoped access.Operations: Create (generates a secure random key, hashed before storage), List (shows key metadata — last 4 chars only, creation date, last used), Revoke (soft delete), Rotate (create new + revoke old in one transaction). API keys bypass JWT auth but are validated by a dedicated ApiKeyGuard that checks the X-API-Key header against the brand's active keys. Scoped to the brand they were created for.
Global Interceptors, Filters & Middleware
Cross-cutting concerns applied to every request
⚙️ Global Interceptors
BigIntSerializerInterceptor: PostgreSQL returns BigInt for certain count queries; JSON.stringify() throws on BigInt — this interceptor converts BigInt to String before serialization. CacheResponseInterceptor: Works with @CacheResponse(ttl) decorator to cache GET responses in Redis. LoggingInterceptor: Logs request method, URL, response time for every API call.
🚨 Global Exception Filter
A global NestJS exception filter catches all unhandled exceptions and normalizes them into a consistent error response shape: { statusCode, message, error, timestamp, path }. Prisma errors (P2002 unique violation, P2025 not found) are mapped to readable HTTP errors (409 Conflict, 404 Not Found). Validation errors from class-validator are returned as an array of field-level messages.
🛡️ Middleware
BrandValidationMiddleware: On every /partner/brand/:brandId/ request, validates that the brandId in the URL actually exists and is active. Returns 404 if not. This prevents partner users from guessing brandIds.
✅ Health Check
Endpoint: GET /health (controller: common/health/health.controller.ts). Returns a JSON health report: database connectivity (Prisma ping), Redis connectivity, and process uptime. Used by load balancers and monitoring tools (UptimeRobot, AWS ELB health checks) to determine if an instance is healthy before routing traffic to it.