v0.2 — Data model & knowledge corpus (ACCEPTED)¶
Status: accepted 2026-11-12. Architecture context: v1.0. Fictional company: Kosha Financial (Indian neobank, partner-bank model). All people are synthetic.
0. Ground rules for realism¶
| Rule | Why it matters |
|---|---|
Money is BIGINT paise, never float |
Float rounding is the #1 fintech bug interviewers probe |
All timestamps timestamptz in UTC; rendered IST |
NEFT/RTGS windows and RBI TATs are IST-based |
Full Aadhaar is never stored — only aadhaar_ref_token + last 4 |
UIDAI Aadhaar Data Vault rules |
PAN stored as KMS-encrypted token + last 4; full value only for kyc:pii scope |
DPDP Act 2023 data minimisation |
IDs are prefixed ULIDs (cus_01J…, txn_01J…) |
Sortable, non-guessable, self-describing in logs |
Every format passes real validators: PAN AAAPL1234C (4th char P, 5th = surname initial), IFSC XXXX0YYYYYY, UPI RRN 12 digits, NEFT UTR, GSTIN with checksum, Indian mobile [6-9]\d{9}, pincode ↔ state |
Recruiters who know fintech will spot fake-looking data instantly |
Generator is deterministic (--seed) |
Reproducible tests and demos |
1. Schemas (PostgreSQL 16 + pgvector)¶
Schemas: core (customers/accounts/payments), ledger (double-entry), kyc, risk, ops (disputes, outbox, audit, idempotency), kb (knowledge base).
core.customers¶
customer_id · cif_number (10-digit) · first_name · middle_name · last_name · date_of_birth · gender · email · mobile · mobile_verified · persona (salaried | student | gig_worker | sme_owner | nri | senior_citizen) · occupation · employer_name · annual_income_band · segment (mass | affluent | premium) · residential_status (resident | nri) · preferred_language · onboarding_channel (app | web | assisted | partner) · relationship_start_date · status (prospect | active | on_hold | dormant | frozen | under_investigation | deceased_claim_pending | closed) · risk_category (low | medium | high) · created_at · updated_at
core.addresses¶
address_id · customer_id · address_type (permanent | correspondence) · line1 · line2 · city · district · state · state_code · pincode · country · is_verified · valid_from · valid_to
core.accounts¶
account_id · customer_id · account_number · ifsc (KOSH0000001…) · product_code (SAVINGS_REGULAR | SAVINGS_SALARY | CURRENT | FD | RD) · status (see §1a) · status_reason · mode_of_operation (single | joint) · opened_at · closed_at · ledger_balance_paise · available_balance_paise · hold_amount_paise · minimum_balance_paise · interest_rate_bps · overdraft_limit_paise · nominee_registered · last_txn_at
core.cards¶
card_id · account_id · network (rupay | visa | mastercard) · card_type (debit | credit | prepaid) · pan_last4 · token_ref · status (see §1a) · expiry_month · expiry_year · atm_limit_paise · pos_limit_paise · ecom_limit_paise · contactless_enabled · international_enabled · issued_at
core.vpas (UPI handles)¶
vpa_id · customer_id · account_id · vpa (ravi.k@kosha) · is_primary · status · created_at
core.beneficiaries¶
beneficiary_id · customer_id · nickname · account_number_masked · ifsc · bank_name · added_at · cooling_period_ends_at (new-payee limit — real anti-fraud control) · status (see §1a)
core.merchants¶
merchant_id · display_name · legal_name · mcc (5411, 5812, 4121, 5732, 4900, 6011…) · category · sub_category · city · state · vpa · gstin · acquirer_bank · risk_level
core.transactions (range-partitioned by month on initiated_at)¶
txn_id · account_id · customer_id · direction (debit | credit) · amount_paise (CHECK > 0) · currency · rail (upi | imps | neft | rtgs | card_pos | card_ecom | atm | nach | internal) · txn_type (p2p | p2m | salary | emi | bill_pay | refund | reversal | cash_withdrawal | interest_credit | charges | fd_booking) · status (see §1a) · status_reason_code · failure_reason_code (NPCI-style U30, U69, XB…) · hold_reason · expected_credit_by · utr · rrn · npci_txn_id · counterparty_name · counterparty_vpa · counterparty_account_masked · counterparty_ifsc · merchant_id · mcc · channel (mobile_app | web | pos | atm | api) · device_id · ip_address (inet) · geo_city · geo_lat · geo_lng · narration (statement-style UPI/DR/412345678901/QUICKBASKET/qb@axis/Payment) · remarks · initiated_at · posted_at · value_date · balance_after_paise · risk_score (0–100) · is_flagged
Indexes: (account_id, initiated_at DESC), (customer_id, initiated_at DESC), (merchant_id), unique (utr), pg_trgm on narration.
core.transaction_status_history¶
history_id · txn_id · from_status · to_status · reason_code · actor (system | npci | ops_user | risk_engine) · occurred_at — every transaction's full lifecycle, so "why was this on hold for 3 days?" is answerable.
§1a — Status lifecycles (all enforced by a state-machine table + DB CHECK; illegal transitions rejected)¶
| Entity | Statuses |
|---|---|
| Transaction | initiated → authorised → processing → pending → success · credit_delayed (debited at remitter, beneficiary credit pending — the classic UPI "money gone, not received") · deemed_success (NPCI deemed-approved after beneficiary-bank timeout) · on_hold (risk/compliance hold) · under_review · pending_settlement · settled · failed · timed_out · declined (limits/insufficient funds/risk) · cancelled · expired (UPI collect request lapsed) · returned (NEFT/IMPS returned by beneficiary bank) · reversal_initiated → reversed · partially_reversed · refunded · chargeback_initiated |
| Account | pending_activation · active · kyc_pending · dormant · inoperative (RBI: no customer-induced txn for 2 years) · debit_freeze · credit_freeze · total_freeze · lien_marked · on_hold · pending_closure · closed |
| KYC profile | not_started · pending_documents · pending_vcip · in_review · on_hold · escalated · verified · rejected · re_kyc_due · re_kyc_overdue · expired |
| Card | inactive · active · temp_blocked (user-initiated) · pin_blocked · blocked · hotlisted (lost/stolen) · expired · replaced |
| Dispute | raised · acknowledged · awaiting_customer_info · under_investigation · on_hold · chargeback_raised · pre_arbitration · arbitration · resolved_customer_favour · resolved_merchant_favour · auto_reversed · withdrawn · closed |
| AML alert | open · assigned · in_review · pending_info · on_hold · escalated · closed_false_positive · closed_no_action · closed_str_filed |
| Transaction review | queued · in_review · on_hold · cleared · escalated_to_aml · blocked |
| Beneficiary | pending_cooling · active · disabled · deleted |
The generator produces realistic distributions (≈96% success, ≈1.5% failed/declined, small tails of credit_delayed, deemed_success, on_hold, returned, reversals) — and the long-tail statuses are exactly what disputes and support SOPs reference.
ledger.journal_entries / ledger.postings (double-entry)¶
entry_id · txn_id · posted_at · description
posting_id · entry_id · gl_account (customer account or internal GL: UPI_SETTLEMENT, NEFT_SETTLEMENT, FEE_INCOME, INTEREST_EXPENSE, SUSPENSE) · amount_paise (signed)
Invariant: Σ postings per entry = 0 (deferred constraint trigger). A nightly reconciliation test proves accounts.ledger_balance_paise = Σ postings.
kyc.kyc_profiles¶
kyc_id · customer_id · kyc_type (min_kyc | full_kyc | v_cip | ckyc_download) · kyc_status (see §1a) · ckyc_number (14-digit KIN) · pan_token · pan_last4 · pan_status (valid | invalid | not_aadhaar_linked) · pan_name_match_score · aadhaar_ref_token · aadhaar_last4 · ovd_type (passport | voter_id | driving_licence | aadhaar) · vcip_session_id · vcip_agent_id · liveness_score · face_match_score · vcip_geo_lat · vcip_geo_lng · pep_flag · sanctions_flag · fatca_crs_declared · risk_category · risk_rationale · verified_at · verified_by · next_review_due (high 2y / medium 8y / low 10y per RBI KYC Master Direction) · created_at
kyc.kyc_documents¶
document_id · kyc_id · customer_id · doc_type (pan_card | aadhaar_masked | passport | selfie | address_proof | signature) · s3_key · sha256 · status (accepted | rejected | expired) · rejection_reason · uploaded_at · expires_on
kyc.kyc_events¶
event_id · kyc_id · from_status · to_status · actor · reason · occurred_at (full state-machine history)
risk.aml_rules / risk.aml_alerts¶
Rules: rule_id · name · typology · params (jsonb thresholds) · severity · enabled
Alerts: alert_id · customer_id · rule_id · typology (structuring | rapid_movement | mule_account | round_tripping | dormant_reactivation | high_risk_geo | velocity) · score · status (see §1a) · assigned_to · sla_due_at · triggering_txn_ids (text[]) · narrative · disposition · str_reference · created_at · closed_at
Every alert is generated by actually running the rules over the generated transactions — the planted typologies are what fire them.
risk.screening_results¶
screening_id · customer_id · screened_name · list_source (UN_SC | OFAC_SDN | MHA_UAPA | INTERNAL_PEP — synthetic lists) · match_score · decision (clear | potential_match | true_match) · vendor_ref · screened_at
ops.disputes · ops.transaction_reviews¶
Disputes: dispute_id · txn_id · customer_id · reason_code (unauthorized | goods_not_received | duplicate | amount_mismatch | failed_but_debited | credit_not_received) · amount_paise · status (see §1a) · tat_due_at · compensation_paise (RBI TAT-harmonisation ₹100/day) · resolution · chargeback_ref · idempotency_key · created_by · created_at
Reviews: review_id · txn_id · reason · priority · status (see §1a) · idempotency_key · created_by · created_at
ops.outbox · ops.audit_log · ops.idempotency_keys¶
Outbox: event_id · aggregate_type · aggregate_id · event_type · payload (jsonb) · created_at · published_at
Audit (append-only; UPDATE/DELETE revoked): audit_id · actor_sub · client_id · roles · tool_name · args_hash · resource_ids · pii_unmasked · outcome · error_code · latency_ms · trace_id · occurred_at
Idempotency: key · scope · request_hash · status · response (jsonb) · expires_at — written in the same DB transaction as the business write → exactly-once effect.
kb.documents · kb.chunks¶
Documents: doc_id · doc_code (CMP-SOP-004) · department · title · doc_type (policy | sop | runbook | playbook | api_reference | guideline | faq | template) · version · status (draft | effective | superseded) · effective_date · review_due · owner_role · approver · classification (public | internal | confidential | restricted) · source_format (md | pdf | docx | html | openapi) · s3_uri · sha256 · supersedes_doc_id · regulatory_refs (text[]) · tags (text[])
Chunks: chunk_id · doc_id · chunk_index · section_path (4 › 4.2 Enhanced Due Diligence) · content · token_count · embedding (vector) · tsv (generated tsvector) · metadata (jsonb)
Indexes: HNSW on embedding, GIN on tsv. Postgres Row-Level Security on classification — a marketing user physically cannot retrieve a restricted compliance chunk.
2. Synthetic data volumes (proposed)¶
| Entity | Count |
|---|---|
| Customers | 5,000 (personas weighted to Indian neobank mix) |
| Accounts | ~7,500 |
| Cards / VPAs | ~6,000 / ~6,500 |
| Merchants | ~1,200 |
| Transactions | ~1.5M over 18 months (salary cycles, EMIs, festive spikes) |
| AML alerts | ~400 (from ~2% planted bad actors + false positives) |
| Disputes | ~600 |
3. Knowledge corpus — ~85 documents, 9 departments¶
Mixed formats on purpose (≈60 Markdown, 15 PDF, 6 DOCX, OpenAPI YAML + HTML API docs) so ingestion is real.
Deliberate RAG traps: superseded versions of the same SOP (retrieval must prefer effective), cross-references, fee/limit tables, escalation matrices, RACI tables, and one "vendor-supplied" doc containing a planted prompt-injection string for security tests.
| Dept | Code | Documents |
|---|---|---|
| Compliance | CMP | AML/CFT Policy · CDD & EDD SOP · Transaction Monitoring & Alert Handling SOP · STR/CTR Filing to FIU-IND SOP · Sanctions & PEP Screening SOP · Record Retention Policy (PMLA) · Regulatory Reporting Calendar · Payment Data Localisation Policy · Compliance Testing Charter · Whistleblower Policy |
| Onboarding / KYC | ONB | Digital Onboarding SOP · Video-KYC (V-CIP) Procedure · Min-KYC → Full-KYC Upgrade SOP · Periodic Re-KYC SOP · CKYC Upload/Download SOP · OVD Verification Checklist · NRI Onboarding SOP · Onboarding Rejection Handling · Minor Accounts SOP |
| Legal | LGL | Savings Account Terms & Conditions · Privacy Notice (DPDP Act 2023) · Data Processing Agreement template · Grievance Redressal Policy (RBI Integrated Ombudsman) · Law-Enforcement Request & Account Freeze SOP · Customer Consent Management Policy · Vendor Contract Standards · Digital Lending Guidelines Compliance Note |
| Risk & Fraud | RSK | Fraud Risk Management Policy · Disputes & Chargebacks SOP · Failed-Transaction TAT & Compensation SOP · Mule Account Detection Playbook · Account Takeover Response Runbook · Operational Risk Incident Reporting · CERT-In Cyber Incident Reporting (6-hour rule) · Risk Appetite Statement |
| Customer Support | CS | Support Tiering Playbook · Escalation Matrix · Response Macros Library · Card Block/Unblock SOP · Complaint Categorisation Guide · Deceased Claim Settlement SOP · Frozen Account Communication Guide · Support FAQ |
| Sales | SLS | Product Catalogue & Schedule of Charges · Corporate Salary-Account Tie-up SOP · Referral Programme Rules · Sales Conduct & Mis-selling Policy · Lead Qualification Playbook · Business Correspondent Partner Onboarding |
| Marketing | MKT | Brand Guidelines · Marketing Communications Compliance (RBI Fair Practices, ASCI) · Campaign Approval Workflow · Festive Campaign Playbook · TRAI DLT SMS Template Registration SOP · Social Media Policy |
| Engineering / API | ENG | Public API Reference (OpenAPI 3.1: accounts, payments, KYC) · Authentication Guide (OAuth 2.1) · Webhooks Guide (signing, retries) · Idempotency Guide · Rate Limits & Error Codes · Sandbox Guide · API Versioning & Deprecation Policy · Incident Management Runbook & SEV Levels · Changelog |
| Company | CORP | Company Overview & Org Chart · Code of Conduct · Information Security Policy · BCP / DR Policy · Employee Handbook · Corporate Glossary · Board-Approved Policy Register |
Every document carries a header block: doc code, version, status, effective date, owner, approver, classification, regulatory references, revision history. Real public regulations are cited by name; the company and all its procedures are fictional, and every file says so.