Argus— Our Story
Inspiration
Financial fraud is everywhere in the news. Billions of dollars lost every year, money laundering operations spanning dozens of accounts, and banks scrambling to keep up with increasingly sophisticated schemes. We've all seen the headlines — but when you study fintech and think about how these systems actually work under the hood, the headlines hit differently.
We kept coming back to one question: why is fraud detection still so reactive? Banks flag a suspicious transaction after the fact, freeze an account, and then an analyst spends hours manually tracing the money trail. By then, the damage is done.
We wanted to flip that. What if you could see the entire network of suspicious relationships in real time, before the money disappears? That idea — treating fraud as a graph problem rather than a transaction problem — became the foundation of Argus.
What We Learned
The biggest lesson wasn't technical. It was about working as a team under time pressure.
When you're building something this layered — a trained ML model, a REST API, a WebSocket backend, and a React frontend all talking to each other — there are a hundred places things can break. And at a hackathon, they do break, usually at the worst possible moment.
We learned to divide ownership clearly, communicate constantly, and resist the temptation to gold-plate one piece of the system while another piece was still broken. When the backend was crashing and the demo was hours away, what mattered wasn't perfect code — it was trust that your teammate had their piece handled while you fixed yours.
We also learned a lot technically. Graph Neural Networks were new territory for all of us. Understanding how GraphSAGE aggregates neighborhood information, how to engineer node features from raw transaction data, and how to turn edge-level fraud labels into node-level predictions — none of that was obvious at the start. We figured it out together.
How We Built It
We split the project into three layers and worked in parallel as much as possible.
The Model came first. We used the PaySim dataset — a simulation of 6.3 million real mobile money transactions — and built a PyTorch Geometric graph where every account is a node and every transaction is a directed edge. We engineered four node features from the raw data: total amount sent, number of outgoing transactions, total amount received, and number of incoming transactions. A 3-layer GraphSAGE network was then trained to classify each node as fraudulent or legitimate, with class weights to handle the heavy imbalance between fraud and normal accounts. After training, we exported a scores.json file mapping every account ID to a risk score between 0 and 1.
The Backend was a FastAPI server that loads scores.json and the full PaySim CSV at startup. From there it serves account graphs, risk tier breakdowns, and suspicious cluster data — all computed in-memory using NetworkX and Pandas, no database required. We also added a WebSocket endpoint for a simulated live transaction feed, and integrated Google Gemini 2.5 Flash to generate structured Suspicious Activity Reports on demand.
The Frontend is a React + Vite dashboard built around react-force-graph-2d. Analysts can browse the top fraud alerts, click any account to visualize its transaction neighborhood as an interactive force-directed graph, and read an AI-generated SAR that cites exact dollar amounts, timestamps, and counterparty account IDs — all in seconds.
Challenges
Training the GNN was harder than expected. The PaySim dataset is heavily imbalanced — fraudulent transactions make up less than 1% of the data. Getting the model to actually learn to detect fraud rather than just predicting "normal" for everything required careful tuning of class weights and multiple training runs. We also had to make a key architectural decision: PaySim labels fraud at the transaction level, but our GNN scores accounts (nodes). Translating edge-level labels into node-level ground truth, without leaking information, took real thought.
Connecting everything together was the other wall we hit. Getting the trained model's output (a JSON file of risk scores) to flow correctly into the FastAPI server, which then had to serve it to a React frontend over both REST and WebSocket — while also making Gemini API calls and handling CORS — meant a lot of moving parts had to align at once. Environment variables weren't loading, imports were failing, ports were being blocked. We debugged it one layer at a time and got there.
Built With
- batchfile
- css
- html
- javascript
- python
- shell
Log in or sign up for Devpost to join the conversation.