Lecture 10 ยท Module 2 Capstone

Banking Fraud Detection
End-to-End

Multi-Producer ยท Kafka ยท MongoDB or MySQL ยท Enrichment ยท 3 Fraud Rules ยท Live Alerts

๐Ÿ“… Module 2 โ€” Making Kafka Work
โฑ 90 min Workshop
๐Ÿฆ We build it live, together
02 / 10 Agenda

Today's 90 Minutes

TimeWhat We DoFormat
0 โ€“ 10Module 2 recap โ€” full path from L6 โ†’ L9Discussion
10 โ€“ 20Why fraud detection? Architecture overviewLecture
20 โ€“ 30The dataset โ€” 2,003 synthetic transactions, 3 fraud patterns plantedDemo
30 โ€“ 45Step 1 โ€” Generate data + Run producerLive build
45 โ€“ 60Step 2 โ€” choose MongoDB or MySQL storage consumerLive build
60 โ€“ 80Step 3 โ€” consumer_fraud.py (3 rules + MongoDB enrichment)Live build
80 โ€“ 90See fraud alerts fire, discuss extensions, module wrap-upDiscussion
03 / 10 Context

Why Fraud Detection?

Every card swipe triggers a real-time decision. Banks have milliseconds โ€” not hours โ€” to approve or hold.

Batch System (Old)Streaming System (Now)
Check transactions overnightCheck every transaction as it arrives
Fraud flagged next morningFraud flagged before transaction clears
Customer already abroad, card maxedTransaction held, customer called instantly
No geographic contextKnows where card was used 3 minutes ago

The pattern we use today: Kafka brings the current signal (this transaction). MongoDB holds the historical context (last known location, average spend). The consumer combines both to decide.

Scale Reference

NetworkPeak Transactions/sec
Visa65,000
Mastercard50,000+
NPCI / UPI10,000+

None of these run on batch. All use streaming architectures similar to what you're building today.

04 / 10 Architecture

What We Build Today

generate_transactions.py
2,003 rows ยท 3 fraud patterns
โ†’
transactions.csv
synthetic dataset
โ†’
transaction_producer.py
0.3s per message
โ†’
transactions-topic
Kafka
โ†™ โ†˜
Storage Consumer
consumer_store.py
or consumer_store_mysql.py
Alert Consumer
consumer_fraud.py
or consumer_alerts_mysql.py
MongoDB or MySQL
operational history
analytics destination
๐Ÿšจ Fraud Alerts
Impossible Travel
Unusual Amount ยท Rapid Fire

Choose by objective: use consumer_store.py with MongoDB for the fraud-enrichment lab, or consumer_store_mysql.py to create a live SQL table for the Grafana lectures. Both consume the same Kafka topic.

05 / 10 Dataset

The Synthetic Dataset

Run generate_transactions.py to create transactions.csv โ€” 2,003 rows, 50 fake users, 8 Indian cities.

FieldExampleNotes
transaction_idTXN-00847Unique per row
user_idUSR-04250 synthetic users
user_nameBhavna ThakurRealistic Indian names
amount4500.00INR, varies by merchant type
merchantSwiggy30 merchant types
city / lat / lonMumbai / 19.076 / 72.877Real GPS coordinates
timestamp2025-08-01 10:00:00Spread over 30 days

Planted Fraud Patterns (~5% of rows)

Pattern 1
Impossible Travel
Mumbai 10:00 โ†’ London 10:45 (7,189 km in 45 min)
10 users affected

Safe repeated runs: The generator stores the last issued number in .transactions_sequence. If the first batch ends at TXN-02003, the next batch starts at TXN-02004. The CSV contains the latest batch, while IDs continue to avoid MySQL primary-key conflicts.

Need 20,000 or a Custom Fraud Mix?

Open the course-wide Configurable Transaction Generator. Choose the total rows, total fraud as count or percentage, and the count or percentage for each fraud type. The browser validates the allocation and downloads a Python configuration file.

Pattern 2
Amount Spike
User avg โ‚น800 โ†’ single txn โ‚น92,000 at jeweller
15 users affected
Pattern 3
Rapid Fire
4 transactions in 88 seconds (card cloning test)
17 users affected
06 / 10 Step 1 โ€” Terminal 1

Generate Data & Run Producer

bash ยท Terminal 1
python generate_transactions.py
# โœ… Generated 2003 transactions โ†’ transactions.csv
#    Legitimate: 1927  |  Fraud planted: 76
#    Next run continues after the displayed ID range

python transaction_producer.py

You'll see the live feed:

โ†’ [0001] Aarav Sharma Mumbai โ‚น 4,500.00 Swiggy โ†’ [0002] Priya Mehta Delhi โ‚น 1,250.00 Amazon ๐Ÿšจ [0847] Bhavna Thakur London โ‚น 38,200.00 Duty Free โ†’ [0848] Aarav Sharma Bengaluru โ‚น 890.00 Zomato

Notice: The producer marks fraud rows with ๐Ÿšจ in its own output โ€” but the consumer doesn't know this yet. It's discovering fraud independently from Kafka + MongoDB. Leave this running and open Terminal 2.

07 / 10 Step 2 โ€” Terminal 2

Storage Consumer โ€” Choose a Destination

The consumer can write the same Kafka stream to either destination:

OptionUse It WhenConsumer
MongoDBYou want to run the three fraud rules using user profiles and recent historyconsumer_store.py
MySQLYou want SQL analysis and a live data source for the Lecture 14โ€“16 Grafana dashboardsconsumer_store_mysql.py

Option A โ€” MongoDB: Persist and Profile

Two MongoDB writes occur on every message:

python ยท consumer_store.py โ€” key logic
# 1. Append raw transaction to audit log
txns.insert_one({**txn, "ingested_at": datetime.utcnow()})

# 2. Upsert user_profiles โ€” freshest location + running totals
profiles.update_one(
    {"user_id": txn["user_id"]},
    {
        "$set": {"last_city": txn["city"], "last_lat": lat, "last_lon": lon, ...},
        "$inc": {"total_spend": amount, "txn_count": 1}
    },
    upsert=True
)

What upsert=True means

SituationBehaviour
User seen for the first timeCreates a new document in user_profiles
User seen beforeUpdates only the specified fields โ€” no duplicate

Check Atlas: After 30 seconds, open MongoDB Atlas โ†’ Browse Collections โ†’ sda_course. You'll see user_profiles filling up with one document per user, each showing their latest city and cumulative spend.

Option B โ€” MySQL: Persist for SQL and Grafana

Start the free MySQL container used in Lecture 14, install the connector, and run the alternative consumer:

bash ยท Terminal 2
docker run -d \
  --name sda-mysql \
  -e MYSQL_ROOT_PASSWORD=admin \
  -p 3306:3306 \
  mysql:8.4

pip install kafka-python mysql-connector-python
python consumer_store_mysql.py

The script creates sda_course.transactions, converts numeric and date fields, and writes one row after each Kafka message. Its upsert protects against duplicate rows if Kafka replays a transaction.

# Save first, then commit the Kafka offset
cursor.execute(UPSERT_SQL, transaction_values(txn))
db.commit()
consumer.commit()

Checkpoint: Run docker exec -it sda-mysql mysql -uroot -padmin, then query SELECT COUNT(*) FROM sda_course.transactions;. The count should rise while the producer is running.

Important: consumer_fraud.py still reads MongoDB profiles. Choose MongoDB for the complete fraud lab; choose MySQL for the optional SQL/Grafana path.

Option C โ€” Persist Alert Events in MySQL

For the live Grafana extension, open another terminal and run a second consumer group. It reads the same topic, keeps only flagged transactions, classifies the classroom fraud pattern, and writes each alert to sda_course.fraud_alerts.

bash ยท Terminal 3
python consumer_alerts_mysql.py

# Check the live alert table
docker exec -it sda-mysql mysql -uroot -padmin \
  -e "SELECT alert_type, severity, COUNT(*)
      FROM sda_course.fraud_alerts
      GROUP BY alert_type, severity;"

The mysql-store-group and mysql-alert-group are independent. Each receives every transaction: one builds the transaction table; the other builds the operational alert queue.

08 / 10 Step 3 โ€” Terminal 3

consumer_fraud.py โ€” 3 Fraud Rules

For every Kafka message, query MongoDB for the user's history โ€” then apply rules:

Rule 1
๐ŸŒ Impossible Travel
Haversine distance from last_lat/lon (MongoDB) to current > 500 km AND time diff < 60 min
Enrichment from MongoDB required
Rule 2
๐Ÿ’ธ Unusual Amount
Current amount > 3ร— (total_spend รท txn_count) โ€” requires at least 5 prior transactions
Historical avg from MongoDB required
Rule 3
โšก Rapid Fire
3+ transactions from same user in last 60 seconds โ€” query transactions collection by timestamp
Recent history from MongoDB required

All three rules need MongoDB. None of them can fire on Kafka data alone โ€” they need context that only the storage consumer has been building.

09 / 10 Discussion

What Good Output Looks Like

Legitimate transactions

โœ… [0001] APPROVED TXN-00001 Aarav Sharma Mumbai โ‚น 4,500.00 โœ… [0002] APPROVED TXN-00002 Priya Mehta Delhi โ‚น 1,250.00

Impossible Travel alert

๐Ÿšจ IMPOSSIBLE TRAVEL Transaction : TXN-00847 User : Bhavna Thakur (USR-042) ยท card ยทยทยท5530 Amount : โ‚น38,200.00 at Duty Free [IMPOSSIBLE TRAVEL] Last seen in Mumbai (19.07ยฐ, 72.87ยฐ) at 2025-08-14 10:00:22 Now at London (51.50ยฐ, -0.12ยฐ) at 2025-08-14 10:45:18 Distance 7,189 km in 44 min โ›” ACTION : HOLD TRANSACTION

Discussion Questions

  1. Change IMPOSSIBLE_TRAVEL_KM = 100. What new alerts fire? Are any of them false positives?
  2. A customer genuinely flies Mumbai โ†’ Dubai (2,200 km, 3.5 hr flight). Your rule would have blocked their arrival transaction. How do you solve this?
  3. Rule 2 requires 5+ past transactions. A customer's first big purchase is always suspicious. What would you do for new users?
10 / 10 Takeaways

Module 2 Complete

Downloads

1 / 10