Inspiration

Cybersecurity is very much like a game of bluff, you have seconds to decide what is true and what is not, and the stakes of deciding wrong are very high. Which is exactly why we build a dashboard that feels like reading the table. It starts a live feed where risky transactions stand out the way a bad bet does at the poker table. Every part of our product is backed by real fraud detection heuristics instead of a demo data set which makes it something that is ready to be used in the real world and by everyone. The casino framing helps map risk tiers, suits and calls such as flagging, clearing or escalating a suspicious transaction, all of which create a visual metaphor that an analyst can read at a glance.

What it does

  1. Live transaction feed — a simulator continuously generates realistic purchases against WebSockets as they're scored in real time.
  2. Rule-based risk scoring — each transaction is scored against four independent fraud signals: amount outliers (over 5x normal range), velocity spikes (a second transaction on the same account within 15 seconds), geo-anomalies (transactions across the world in a span of time that wouldn't allow travel to the second location), and card-not-present transactions. Scores combine into a 0-100 risk score and a low/medium/high rating.
  3. Geo-visualization — a live map shows all transactions as poker chip markers colored by risk level, with dashed travel lines drawn from home location to transaction location for high-risk or impossible-travel cases.
  4. Card-table UI — transactions are dealt onto the table like playing cards, with stats rolling like slot-machine digits.
  5. Analyst review workflow — anyone using the product can flag, clear, or escalate a suspicious transaction; every analyst decision is written both to Postgres and as a memo instruction on the Solana devnet Memo Program, giving each action a public, timestamped, immutable on-chain record.
  6. Audit log UI — renders each entry as a literal playing card (suit = action type, rank derived from the entry ID) with an "on-chain" vs. "pending" badge depending on whether the chain write has confirmed.
  7. Credential-stuffing defense demo — a "Simulate attack" button fires a burst of fake login attempts against the backend, which is rate-limited (express-rate-limit) so the attack gets blocked after a threshold, with the block visualized live.
  8. Two-factor analyst gate — access to the dashboard is stubbed behind a two-step identity check (Persona for identity verification, Presage for liveness), giving a real answer to "who can even see this data."
  9. AI-generated seed data — customers, accounts, and 90-day purchase histories used to seed the demo are synthesized by Google's Gemini API using structured JSON-schema output, so the "normal" spending behavior the fraud rules compare against is realistic and varied instead of hardcoded. ## How we built it
  10. Frontend: Nuxt 3 / Vue 3 + TypeScript, Pinia for the transaction store, Tailwind for styling, Leaflet (with Stadia Maps dark tiles) for the live map, and Socket.io-client for the real-time feed. If the WebSocket can't connect within 2.5s, it falls back to a local mock generator so the UI is always demoable, even offline.
  11. Backend: Node/Express with Socket.io for the real-time layer, PostgreSQL for persistence (customers, accounts, transactions, audit log), and a simulator service that generates transactions against real seeded account data on an interval, running the same haversine-distance and rule-based scoring logic that would run against live transactions in production.
  12. On-chain audit trail: @solana/web3.js writes a short memo to Solana devnet via the public Memo Program for every flag/clear/escalate decision — cheap, tamper-evident proof of who did what and when, without needing a custom on-chain program.
  13. Data: A pluggable data-provider layer generates the seed dataset; the implemented provider calls Gemini (gemini-3.1-flash-lite) with a JSON schema for customers, accounts, and purchases, so every seeded customer, account, and transaction history is AI-generated rather than hardcoded, then loaded into a Nessie-style Postgres schema. Purchases are requested in batches of 10 with retry/backoff on rate limits and malformed batches. Home locations are assigned per account (mapped from state to coordinates, with jitter) so "impossible travel" has a real baseline to compare against.

Challenges we ran into

  1. Risk you can actually see mid-feed. A number in a row is easy to miss; a card dealing in red and glowing isn't. We spent real time tuning the tier-to-visual mapping (fill color, suit, glow, stamp) so the eye catches what matters without reading every field.
  2. Making sure the demo can't just die. Live demos fail when networks don't cooperate, so there's a mock-feed fallback on the frontend, a local placeholder if Solana devnet is down or unfunded, and Persona/Presage stub to sandbox approve buttons — a missing API key shouldn't kill a walkthrough. 3, Real signals, not random tiers. Instead of randomly assigning risk, we built actual detection logic — haversine distance for impossible travel, per-account velocity tracking, merchant-relative amount outliers — so the "why flagged" reasons are honest, not decorative.
  3. Realistic "normal" behavior at scale. Fraud only reads as fraud against a believable baseline. Getting Gemini to reliably output large, schema-valid purchase histories meant chunking requests (10 at a time) with retry/backoff, instead of trusting one big call ## Accomplishments that we're proud of
  4. A fraud engine that actually crunches real geo-distance and velocity numbers server-side — not cosmetic risk labels, but real math behind the "impossible travel" and "too fast" flags.
  5. A tamper-evident audit trail — every flag/clear/escalate call is independently verifiable on Solana devnet, not just sitting in a database someone could quietly edit.
  6. A UI built to be read under pressure — the card-table layout and poker chip markers aren't just a fun skin, they're there so an analyst can scan risk at a glance instead of parsing a spreadsheet mid-incident.

What we learned

The biggest lesson was that a security tool is only as good as how fast someone can read it — the fraud logic can be perfect, but if an analyst can't spot the risky transaction in half a second, it doesn't matter. That's why we put real time into the card visuals instead of treating them as decoration. We also learned demos break at the infrastructure level, not the logic level — our detection and Solana writes worked fine, the real risk was network flakiness or a rate limit, so building fallbacks mattered just as much as building the features themselves. And on the data side, making "normal" behavior actually look normal at scale was harder than expected — Gemini needed chunked requests and retries to reliably produce realistic purchase histories instead of one clean call. What we're proud of: real math behind the fraud signals instead of cosmetic labels, an audit trail that's genuinely verifiable on-chain, and a UI built to be scanned under pressure instead of read line by line.

What's next for Call the Bluff

  1. Trained anomaly-detection layer — swap the rule-based scorer for a real model: an isolation forest (flags outliers by how easily they separate from the rest of the data) or gradient boosting (a chain of decision trees, each correcting the last). Train it on the seeded transaction history, using the current fraud rules as input features rather than the final verdict.
  2. Real liveness verification — swap the stubbed Presage check for genuine sandbox credentials, so the analyst gate does real liveness verification (confirming a live human, not a photo or recording) instead of a fake setTimeout pass-through.
  3. Custom on-chain audit program — move off Solana's generic Memo Program (just a plain text note) and onto a small custom program (purpose-built on-chain code), so fields like transaction ID, action, analyst, and prior status are directly queryable on-chain instead of buried in memo text.
  4. Account-level history view — let an analyst view a flagged transaction alongside that account's last couple of purchases, so it's judged in context instead of in isolation.

Built With

Share this project:

Updates

Submission history