10 - Database & Sync Tables
PostgreSQL schema with 75 tables managed via EF Core. Plus 22 reference tables that must be synced from the existing MOSL data lake / legacy DB.
Database Setup
| Engine | PostgreSQL 14+ |
|---|---|
| Database name | ekyc3 |
| Schema | ekyc (default for all tables) |
| ORM | EF Core 8 with Npgsql provider |
| Naming | Snake_case via EFCore.NamingConventions (automatic) |
| Connection string | Host=127.0.0.1;Port=5432;Database=ekyc3;Username=postgres;Password=root123;Search Path=ekyc |
| Migrations | None - schema is code-first via EntityTypeConfigurations in OnModelCreating |
The project currently has no Migrations/ folder. Schema setup is manual or via DbContext.Database.EnsureCreatedAsync(). For production, generate migrations with dotnet ef migrations add InitialCreate.
Table Categories (75 tables total)
| Category | Count | Tables |
|---|---|---|
| Lead & Session | 3 | leads, lead_sessions, lead_state_transitions |
| Consent & Fraud | 3 | consents, fraud_checks, negative_list_entries |
| OTP & Email | 2 | otp_verifications, email_verifications |
| PAN & KRA | 3 | pan_verifications, kra_records, csafe_checks |
| Aadhaar | 1 | aadhaar_verifications |
| Bank | 3 | bank_accounts, bank_verification_attempts, bank_auto_verifies (Decentro) |
| Biometrics & Docs | 3 | liveness_verifications, signature_verifications, document_uploads |
| Personal & Nominee | 5 | personal_details, nominees, nominee_witnesses, fatca_declarations, guardians |
| Final Validation | 1 | final_validations |
| AOF & eSign | 3 | aof_documents, esign_transactions, document_path_infos |
| Account & Payment | 2 | account_activations, fund_transfers |
| CS Journey | 1 | cs_journey_holds |
| Verifier & Objection | 2 | verifier_reviews, objection_corrections |
| Journey Tracking | 5 | journey_stage_events, journey_activity_logs, stage_dropoff_configs, analytics_snapshots, journey_configurations |
| Downstream & Notifications | 2 | downstream_events, notifications |
| SEBI | 1 | sebi_submissions |
| Audit & Admin | 7 | api_audit_log, provider_configurations, provider_health_metrics, mock_response_templates, mock_scenarios, admin_users, feature_flags |
| Lookups & Config | 3 | lookups, application_config, handoff_links |
| Reference Masters | 22 | See "Sync Tables" section below |
| Account Aggregator & Income | 2 | account_aggregator_requests, income_proof_records |
Key Tables - Detailed
leads
The root entity. Every journey starts with a row here.
| Column | Type | Notes |
|---|---|---|
| lead_id | uuid PK | Generated at arrival |
| mobile | varchar(15) | Plain for SMS sending |
| mobile_hash | varchar(255) | BCrypt hash for dedup lookup |
| full_name | varchar(255) | |
| current_stage | smallint | 0-15, matches StageDefinitions |
| current_state | varchar(50) | INITIATED, OTP_VERIFIED, BANK_VERIFIED, etc. |
| is_completed | boolean | Final activation flag |
| client_id | varchar(20) | Assigned at Stage 14 (CBOS) |
| consent_terms, consent_bank_autoverify, consent_aa | boolean | Captured at registration |
| created_at, updated_at | timestamptz | updated_at set automatically in SaveChanges override |
provider_configurations
Runtime provider chain config. Read by ProviderChainExecutor on every call.
| Column | Notes |
|---|---|
| id (PK), provider_name, category | e.g. ("HypervergePan", "PAN") |
| enabled | boolean - include in chain at all |
| priority | smallint - lower = tried first |
| timeout_ms | Per-provider HTTP timeout |
| mock_mode | When true, executor returns default without calling provider |
| mock_latency_ms | Artificial delay in mock mode |
| circuit_breaker_threshold, circuit_breaker_cooldown_seconds | Failure handling |
api_audit_log
Every external provider call is logged here with full request/response for audit and debugging.
| Column | Notes |
|---|---|
| id, lead_id, correlation_id | Trace across related calls |
| provider, api_name, method | e.g. ("Decentro", "MobileToAccount", "POST") |
| request_url, request_headers, request_body | JSON or text |
| response_status_code, response_body | |
| duration_ms | End-to-end timing |
| is_success, is_mock, error_message | |
| created_at |
journey_activity_logs
Human-readable activity log per lead. Powered by async channel + ActivityLogWriterService hosted service for batched writes.
bank_auto_verifies
Results of Decentro mobile-to-bank auto-verify. Triggered at Stage 2 (OTP verified). Contains encrypted account number, IFSC, beneficiary name, account type. BankVerificationService.GetBankDetailsAsync() auto-promotes successful active savings records to a verified bank_accounts row.
Sync Tables (From Data Lake / Legacy DB)
Several reference tables are not populated by the new eKYC backend itself. They are expected to be synced from the existing MOSL data lake, back-office systems, or external regulators (SEBI, RBI). Without these tables populated, parts of the journey will fail.
The authoritative list and sync strategy is documented in the BRD Analysis folder:
- Sync Tables Master List - the full 22-table list with source system, sync frequency, owner, and status
- DB Actions Checklist - all DB setup tasks required for go-live
- PostgreSQL Compatibility Audit - Oracle/SQL Server → PostgreSQL porting notes
Sync Strategy Summary
| Sync Type | Count | Source | Tables |
|---|---|---|---|
| Daily sync | 5 | MOSL back-office | client_master, branch_master, subbroker_master, employee_pan_master, franchise_pan_whitelist |
| External / regulatory | 2 | SEBI, RBI | negative_list_entries (SEBI), bank_ifsc_masters (RBI) |
| One-time / manual populate | 15 | BRD docs, config files, old DB | state_masters, city_masters, pincode_masters, nsdl_error_masters, cvl_status_mappings, allowed_email_domains, restricted_email_domains, restricted_mobiles, suspicious_contacts, location_exception_whitelist, duplicate_bypass_whitelist, proof_upload_configs, referral_codes, lookups, application_config |
Why sync tables matter
- Dedup & fraud checks:
suspicious_contacts,negative_list_entries,duplicate_bypass_whitelistneed to be populated or dedup checks will miss bad actors - Client code resolution:
client_masterandbranch_masterdrive Stage 14 account creation; stale data causes CBOS failures - PAN whitelists:
employee_pan_master,franchise_pan_whitelistbypass certain checks for internal users - IFSC lookup:
bank_ifsc_masterspowers auto-fill of bank and branch name at Stage 6 - Pincode / state / city: used in address validation and manual entry forms
- KRA status codes:
nsdl_error_masters,cvl_status_mappingsdecode provider response codes into user-friendly messages
For the detailed list of each table - its columns, source system, sync job details, and expected row count - open the Sync Tables Master List.
EF Core DbContext
backend/src/MO.Ekyc.Infrastructure/Persistence/EkycDbContext.csC#excerpt
public class EkycDbContext : DbContext
{
public DbSet<Lead> Leads => Set<Lead>();
public DbSet<LeadSession> LeadSessions => Set<LeadSession>();
public DbSet<OtpVerification> OtpVerifications => Set<OtpVerification>();
public DbSet<PanVerification> PanVerifications => Set<PanVerification>();
public DbSet<BankAccount> BankAccounts => Set<BankAccount>();
public DbSet<BankAutoVerify> BankAutoVerifies => Set<BankAutoVerify>();
public DbSet<ProviderConfiguration> ProviderConfigurations => Set<ProviderConfiguration>();
public DbSet<ApiAuditLog> ApiAuditLogs => Set<ApiAuditLog>();
// ... 75 DbSets total
protected override void OnModelCreating(ModelBuilder mb)
{
mb.HasDefaultSchema("ekyc");
mb.ApplyConfigurationsFromAssembly(typeof(EkycDbContext).Assembly);
}
public override async Task<int> SaveChangesAsync(CancellationToken ct = default)
{
// Auto-update Lead.UpdatedAt on any modification
foreach (var entry in ChangeTracker.Entries<Lead>())
if (entry.State == EntityState.Modified)
entry.Entity.UpdatedAt = DateTimeOffset.UtcNow;
return await base.SaveChangesAsync(ct);
}
}
Useful DB Queries
SQLDaily onboarding funnel
SELECT current_stage, COUNT(*) AS count
FROM ekyc.leads
WHERE created_at::date = CURRENT_DATE
GROUP BY current_stage
ORDER BY current_stage;
SQLLead state transition history
SELECT from_state, to_state, trigger_action, transitioned_at
FROM ekyc.lead_state_transitions
WHERE lead_id = '8f2a1c9e-...'
ORDER BY transitioned_at;
SQLProvider health metrics
SELECT provider_name, success_count, failure_count,
avg_duration_ms, last_failure_at
FROM ekyc.provider_health_metrics
ORDER BY success_count DESC;
SQLRecent provider calls (audit)
SELECT provider, api_name, response_status_code, duration_ms, is_success, is_mock, created_at
FROM ekyc.api_audit_log
WHERE lead_id = '8f2a1c9e-...'
ORDER BY created_at DESC;