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) │
└─────────────────────────────────────────────────────────────┘