BOI Hackathon | PS2: Mule Account Detection | MVP Build Roadmap
MVP BUILD ROADMAP
AI/ML Mule Account Classification
Bank of India Hackathon | 4-Member Team | Problem Statement 2
1. What We Are Building
A minimum viable ML-powered system that ingests the provided CSV dataset, trains a classification
model to detect suspicious/mule accounts, and exposes predictions through a simple interface. Three
deliverables:
• ML Pipeline: Trained model that reads the dataset, engineers features, and outputs a risk label
(SUSPICIOUS / LEGITIMATE) plus a 0-100 score per account.
• REST API: FastAPI backend that loads the trained model and accepts a CSV upload, returning
predictions as JSON.
• UI: Minimal React page — upload CSV, see results table with risk scores. No extra features.
Target variable is F3924 (binary: 1 = mule/suspicious, 0 = legitimate). The 18 hint features from the
problem statement are the starting point for the model.
2. Tech Stack
Layer Tool Why
Data & ML Python 3.11, pandas, scikit-learn, Industry standard. XGBoost is the best
XGBoost performer on tabular fraud data.
Imbalance imbalanced-learn (SMOTE) Fraud datasets are skewed; SMOTE
generates synthetic minority samples.
Explainability SHAP Shows which features drove each
prediction. High-value for bank judges.
Model Saving joblib Serialize trained model to disk so the API
can load it.
API FastAPI (Python) Minimal setup, auto-generates /docs
page, handles CSV file uploads natively.
Frontend React + Tailwind CSS Fast to scaffold. Tailwind keeps styling
quick with no custom CSS.
HTTP Client Axios One-line POST from React to FastAPI.
Deployment Railway (backend) + Vercel Both have free tiers and deploy from
(frontend) GitHub in minutes.
Internal Use Only Page 1
BOI Hackathon | PS2: Mule Account Detection | MVP Build Roadmap
3. Initial Requirements
3.1 Before the Hackathon Starts — Everyone
1. Create a shared GitHub repository. Agree on folder structure: /data, /notebooks, /model, /api,
/frontend.
2. Each member clones the repo and creates their branch.
3. Install Python environment: python -m venv venv && pip install pandas numpy scikit-learn xgboost
lightgbm imbalanced-learn shap fastapi uvicorn python-multipart joblib
4. Install Node environment for frontend: node -v (must be 18+), npx create-react-app frontend or use
Vite.
5. Test all imports in a blank Python script — resolve any version conflicts now, not during the
hackathon.
6. Download and inspect the dataset. Check shape, null counts, and F3924 class distribution. Run
df['F3924'].value_counts() and note the imbalance ratio.
7. Agree in writing (Notion/WhatsApp) on the API contract: endpoint URL, input format (CSV file
upload), output JSON schema ({ account_id, risk_score, label }).
3.2 Required Files to Have Ready
• [Link]: Full Python dependencies file committed to repo root.
• [Link]: Node dependencies for the React app.
• sample_input.csv: A small 10-row slice of the dataset for quick API testing without the full file.
• .[Link]: Template for environment variables (API URL for frontend, port configs).
4. Team Roles
Member Role Owns
M1 Data & Features EDA notebook, preprocessing script, feature engineering, SMOTE.
Delivers: clean_train.csv, clean_test.csv, [Link]
M2 ML Model Model training, evaluation, SHAP integration. Delivers: [Link],
metrics report, shap_values.csv
M3 Backend API FastAPI app, model loading, /batch_predict endpoint, Docker.
Delivers: running API on Railway
M4 Frontend UI React app, CSV upload, results table. Delivers: deployed UI on
Vercel connected to API
5. Development Phases
PHASE 1 — Setup & Data Exploration | Hours 0 – 2 | All Members
All four members work together on this phase. The goal is to understand the dataset and agree on the
plan before splitting up.
Internal Use Only Page 2
BOI Hackathon | PS2: Mule Account Detection | MVP Build Roadmap
Task Owner Details
Repo & environment All Create GitHub repo, everyone clones, installs Python +
setup Node deps, confirms imports work.
Load & inspect dataset M1 [Link], [Link](), [Link](),
df['F3924'].value_counts() — share results in group
chat.
Check null counts M1 [Link]().sum().sort_values(ascending=False).head(30
) — decide imputation strategy.
Check hint features M2 Pull out the 18 hint features, check distributions,
identify any that are all-null or constant.
Agree API contract M3+M4 Confirm: POST /batch_predict accepts CSV file,
returns [{account_index, risk_score, label}].
Scaffold folders All Create /data, /notebooks, /model, /api, /frontend in
repo. Push skeleton files.
PHASE 2 — Data Preprocessing & Feature Engineering | Hours 2 – 6 | M1 leads
M1 owns this phase entirely. M2 can start Phase 3 in parallel once the hint features are available (Hour
3).
Steps for M1:
8. Separate features and target: X = [Link]('F3924', axis=1) | y = df['F3924']
9. Train/test split (stratified to preserve class ratio): from sklearn.model_selection import
train_test_split — use test_size=0.2, stratify=y, random_state=42
[Link] nulls: SimpleImputer(strategy='median') — fit on train only, transform both train and test.
[Link]: RobustScaler() — fit on train only. RobustScaler is preferred because it is not thrown off by
outliers.
[Link] imputer + scaler into a single sklearn Pipeline object and save: [Link](pipeline,
'model/[Link]')
[Link] SMOTE on training data only: sm = SMOTE(random_state=42, sampling_strategy=0.3) —
X_res, y_res = sm.fit_resample(X_train_scaled, y_train)
[Link] clean arrays: [Link]('data/X_train.npy', X_res) and the same for X_test, y_train, y_test.
[Link] M2 that data is ready. Share the shape of X_res and class distribution of y_res.
Hint Features to prioritize (start model with these 18):
F115, F321, F527, F531, F670, F1692, F2082, F2122, F2582, F2678, F2737, F2956, F3043, F3836,
F3887, F3889, F3891, F3894
Run a quick Random Forest on these 18 first (15 min) to get a baseline AUC before touching the full
3900-column dataset.
PHASE 3 — Model Training & Evaluation | Hours 4 – 9 | M2 leads
Internal Use Only Page 3
BOI Hackathon | PS2: Mule Account Detection | MVP Build Roadmap
M2 runs three models in sequence, picks the best, wraps in an ensemble, integrates SHAP. M1 assists
after Phase 2 is done.
Step-by-step for M2:
[Link] the preprocessed data from /data/. Confirm shapes and class balance.
[Link] — Random Forest on hint features only (18 features). Measure AUC-ROC. This is your
sanity check.
[Link] on full feature set. Key params: n_estimators=200, max_depth=6, learning_rate=0.1,
scale_pos_weight=(count of 0s / count of 1s). Evaluate with 5-fold stratified cross-validation.
Record mean AUC ± std.
[Link] with is_unbalance=True. Same CV evaluation. Compare AUC to XGBoost.
[Link]-voting ensemble: average predicted probabilities from XGBoost and LightGBM. This usually
beats either model alone by 0.5–1% AUC.
[Link] ensemble on held-out test set. Print: classification_report(y_test, ensemble_predictions),
roc_auc_score(y_test, ensemble_proba)
[Link] (minimum viable): import shap — explainer = [Link](xgb_model). Compute
shap_values for the test set. Run shap.summary_plot() to get a screenshot for the presentation.
[Link] the ensemble: [Link]({'xgb': xgb_model, 'lgb': lgb_model, 'pipeline': pipeline},
'model/[Link]')
[Link] [Link] with final AUC, F1, precision, recall numbers. Commit to repo.
Minimum acceptable results to proceed: AUC-ROC ≥ 0.85, F1 (fraud class) ≥ 0.75. If below, increase
scale_pos_weight or try class_weight='balanced'.
PHASE 4 — FastAPI Backend | Hours 6 – 11 | M3 leads
M3 builds the API in parallel with Phase 3. Use dummy model predictions until [Link] is ready, then
swap in the real file.
File structure for /api:
api/
[Link] # FastAPI app
model/ # [Link] and [Link] go here
[Link]
Dockerfile
[Link] — core logic:
from fastapi import FastAPI, UploadFile, File
from [Link] import CORSMiddleware
import pandas as pd, joblib, numpy as np, io
app = FastAPI()
app.add_middleware(CORSMiddleware, allow_origins=['*'],
allow_methods=['*'], allow_headers=['*'])
Internal Use Only Page 4
BOI Hackathon | PS2: Mule Account Detection | MVP Build Roadmap
models = [Link]('model/[Link]')
pipeline = models['pipeline']
@[Link]('/health')
def health(): return {'status': 'ok'}
@[Link]('/batch_predict')
async def batch_predict(file: UploadFile = File(...)):
df = pd.read_csv([Link](await [Link]()))
X = [Link]([Link]('F3924', axis=1, errors='ignore'))
xgb_p = models['xgb'].predict_proba(X)[:,1]
lgb_p = models['lgb'].predict_proba(X)[:,1]
proba = (xgb_p + lgb_p) / 2
scores = (proba * 100).round(1).tolist()
labels = ['SUSPICIOUS' if p >= 0.65 else 'LEGITIMATE' for p in proba]
return [{'index': i, 'risk_score': scores[i], 'label': labels[i]}
for i in range(len(scores))]
Dockerfile:
FROM python:3.11-slim
WORKDIR /app
COPY [Link] .
RUN pip install -r [Link]
COPY . .
CMD ["uvicorn", "main:app", "--host", "[Link]", "--port", "8000"]
[Link] locally: uvicorn main:app --reload — visit [Link] to confirm both endpoints
show.
[Link] with curl: curl -X POST [Link] -F 'file=@sample_input.csv'
[Link] to GitHub. Connect Railway to the /api folder. Set start command to the uvicorn CMD above.
[Link] the Railway public URL and share with M4.
PHASE 5 — React Frontend | Hours 7 – 13 | M4 leads
M4 builds the minimum interface: file upload, call API, display results table. No extra features until this
baseline works end-to-end.
Component structure (keep it flat — no over-engineering):
src/
[Link] # root, holds state
[Link] # drag-drop or file input + submit button
[Link] # table of results with risk score + label
[Link] # Axios call to /batch_predict
[Link]:
import axios from 'axios';
Internal Use Only Page 5
BOI Hackathon | PS2: Mule Account Detection | MVP Build Roadmap
const BASE = [Link].REACT_APP_API_URL || '[Link]
export async function predict(file) {
const form = new FormData();
[Link]('file', file);
const res = await [Link](`${BASE}/batch_predict`, form);
return [Link];
}
[Link] — color-coded risk badges:
function badge(score) {
if (score >= 70) return 'bg-red-100 text-red-700';
if (score >= 40) return 'bg-yellow-100 text-yellow-700';
return 'bg-green-100 text-green-700';
}
[Link] with Vite: npm create vite@latest frontend -- --template react, then cd frontend && npm
install axios
[Link] Tailwind: npm install -D tailwindcss postcss autoprefixer && npx tailwindcss init -p
[Link] UploadSection first — file input, onChange stores file in state, button calls predict(file).
[Link] ResultsTable — maps over results array, renders one row per account with index, risk score
badge, label.
[Link] [Link]: on submit call API, set results state, conditionally render ResultsTable.
[Link] loading state (simple spinner div) so UI doesn't look frozen during prediction.
[Link] REACT_APP_API_URL to the Railway URL in Vercel environment variables. Deploy.
PHASE 6 — Integration & Final Testing | Hours 12 – 16 | All Members
Task Owner Details
End-to-end test M3 + M4 Upload real CSV through deployed frontend. Confirm
predictions render. Fix CORS or URL issues.
Edge case test M2 + M3 Test with CSV missing some columns, CSV with wrong
column names — API should return a clear error, not
crash.
Prepare demo CSV M1 Create a 50-row test file with a mix of known high-risk
and low-risk accounts for the live demo.
Screenshot results M4 Take a screenshot of the results table with risk scores
visible — use in presentation slides.
Metrics slide M2 Pull AUC, F1, precision, recall from [Link]. Format
as a clean table for slide 4.
Practice demo run All Do one full run-through: upload CSV, walk through
results, point to a high-score account. Time it — target
under 3 minutes.
Internal Use Only Page 6
BOI Hackathon | PS2: Mule Account Detection | MVP Build Roadmap
6. Integration Contracts
These are the exact formats that connect each member's work. Agree on these on Day 1 and do not
change them without notifying the dependent member.
M1 → M2: Preprocessed data
• X_train.npy / X_test.npy: Float arrays, shape (n_samples, n_features). Already imputed and
scaled.
• y_train.npy / y_test.npy: Integer arrays, values 0 or 1.
• [Link]: Fitted sklearn Pipeline (imputer + scaler). M3 also needs this file.
M2 → M3: Trained model
• [Link]: joblib file containing dict: { 'xgb': fitted_xgb, 'lgb': fitted_lgb, 'pipeline':
fitted_pipeline }
• Expected input: Raw DataFrame with same columns as training data (minus F3924). API applies
the pipeline internally.
• Expected output: predict_proba()[:,1] — probability of class 1 (mule) per row.
M3 → M4: API response schema
[
{ "index": 0, "risk_score": 87.3, "label": "SUSPICIOUS" },
{ "index": 1, "risk_score": 12.1, "label": "LEGITIMATE" },
...
]
7. Fallback Plan
If any component is not working by Hour 14, use these fallbacks for the demo:
• Frontend not ready: Use FastAPI's built-in /docs (Swagger UI) to demo the API directly in the
browser. It has a file upload interface out of the box.
• API not deployed: Run uvicorn locally on a laptop. Demo from that machine. Use ngrok if you
need a public URL: ngrok http 8000
• Model AUC is poor: Report the number honestly. Emphasize the pipeline architecture, SHAP
explainability, and the correct framing of the problem (precision-recall trade-off). Judges value
approach over raw accuracy in hackathons.
• SHAP too slow: Pre-compute SHAP values once offline, save to shap_output.csv, hardcode a
small sample into the API response for demo purposes.
8. Definition of Done (MVP)
The MVP is complete when all of the following are true:
36.A CSV file uploaded through the frontend returns a risk score and label for every row.
Internal Use Only Page 7
BOI Hackathon | PS2: Mule Account Detection | MVP Build Roadmap
[Link] model achieves AUC-ROC ≥ 0.85 on the held-out test set.
[Link] API is live on Railway and the frontend is live on Vercel — accessible from any browser.
39.A SHAP summary plot image exists and is ready to show in the presentation.
[Link] team can demo the full flow in under 3 minutes without errors.
Everything beyond this list — threshold sliders, per-account detail panels, export buttons, network graphs
— is optional and only built if Phase 1–6 are complete with time to spare.
End of Roadmap Document
Internal Use Only Page 8