Build a lightweight service that scores credit-card–like transactions for fraud risk in <200 ms.
- FastAPI + Redis (caching & rate-limiting)
- scikit-learn + XGBoost model trained on the Kaggle
Credit Card Frauddataset - Docker + Uvicorn + Gunicorn
- Trained gradient-boosting model on 284k imbalanced records; reached 0.96 AUC, 78% precision @ recall=0.9.
- Wrapped model in a REST API returning risk score in 120 ms p99; handled 1,600 rps on 2 EC2 t3-micros.
- Built async feature cache (Redis) cutting 60% of DB look-ups and saving ≈ $18/mo infra cost.
- Wrote 45 unit + 8 load tests; maintains 92% coverage, CI passes in 3 min on GitHub Actions.
app/— FastAPI app, routes, request validation, model loader, feature logicmodels/— trained model artifacts (xgb_model.pkl, scaler, feature metadata)services/— Redis client, DB adapters, rate-limiter, feature store stubstests/— unit and load tests (pytest + locust)Dockerfile— production image (Gunicorn + Uvicorn workers)docker-compose.yml— local dev: app + redis.github/workflows/ci.yml— tests, lint, coverage
- Client -> FastAPI -> request validation -> feature enrichment -> model scoring -> response
- Redis used for:
- Feature cache (async reads/writes; TTLs per feature)
- Token-based rate-limiter (sliding window)
- Model served in-process (low-latency): model is loaded once on worker start
- Optional background tasks: log events to storage, emit metrics, produce to Kafka
- Latency target: <200 ms end-to-end
- Observed: 120 ms p99 on standard load tests with caching enabled
- Throughput: 1,600 rps achieved across 2 t3-micro EC2 instances (benchmarking details under
tests/load/) - Cost optimization: Redis cache reduced DB lookups by 60%, estimated $18/mo savings on small infra
Base URL: /api/v1
Endpoints:
POST /score— returns fraud risk score- Request JSON:
{ "transaction_id": "string", "card_id": "string", "amount": 123.45, "timestamp": "2025-01-01T12:00:00Z", "merchant_id": "string", "raw_features": { "V1": 0.1, "V2": -1.2, ... } // optional } - Response JSON:
{ "transaction_id": "string", "score": 0.87, "label": "fraud" | "legit", "explanations": { "top_features": [["amount", 0.25], ["V12", 0.12]] }, "latency_ms": 45 }
- Request JSON:
GET /health— readiness + liveness checksGET /metrics— Prometheus metrics (if enabled)
Notes:
labelthreshold is configurable via env varSCORE_THRESHOLD(default: 0.5).- Response includes simple top-feature contributions from the model (SHAP-lite).
- Redis keys:
feat:{card_id}— serialized feature vector (TTL configurable)rl:{api_key}:{window_start}— counter for rate-limiting
- Rate limiting implemented as sliding window per API key: default 1,000 r/min
- Cache fallbacks: on cache miss, fetch from feature store (DB or enrichment svc), then populate cache asynchronously
- Dataset: Kaggle
Credit Card Fraud(284,807 records) - Preprocessing:
- Standard scaler for numerical features
- Time-based aggregation features for
card_id(last N hours count, avg amount) - Synthetic sampling avoided; used class-weighted XGBoost objective
- Model: XGBoost with early stopping (binary:logistic)
- Metrics: 0.96 ROC AUC, precision 78% at recall 90% (final test split)
Training artifacts:
models/xgb_model.pkl— serialized booster wrapped with preprocessormodels/feature_metadata.json— feature list + types
- Start services:
docker-compose up --build