Inspiration

Every financial literacy curriculum I have seen teaches budgeting, compound interest and credit scores. All of it quietly assumes one thing that nobody checks: ==that the money reaches the right person.==

In 2024, US consumers reported $12.5 billion lost to fraud.[^ftc] India reported ₹22,845 crore in cyber-fraud losses in a single year.[^mha] Those are only the reported figures, and fraud is one of the most under-reported crimes there is.

The gap is not knowledge. Almost everyone can recite "your bank will never ask for your PIN." The gap is reflex. A scam message does not arrive during a lesson. It arrives while you are walking to class, distracted, expecting a delivery that genuinely is on its way. You get about fifteen seconds and no time to reason from first principles.

That cannot be taught as a list of rules, because scammers rewrite the rules weekly. The only thing that transfers is ==pattern exposure at speed, with a price attached to being wrong.== So I built a game that does nothing else.


What it does

Fraud IQ is scam detection as a daily game.

Home screen A live case The reveal
Pick a region, take the daily One message, fifteen seconds The game shows you the tells

A run is a 13-case gauntlet: twelve cards drawn from the pool, then a boss finale worth double. Each case is rendered to look like the real thing.

Artifact Example
SMS A delivery notice with a redirect link
Email A payroll change request from "HR"
Payment request A UPI collect framed as a refund
DM A recruiter offering a wrap-your-car job
Ad A too-good marketplace listing
Call screen An unknown number spoofing your bank
Browser popup A fake security alert with a support number

Three lives, fifteen seconds per case. You call it SCAM or LEGIT.

On reveal, the game highlights the exact tells inside the message: the lookalike domain, the urgency clause, the payment rail that cannot be reversed. Legitimate cards explain their green flags too, ==because a trainer that only ever shows fraud teaches paranoia, not judgement.==


The part that makes it economics

Most quiz games stop at right and wrong. This one converts your session into money, then charges you in both directions.

Every scam card carries a realistic loss amount \(\ell_i\), sized against typical reported figures. At the end of a run the game computes two separate costs:

$$ C_{\text{trust}} = \sum_{i \in M} \ell_i \qquad\qquad C_{\text{suspicion}} = \lvert F \rvert $$

where \(M\) is the set of scam cards you trusted or let time out, and \(F\) is the set of legitimate messages you flagged as fraud.

Splitting them matters, because the naive way to never lose money is to distrust everything, and that is not free either:

Strategy \(C_{\text{trust}}\) \(C_{\text{suspicion}}\) Real-world cost
Trust everything maximum 0 You get phished
Flag everything 0 maximum You miss real refunds, real delivery notices, real bank alerts
Calibrated low low The actual goal

The target is not maximum suspicion. It is calibration. Scoring both error directions is what turns this from a fear machine into a financial-decision trainer.


How scoring works

For a correct call, points are awarded as:

$$ s_i = \left(100 + \mathrm{round}!\left(\frac{50\,t_i}{15}\right) + \min\left(10\,\sigma_i,\; 100\right)\right) \cdot b_i $$

Term Meaning
\(t_i\) seconds left on the clock, out of 15
\(\sigma_i\) consecutive correct answers before this card
\(b_i\) 2 on the boss card, 1 everywhere else

A wrong call or a timeout scores \(s_i = 0\) and costs a life. Difficulty is banded by player level, so later levels shift the deck toward harder tiers: ==the deck sharpens as the player does.==

One daily gauntlet, the same deck for everyone, flipping at midnight US Eastern. Comparable scores, a real leaderboard, a share block, and a reason to come back tomorrow. Retention is not a growth hack bolted on afterwards, it is the mechanism, because reflexes come from repetition rather than from one good session.


How I built it

Layer Choices
Front end React, TypeScript, Vite, Tailwind, Framer Motion, wouter, TanStack Query
Back end Express 5, Drizzle ORM, PostgreSQL, Zod
Testing Vitest, 66 tests
Tooling Node 24, pnpm workspaces

Three architectural decisions carried the project.

1. All game logic is pure functions. Session construction, deck banding, scoring, streaks, the level curve, persistence and share formatting live in one module with no React and no I/O. Screens render, they never compute. That is what makes the rules testable without a browser.

2. Integrity is enforced by the database, not by application checks. Two partial unique indexes do work that would otherwise need locking:

  • (player_id, run_id) where run id is not null makes score submission idempotent, so a retried or double-fired request cannot inflate the leaderboard.
  • (player_id, run_date) where mode is daily enforces one daily score per player at the storage layer, not in a race-prone check-then-insert.

The date key is computed server-side in America/New_York, so nobody farms extra daily attempts by changing their device clock.

3. Anti-cheat runs in three layers. Zod bounds every field at the boundary. A pure isImpossibleRun() rejects states the game cannot physically produce, such as a positive score with zero accuracy, or total money handled above MAX_MONEY_PER_RUN of 37,400, which exceeds the richest deck the dealer can build. Submissions less than ten seconds apart are rejected outright. Because those rules are pure and exported, every one of them is unit-tested with no database in the loop.

Players are identified by an opaque token compared with crypto.timingSafeEqual, never with plain string equality. ==No email, no password, no personal data.==

And no AI is called at runtime. The game is deterministic, playable offline as a guest, and costs a fraction of a cent per player to serve. At this problem's scale, cost to serve is a feature rather than an implementation detail.


Challenges I ran into

Writing the content pool by hand.

Total cases 187
Scams / legitimate 118 / 69
Categories 33
Sourced intel cards 34

==None of it is AI-generated.== Every card is written from real reported fraud patterns: FTC and IC3 case types, bank and postal service advisories, platform trust-and-safety writeups, and India-specific rails like UPI collect requests, fake KYC re-verification and the digital-arrest scam. This was by far the largest time cost and it was the right one, because a fraud trainer built on synthetic fraud teaches synthetic reflexes.

Making the highlighter honest. Each tell's span has to be a literal substring of that card's own text, so the reveal marks up the words the player actually read instead of a paraphrase. Enforcing that across 118 scam cards meant treating the content as typed data with invariants rather than as copy.

Two markets, one deck, no confusion. A US player should never be graded on a UPI collect request, and an India player should not be tested on FAFSA. The dealer serves region-neutral cards plus the player's own country:

Player region Cards they can draw
United States 137
India 107
Shared pool 187

Accessibility on a timed game. The countdown was machine-gunning the screen reader announcement queue, so the number is now hidden and replaced with a coarse spoken bucket. The quit dialog had to become a real aria-modal with a focus trap, because keystrokes were leaking through to the game running behind it. This mattered more than usual here: ==older and low-vision users are among the most targeted demographics for fraud==, so an inaccessible fraud trainer excludes exactly the people who need it most.


Accomplishments that I'm proud of

Results screen

  • Every statistic in the product cites a source and a year, and a test enforces it. All 34 collectible intel cards carry provenance on the card face. An uncited stat fails the build rather than shipping quietly.
  • 66 tests, all green. 41 covering game logic and content provenance, 25 covering the API and anti-cheat rules.
  • The economics card. Pricing over-suspicion as a real cost is the idea that makes this a financial product rather than a security quiz, and it survived contact with the implementation.
  • It is genuinely finished. Full accessibility pass, deterministic offline play, a real leaderboard with server-side integrity, and no placeholder content anywhere in the deck.

What I learned

Fraud is priced in both directions, and almost nobody teaches the second one. Building the results screen forced me to quantify the cost of over-caution, and that single decision reframed the entire project.

Push integrity down to the storage layer. My first daily-limit implementation was a check-then-insert, which is a race condition with extra steps. Replacing it with a partial unique index deleted code and made the guarantee real.

Content is infrastructure. The highest-leverage decision in the whole build was treating 187 hand-written cases as typed, tested data with invariants, rather than as strings in a file.


What's next for Fraud IQ

  • [x] Two markets live, region-aware dealing, 187 sourced cases
  • [ ] More regions. The schema is already region-tagged and the dealer already filters by market, so the UK, Nigeria, the Philippines and Brazil are content work rather than engineering work.
  • [ ] Classroom mode. Cohort codes, an aggregate weak-category view for the teacher, and no student accounts.
  • [ ] Institutional distribution. The natural buyer is a bank, a credit union or a campus financial-aid office, all of whom already absorb the loss when someone gets phished. A deterministic, offline-capable trainer at a fraction of a cent per player is cheap enough to hand out at that scale.
  • [ ] A live-pattern pipeline. Turn newly reported scam formats into vetted cards, so the deck tracks what is actually circulating this month.

[^ftc]: Federal Trade Commission, Consumer Sentinel Network Data Book 2024. Consumers reported losing more than $12.5 billion to fraud, a 25% increase over 2023. [^mha]: Ministry of Home Affairs, reply in the Lok Sabha, 2025, reporting ₹22,845 crore in cyber-fraud losses.

Built With

Share this project:

Updates

Submission history