Real-Time Fraud Detection using Apache Kafka Β· Redis Β· Spring Boot Β· WebSocket
An enterprise-grade real-time fraud detection system that analyses every financial transaction in under 100ms using a multi-signal scoring engine, Kafka event streaming, Redis velocity checks, and an adaptive feedback loop that gets smarter over time.
Payment arrives β Kafka β Fraud Scorer (5 signals) β Decision Engine β APPROVED / FLAGGED / BLOCKED
β
Live WebSocket alert to analyst dashboard
β
Analyst feedback β rule weights adapt
| Layer | Technology |
|---|---|
| Language | Java 17 |
| Framework | Spring Boot 3.2 |
| Event Streaming | Apache Kafka 3.7 (KRaft mode) |
| Cache | Redis 7.2 |
| Database | MySQL 8.0 |
| Real-time | WebSocket + STOMP |
| Auth | JWT (jjwt 0.11.5) |
| API Docs | Swagger UI |
| Infrastructure | Docker Compose |
docker-compose up -dThis starts MySQL, Redis, and Kafka β all configured and ready.
Verify:
docker-compose ps
# All 3 should show "healthy"mvn spring-boot:runApp starts at http://localhost:8081
On first run you will see:
Seeded 5 default rule weights
Seeded default users: admin / analyst1
Started FraudEngineApplication on port 8081
http://localhost:8081/swagger-ui
http://localhost:8081/dashboard.html
POST /api/auth/login
{
"username": "admin",
"password": "admin123"
}Copy the JWT token from the response.
POST /api/transactions
Authorization: Bearer YOUR_TOKEN
{
"userId": "user-mandeep",
"amount": 500,
"currency": "INR",
"merchantId": "flipkart",
"merchantCategory": "ELECTRONICS",
"userLocation": "Mumbai, IN",
"ipAddress": "103.21.58.12"
}Check status: GET /api/transactions/{transactionId}/status
Send the same request 6 times quickly for the same userId. After the 6th, the score exceeds 70 β auto-blocked.
# First send from India:
"userLocation": "Mumbai, IN"
# Then immediately send from UK for same userId:
"userLocation": "London, UK""merchantCategory": "CRYPTO"
# or: "GAMBLING", "WIRE_TRANSFER", "GIFT_CARDS"- Open http://localhost:8081/dashboard.html
- Paste your JWT token β click Connect
- Submit transactions in Swagger
- Watch alerts appear live in the dashboard
Click "Review" on any flagged/blocked alert in the dashboard.
Mark as Confirmed Fraud or False Positive.
Then check GET /api/analyst/rule-weights β the weights will have changed.
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/auth/login |
Login β get JWT token |
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/transactions |
Submit payment for fraud analysis |
| GET | /api/transactions/{id}/status |
Check fraud decision |
| GET | /api/transactions |
List all transactions |
| GET | /api/transactions/pending-review |
List flagged + blocked |
| GET | /api/transactions/user/{userId} |
Transactions by user |
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/analyst/feedback |
Submit fraud / false positive verdict |
| GET | /api/analyst/cases |
List open fraud cases |
| GET | /api/analyst/rule-weights |
View adaptive scoring weights |
| GET | /api/analyst/dashboard |
Summary statistics |
| Signal | Weight | Triggers when |
|---|---|---|
| Velocity check | 40 pts | >5 transactions in 60 seconds |
| Geo anomaly | 35 pts | Transaction from different country than usual |
| Amount anomaly | 25 pts | Amount is 3x+ above user's average |
| High-risk merchant | 20 pts | CRYPTO, GAMBLING, WIRE_TRANSFER, GIFT_CARDS |
| New IP address | 15 pts | IP never seen for this user before |
Thresholds: Score 0β30 = APPROVED Β· 31β70 = FLAGGED Β· 71β100 = BLOCKED
| User | Password | Role |
|---|---|---|
| admin | admin123 | ADMIN |
| analyst1 | analyst123 | ANALYST |
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Spring Boot App β
β β
β REST API β TransactionIngestor β Kafka: transactions.raw β
β β β
β FraudScorer (5 signals) β
β + Redis velocity/baseline β
β β β
β Kafka: transactions.scored β
β β β
β DecisionEngine β
β β MySQL (save result) β
β β WebSocket broadcast β
β β β
β Analyst Dashboard (live) β
β β Feedback API β
β β Kafka: feedback.labels β
β β β
β FeedbackService (adapt weights) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ