This project is a natural progression from a standard payment microservice: it accepts transaction requests, enriches them with real-time behavioral features, scores fraud risk in an isolated ML service, and stores the final decision before the transfer is committed.
The repository is now configured to reuse existing Dockerized infrastructure for Postgres and Redis instead of creating new database or cache containers.
For a full beginner-to-advanced explanation of how the project works, see DOCUMENTATION.md. For a phased implementation plan and upgrade path, see ROADMAP.md. For a beginner-friendly explanation of the trained model pipeline, see ML_MODEL_GUIDE.md.
api/: Go API gateway and transaction decision serviceml-service/: Python FastAPI inference serviceml-service/training/: model training pipelineml-service/models/: saved trained model artifactsinfra/postgres/init.sql: Postgres schema bootstrapdocker-compose.yml: local stack for the API and ML service, configured to talk to your existing Postgres and Redis containers
Request flow:
- The Go API receives a transaction request.
- Redis is queried for recent transaction count, average transfer amount, and recent location history.
- The compiled feature payload is sent to the ML inference service.
- Fraud probability is mapped to
APPROVED,FLAGGED_FOR_REVIEW, orDENIED. - Postgres stores the transaction, features, score, and final status.
- A decision event is emitted through a publisher abstraction that can later target Kafka, NATS, or SQS.
- Low-latency API design with Redis-backed feature reads
- Cross-service communication via REST between Go and FastAPI
- Event-driven ready design through a pluggable decision publisher
- Model-serving separation that makes it easy to swap heuristic scoring for a trained classifier
- Includes a real trained
RandomForestClassifierartifact for demo and learning use
Before starting this project, make sure your existing containers are already running:
- Postgres container:
go_crud_postgres - Redis container:
redis-server
Then start only the API and ML service:
docker compose up --buildServices started by this repo:
- API:
http://localhost:8080 - ML service:
http://localhost:8000
External containers reused by this repo:
- Postgres:
localhost:5432 - Redis:
localhost:6379
The API container connects to those existing services through host.docker.internal, so this assumes your Postgres and Redis containers publish ports 5432 and 6379 to the host.
curl -X POST http://localhost:8080/v1/transactions ^
-H "Content-Type: application/json" ^
-d "{\"user_id\":\"user-123\",\"source_account\":\"acct-a\",\"destination_account\":\"acct-b\",\"amount\":4200,\"currency\":\"USD\",\"location\":\"IN-BLR\",\"ip_address\":\"203.0.113.7\",\"device_id\":\"device-77\"}"Example response:
{
"transaction_id": "4fd7f445-c147-4d0c-9ab3-a4c4a2e51927",
"status": "FLAGGED_FOR_REVIEW",
"fraud_score": 0.71,
"reason": "model score exceeds manual review threshold"
}The API expects the following user-scoped keys:
user:{user_id}:txn_count-> integer recent transaction countuser:{user_id}:avg_transfer_amount-> float average transfer amountuser:{user_id}:locations-> list of recent locations
If a key is missing, the service falls back to safe defaults so the platform remains operable in local development.
- Your Postgres container
go_crud_postgresis running and exposes5432 - Your Redis container
redis-serveris running and exposes6379 - The
appdbdatabase exists in Postgres - The schema in infra/postgres/init.sql has already been applied, or you will apply it once against the existing database
PORTdefault8080DATABASE_URLdefaultpostgres://app:app@localhost:5432/appdb?sslmode=disableREDIS_ADDRdefaultlocalhost:6379REDIS_PASSWORDdefault emptyML_SERVICE_URLdefaulthttp://localhost:8000DENY_THRESHOLDdefault0.85REVIEW_THRESHOLDdefault0.60
PORTdefault8000MODEL_PATHpath to a serialized sklearn-compatible model withpredict_proba
The repository now includes a real trained RandomForestClassifier pipeline for the ML service.
- training script: ml-service/training/train_model.py
- saved model artifact: fraud_model.joblib
- beginner guide: ML_MODEL_GUIDE.md
The training flow is:
- Generate synthetic fraud-like transaction examples.
- Train a
RandomForestClassifieron the same feature shape used by the live API. - Save the trained model artifact.
- Load that artifact in the FastAPI service through
MODEL_PATH. - Use
predict_proba(...)during live transaction scoring.
To retrain the model locally:
cd .\ml-service
python .\training\train_model.pyIf MODEL_PATH is missing or the file cannot be loaded, the service safely falls back to heuristic scoring.
Important note:
- this is a real ML pipeline and real model inference
- the current dataset is synthetic, so it is suitable for learning, demos, and portfolio use rather than production banking use
GET /healthzPOST /v1/transactionsGET /v1/transactions/{id}
- Apply infra/postgres/init.sql to your existing
go_crud_postgresdatabase if thetransactionstable does not exist yet - Replace the heuristic inference fallback with a real Random Forest or XGBoost artifact
- Publish decision events to Kafka or NATS for audit and downstream review queues
- Add gRPC between the API and ML service if you want stricter contracts and lower serialization overhead
- Backfill Redis feature keys from a streaming pipeline or CDC consumer