InsightGo is a full-stack local-business analytics platform: business owners sign in, upload sales/CSV data, view Power BI–style visualizations, read customer feedback — and now, from the same dashboard, run explainable customer-churn prediction backed by an ensemble ML model, SHAP/LIME explanations, and a Q-learning feedback loop.
This repository merges two previously separate projects into one product:
- Local Business Insight Platform — the MERN app (this repo's frontend theme, auth, dashboard, CSV import, review collection, visualizations).
- Churn Prediction Using XAI & Reinforcement Learning — a LightGBM ensemble classifier (98.76% accuracy) with SHAP + LIME explainability and a Q-learning-driven retraining loop that reacts to wrong predictions.
The merge is purely architectural: every model, the preprocessing pipeline, the SHAP/LIME explainers, and the RL retraining logic are copied over unchanged. What changed is plumbing — one Express API instead of two, one themed React UI instead of two, consistent ports/paths — so the two systems run as a single product instead of two disconnected demos. See "What changed vs. the original repos" for the exact list.
Churn & Business Analytics Platform using XAI & Reinforcement Learning — Engineered a web-based churn prediction system using LightGBM ensemble learning, achieving 98.76% accuracy in predicting subscription retention, integrated with SHAP and LIME for model explainability and enhanced with Q-learning-based feedback for automated, real-time, feedback-driven model updates. Integrated a business analytics dashboard for real-time sales analysis and customer feedback insights, built with React, Node.js/Express and Flask, backed by MongoDB, enabling continuous data collection for real-time customer churn prediction.
┌─────────────────────────┐
│ client (React + Vite) │ :5173
│ business & customer UI │
└────────────┬─────────────┘
│ REST (axios)
▼
┌─────────────────────────┐
│ server (Express API) │ :8000
│ auth · CSV import · │
│ reviews · /churn/* │
└───────┬─────────┬─────────┘
│ │
MONGO_URI │ │ ML_SERVICE_URL
▼ ▼
┌───────────────┐ ┌───────────────────────┐
│ MongoDB │◄──│ ml-service (Flask) │ :5001
│ "insightgo" │ MONGO_URI (same DB) │
│ ──────────── │ LightGBM + SHAP/LIME + │
│ businessinfos │ Q-learning retraining │
│ customerinfos │ └───────────────────────┘
│ import_data │
│ orders (feedback)
│ customer_rs (churn)
│ wrong_predictions
└────────────────┘
One database, insightgo, for the whole platform — the tables above are all
collections in it, not separate databases. Both server/ (via Mongoose) and
ml-service/ (via PyMongo) read MONGO_URI from their own .env and connect
to the same database, so a CSV import, a business signup, and a churn
prediction all land in one place.
- client/ — React (Vite) + Tailwind + custom CSS. Business owner, customer sign-in/sign-up, CSV upload & visualization, review collection, and the new churn prediction pages, all sharing one visual theme.
- server/ — Express API. Owns business/customer auth, CSV import, reviews,
search, and a
/churn/*module that mirrors the original churn-app's own Node "db" layer (save record → call the ML service → persist prediction → track wrong predictions → trigger RL retraining at the same threshold). - ml-service/ — the original Flask app (
predict.py), the RL retraining script (retrain_with_rl.py), the trained model artifacts (model_churn.pkl,rewards_model.pkl, …), andxai.py/benchmarking.pyused during research. Copied over unchanged aside from the path fixes listed below. - research/ — the original dataset-prep notebooks, the training notebook, and the papers referenced while building the churn model. Kept for documentation/portfolio purposes; not part of the running app.
- From the business platform's landing page, sign up/sign in as a Business.
- The business-owner dashboard has three options: Import Data, Customer Reviews, and Predict Churn.
- Predict Churn opens the churn form (13 customer features). Submitting
it saves the record and shows the LightGBM model's prediction, and — if the
customer is flagged as likely to churn — an "Explain Why" panel with the
per-feature SHAP values (as text, increase/decrease risk), a LIME
explanation plot, and the coupons/cashback the rewards model suggests to
retain them. (
ml-service/predict.pyalso returns a SHAP graph image; the UI intentionally doesn't render that one — text values + LIME plot only.) - The same page has an "Update Actual Outcome" panel: once you know what a
customer actually did, record it there. Every mismatch between prediction
and reality is logged; once 5 wrong predictions accumulate, the server
kicks off
ml-service/retrain_with_rl.py, which runs the Q-learning loop and retrains the churn/rewards models on the accumulated feedback — exactly as in the original standalone churn app. - Import Data → Current Sales Report embeds a Looker Studio dashboard. Until one is connected, it shows a themed "not connected yet" placeholder instead of a broken iframe — see Connecting Looker Studio below.
RecentVisualization.jsx ("Current Sales Report") renders through
LookerReport.jsx, which reads its
embed URL from an env var instead of a hardcoded iframe src.
Hard constraint to know going in: Looker Studio runs in Google's cloud —
it can never reach localhost. So the "Current Sales Report" can't query
this app's database directly; it needs a bridge Google's servers can reach.
This app uses Google Sheets as that bridge (Looker Studio's
best-supported, free, native connector): every CSV import automatically
pushes that batch of rows to a Google Sheet via
server/services/sheetsSync.js, and Looker
Studio reads the Sheet, refreshing whenever the report is opened or manually
refreshed. That's the realistic meaning of "real-time" here — the data is
never stale by more than one import, but it's not an instant push.
CSV upload → multer saves file → csv-parser reads it → MongoDB (import_data,
full history, never cleared) → Google Sheets (this batch only, replaces
previous) → Looker Studio report (built once against that Sheet) → embedded
in RecentVisualization.jsx via VITE_LOOKER_STUDIO_CURRENT_REPORT_URL
The database write and the Sheets sync are decoupled on purpose: if Sheets
sync fails or isn't configured yet, the CSV import still succeeds and the
data is still safely in MongoDB — /upload-csv/'s response includes a
sheetSync field ({ synced: true/false, reason }) so you can tell which
happened. You can also trigger a resync without a new upload:
POST /analytics/resync-current-sheet.
- Create a Google Cloud project at console.cloud.google.com → the project dropdown (top left) → New Project → name it (e.g. "insightgo") → Create.
- Enable the Sheets API: with that project selected, go to APIs & Services → Library, search "Google Sheets API", click it, click Enable.
- Create a service account: APIs & Services → Credentials → Create Credentials → Service account. Name it anything (e.g. "insightgo-sheets-sync"). You can skip granting it project-level roles — access is granted per-Sheet in step 5 instead.
- Generate a key: open the service account you just created → Keys
tab → Add Key → Create new key → JSON → it downloads automatically.
Move that file to
server/credentials/google-service-account.json(the wholeserver/credentials/folder is gitignored — this key never gets committed). - Create the target Google Sheet: make a new blank Sheet at
sheets.google.com, name it anything, rename
its first tab to
CurrentSalesData(or pick your own name and setGOOGLE_SHEET_TAB_NAMEto match). Click Share, and share it with the service account's email address (found on the service account's page, looks likeinsightgo-sheets-sync@<project-id>.iam.gserviceaccount.com) — give it Editor access. - Copy the Sheet ID from its URL —
https://docs.google.com/spreadsheets/d/<THIS_PART>/edit— and set it inserver/.env:GOOGLE_SERVICE_ACCOUNT_KEY_PATH=./credentials/google-service-account.json GOOGLE_SHEET_ID=<the id you just copied> GOOGLE_SHEET_TAB_NAME=CurrentSalesData - Upload a CSV through the business dashboard's "Import Data" — check the
server log for
Sheets sync: wrote N rows to "CurrentSalesData"., and confirm the rows actually appear in the Sheet. - Build the Looker Studio report: at lookerstudio.google.com, Create → Report → Add data → Google Sheets → pick that spreadsheet/tab → build whatever charts make sense for your columns (Sales by Region, a time trend, top categories, …).
- Embed it: File → Embed report → enable embedding → copy the URL →
set it in
client/.env:Also share the report itself as "Anyone with the link can view" (Share button, top right) — otherwise viewers hit Looker Studio's own "Can't access report, please sign in" wall regardless of the embed URL being correct.VITE_LOOKER_STUDIO_CURRENT_REPORT_URL=<embed url> - Restart
npm run dev:client(Vite only reads.envat startup).
From here on, every CSV import automatically refreshes the Sheet, and the report shows the latest data next time it's opened/refreshed — no more manual steps needed.
Prerequisites: Node 18+, Python 3.10+, a MongoDB instance (local or Atlas)
running on mongodb://localhost:27017 (or update the .env files below).
Every command runs from the InsightGo/ project root — cd into it first.
cd InsightGo
# 1. Install everything (creates ml-service/.venv and installs Python deps there —
# macOS's Homebrew Python refuses global `pip install` (PEP 668), so ml-service
# gets its own virtualenv instead of touching the system Python)
npm run install:all
# 2. Configure environment
cp server/.env.example server/.env # already pre-filled locally
cp ml-service/.env.example ml-service/.env
# both MONGO_URI values must point at the SAME database — see Architecture above
# 3. Make sure MongoDB is running locally, e.g.:
mongod --config /opt/homebrew/etc/mongod.conf --fork
# 4. Run client + server + ml-service together
npm run devOr run each piece separately (three terminals):
npm run dev:ml # Flask ML service on :5001
npm run dev:server # Express API on :8000
npm run dev:client # Vite dev server on :5173Nothing about the models, preprocessing, SHAP/LIME explanations, or the Q-learning retraining algorithm was touched. The only changes are wiring so the two apps work as one:
ml-service/predict.py: Flask port5000 → 5001(so it doesn't collide with the churn app's old Node "db" server port, which the main API now occupies), and the SHAP/LIME plot output folder is resolved relative to the file instead of two directories up.ml-service/retrain_with_rl.py:.envandoutputs/paths made relative to the script's own location instead of assuming abackend/db/.envfolder and a specific working directory — both were fragile even in the original repo.- The churn app's standalone Node "db" server (
churn-app/db/server.js) was ported intoserver/controllers/churnController.js+server/routes/churnRoutes.js, route-for-route identical, mounted at/churn/*on the shared Express API instead of running as its own process on its own port. predict.py/retrain_with_rl.pyhad the churn database name hardcoded asclient["churn_prediction"], ignoringMONGO_URI's own path. Both now useclient.get_default_database()so they read/write whatever databaseMONGO_URIactually points at — the same oneserver/uses. (Originally the churn app used a second, separate database; this repo consolidates everything — business data, CSV imports, reviews, and churn/RL tables — into oneinsightgodatabase, deliberately, since it's meant to run as one product.)- The RL-retraining trigger's hardcoded Windows dev path
(
D:\Churn-Prediction-Using-XAI\...) is now a relative path intoml-service/. - Both React frontends (the standalone churn-app CRA UI and the business platform's Vite UI) were consolidated into the business platform's UI/theme; the churn form + result screens are new components with the same fields, same API calls, same response fields — just styled to match the rest of the dashboard instead of introducing a second visual language.
Frontend: React (Vite), React Router, Tailwind CSS, Axios Backend: Node.js, Express, Mongoose, Google Sheets API (googleapis) ML service: Python, Flask, LightGBM, SHAP, LIME, scikit-learn, Q-learning Database: MongoDB (single shared database) BI: Looker Studio, driven by an automated MongoDB → Google Sheets sync Techniques: Ensemble learning (LightGBM), Explainable AI (SHAP, LIME), Reinforcement Learning (Q-learning), CSV-driven business analytics
InsightGo/
├── client/ React + Vite frontend (single themed UI)
├── server/ Express API
│ ├── controllers/ business/customer/CSV/reviews/churn/analytics logic
│ ├── services/ sheetsSync.js — pushes CSV imports to Google Sheets
│ ├── config/ googleSheets.js — service-account auth
│ └── credentials/ gitignored — your Google service-account key goes here
├── ml-service/ Flask ML microservice (model, SHAP/LIME, RL retraining)
├── research/ Dataset-prep notebooks, training notebook, reference papers
└── README.md