13 - FAQ & Glossary
Common questions + glossary of domain terms used throughout the eKYC flow.
Frequently Asked Questions
FAQWhy not BLoC / Riverpod / Provider?
eKYC is a one-way linear journey. Each stage screen owns its local state (_isLoading, _verifiedBank, form controllers). There's no need to share reactive state across 5 screens at once. Vanilla setState is sufficient and reduces file count.
Cross-stage state (leadId, token, sessionId) lives in the StorageService singleton - that's the only "global" state the app has.
See 04 - Architecture and 12 - Code Notes.
FAQWhy is mock mode backend-driven?
Putting a mock flag on the client is insecure (tamperable) and causes client/server drift. The backend's GlobalMockEnabled setting is the single source of truth. When enabled, the backend returns fake redirect URLs; the client detects these and skips external launches - but only in dev builds, guarded by ApiConfig.isDev (a compile-time constant).
See 02 - Mock Mode.
FAQWhere's the Razorpay API key?
The backend returns it in the paymentDefaults response at Stage 15. The mobile app uses this key with the Razorpay SDK. The web app ignores the key and uses the redirect URL flow instead. rzp_test_placeholder is the test key used in dev.
See flutter_app/lib/screens/stage15_congrats.dart for the dual-path code.
FAQWhy is Stage 10 just a redirect to Stage 9?
Income Proof used to be a separate screen. The latest BRD merged it into Stage 9 (Personal Details) under the F&O activation section. Stage 10 exists as a thin auto-navigate for backwards compatibility with the stage numbering.
FAQWhere does Annual Income Range get collected?
Stage 9 Personal Details screen, inside the "Personal Details" accordion (top section). Per the latest BRD, it was previously on Stage 6 Bank but is now on Stage 9.
FAQHow does Decentro bank auto-verify work?
Decentro's mobile-to-bank API is triggered at Stage 2 (after OTP verification) for first-time leads. If Decentro returns an active savings account, the backend stores it in the bank_auto_verifies table. When the user reaches Stage 6, GetBankDetailsAsync checks this table and auto-promotes the data to a verified BankAccount. The user lands directly on the Bank Verified screen with the pre-filled details. Clicking "Change bank" takes them to manual entry.
If Decentro returned a non-active-savings account or failed, the user goes through the normal UPI/manual flow.
See backend: backend/src/MO.Ekyc.Infrastructure/Services/Common/BankAutoVerifyService.cs
FAQWhat's the difference between STP and Non-STP?
STP (Straight-Through Processing): The account is created immediately at Stage 14. The user sees their Client ID and DP ID on Stage 15.
Non-STP: The application requires manual verifier review. The user sees a "Thank You - application submitted" message on Stage 15 and will receive updates via SMS/email.
Determined by backend compliance checks at Stage 11 (Final Validation). The decision is based on name match scores, C-SAFE results, PAN/Aadhaar match, and risk scoring.
FAQCan I skip stages during testing?
Sort of. The app resumes from where it left off - if your lead is at Stage 6 and you restart, you'll land on Stage 6. But you can't jump forward past stages you haven't completed. The backend enforces stage progression via RequiresStage filters on controllers.
For dev convenience: manually update the lead's current_state in the leads table to whatever stage you want, then restart the Flutter app.
FAQHow do I reset my test journey?
Three options:
- Clear browser localStorage (web): Chrome DevTools → Application → Storage → Clear site data
- Clear in-app: call
await (await StorageService.getInstance()).clearAll();then restart - Nuclear option: WarRoom dashboard → "Reset All Journeys" button (requires password)
FAQHow does KRA customer detection work?
At Stage 2 (OTP verified), the backend fires a background KRA lookup (CVL KRA + NDML KRA). If the PAN is already KRA-validated, the Stage 5 (DigiLocker) check returns isKraCustomer: true and the Flutter app skips Stage 5 entirely, jumping straight to Stage 6.
See stage5_digilocker.dart - the _loadAadhaarDetails method handles the skip.
FAQWhy are some files >1000 lines?
api_service.dart is ~1100 lines because it aggregates all ~60 backend endpoints. Splitting would fragment the network layer across 13+ files. Stage 9 (stage9_personal.dart) is ~1000 lines because it has 4 accordion sections + nominees + income proof. This is deliberate - all related UI and logic in one place.
If you find a specific section annoying, use your editor's "Fold All" feature (VS Code: Ctrl+K Ctrl+0) to collapse everything and navigate by method name.
Glossary
| Term | Meaning |
|---|---|
| eKYC | Electronic Know Your Customer - digital identity verification for account opening |
| Stage | One step in the 16-stage journey (Arrival → Registration → OTP → ... → Congrats) |
| Lead | A single user's journey instance. Identified by leadId (Guid). Stored in the leads DB table. |
| Session | A time-bounded interaction. Identified by sessionId. 15-minute inactivity timeout. |
| OTP | One-Time Password. 4-digit code sent via SMS or email. Fixed at 1234 in mock mode. |
| PAN | Permanent Account Number. 10-character Indian tax ID (5 letters + 4 digits + 1 letter). |
| Aadhaar | 12-digit Indian national ID. Verified via DigiLocker at Stage 5. |
| KRA | KYC Registration Agency (CVL KRA, NDML KRA). If user is already KRA-validated, Stage 5 is skipped. |
| DigiLocker | Indian government digital document wallet. Used to fetch verified Aadhaar at Stage 5. |
| NSDL | National Securities Depository Limited. Used for PAN verification at Stage 4. |
| CVL / NDML | Two KRA providers. Backend queries both at Stage 2 background check. |
| Decentro | Fintech aggregator. Used for mobile-to-bank auto-verify at Stage 2 (background). |
| HyperVerge | Liveness + face match provider. Used at Stage 7 for selfie + liveness detection. Also provides Reverse Penny Drop for Stage 6. |
| RPD | Reverse Penny Drop. UPI-based bank verification where the user authorizes a ₹1 reverse debit. Used at Stage 6. |
| IFSC | Indian bank routing code (11 chars). Format: [A-Z]{4}0[A-Z0-9]{6}. |
| eSign | Electronic signature of the AOF document. Providers: eMudhra, HyperVerge. Used at Stage 13. |
| AOF | Account Opening Form. PDF generated at Stage 12, eSigned at Stage 13. |
| STP | Straight-Through Processing. Account created instantly at Stage 14 without manual review. |
| Non-STP | Manual verifier review required. User sees "Thank You" at Stage 15 instead of instant credentials. |
| CBOS | Backend system that creates the actual Demat account at Stage 14. |
| Client ID | Unique identifier for a created Demat account. Shown on Stage 15 for STP users. |
| DP ID | Depository Participant ID. Combined with Client ID to form the full account number. |
| UCIC / UCID | Unique Customer Identification Code. Backend-assigned ID across Motilal Oswal products. |
| F&O | Futures & Options trading segment. Optional opt-in at Stage 9. |
| DDPI | Demat Debit and Pledge Instruction. Permission for broker to pledge/debit shares. |
| DIS | Delivery Instruction Slip. Physical form used to transfer shares. |
| C-SAFE | Internal MOSL compliance check system. Queried at Stage 11 Final Validation. |
| Zintlr | Background check provider (Stage 2 async). Fraud / reputation lookup by mobile number. |
| OneMoney | Account Aggregator partner. Used at Stage 9 for fetching income proof from linked banks. |
| Razorpay | Payment gateway. Used at Stage 15 for initial fund transfer into the Demat account. |
| Lottie | JSON-based animation format. Used throughout for loading, success, congrats animations. |
| SharedPreferences | Flutter's key-value storage API. Wraps NSUserDefaults (iOS), Android SharedPreferences, and localStorage (web). |
| --dart-define | Flutter build-time flag. Used to inject ENV=dev|uat|prod as compile-time constants. |
| setState | Flutter's built-in state update method. Schedules a rebuild of the widget. |
| Scaffold | Flutter Material layout widget providing AppBar, body, bottomNavigation slots. |
| WebView | Embedded web browser widget. Used for DigiLocker (Stage 5) and eSign (Stage 13). |
Where to Find Things
| I need... | Look in |
|---|---|
| Base URL for an environment | lib/config/api_config.dart |
| A specific API method | lib/services/api_service.dart (Ctrl+F the method name) |
| Stage 6 bank UI | lib/screens/stage6_bank.dart |
| Session timeout value | lib/config/api_config.dart - sessionTimeout |
| Brand colors | lib/config/theme.dart - AppTheme.primary etc. |
| An asset path | lib/config/assets.dart - AppAssets.xxx |
| A widget like LoadingOverlay | lib/widgets/ |
| A JSON model | lib/models/ |
| Mock mode settings (backend) | backend/src/MO.Ekyc.Api/appsettings.Development.json |
| Backend controller for an endpoint | backend/src/MO.Ekyc.Api/Controllers/StageN/*.cs |
| Backend business logic | backend/src/MO.Ekyc.Infrastructure/Services/StageN/*.cs |
| Old vs new UI comparison | ui_old_and_new.html |
| Architecture diagrams | frontend_architecture.html |
- Backend docs (pending) - placeholder