DEV Community

Kanha
Kanha

Posted on

I Built an AI Expense Auditor: Vision LLM + Rule-Based Fraud Detection + Multi-Currency Payouts

The Project

Sector Guard — an AI-powered expense reimbursement platform. Employees upload receipts, a vision LLM extracts structured data, a rule-based fraud engine audits every claim, and monthly payouts are locked immutably.

Live: Sector Guard

GitHub:

Sector Guard v1.5

An AI-powered expense reimbursement auditing platform. Employees upload receipts, a hosted vision-language model extracts the data automatically, and a rule-based fraud engine catches policy violations before finance ever sees them.

Live demo: https://sector-guard.vercel.app/


Overview

Sector Guard automates the expense reimbursement workflow that finance teams usually handle manually:

  1. An employee uploads a receipt (ride, food, or accommodation)
  2. A hosted vision-language model (Groq's Qwen 3.8 27B) extracts structured data — merchant, amount, currency, date, category, line items — with zero manual entry
  3. A rule-based fraud engine audits the expense against the employee's recent history, checking for policy violations, receipt-splitting fraud, and temporally impossible claims
  4. Each expense is scored, categorized (APPROVED / FLAGGED / DENIED), and the employee's trust rating adjusts accordingly
  5. At month-end, approved expenses are aggregated and locked into an immutable payout record — capped at the employee's monthly tier limit, with a category-wise (Travel /…

Why I Built This

Expense auditing is manual, slow, and error-prone in most companies. Someone stares at receipt images, types amounts into spreadsheets, checks policy rules by hand. I wanted to automate the full loop:

  1. Receipt → Structured data (vision LLM, not OCR)
  2. Data → Audit decision (deterministic rules, explainable)
  3. Approved claims → Locked monthly payout (immutable, capped at tier limit)
  4. All other things could be queried (corporate overview, individual finances, normalized to USD).

Architecture

Receipt Upload
↓
Groq Vision LLM (Qwen 3.8 27B) → Structured JSON
↓
Currency Converter (fixed rates, 21 Oct 2026) → USD normalization
↓
Fraud Engine (3 rules, risk score 0-100)
↓
Status: APPROVED / FLAGGED / DENIED /
↓
Prisma + Neon Postgres (serverless)
↓
Monthly Payout Close → Immutable record
↓
Company Summary (admin) / Employee Financial Summary

Core Features

Feature What It Does
Vision LLM extraction Receipt image → {merchant, amount, currency, date, category, line_items[]} — no templates, no regex
Fraud engine 3 rules: tier-limit breach, split-receipt detection, temporal conflict. Risk score → status. Plain-language explanations.
Trust rating Starts at 100. Clean audits +1, flags -5 to -15. Visible to admin.
Monthly payouts Approved expenses aggregated, capped at tier limit, categorized (Travel/Food/Stay/Other), locked immutable.
Company dashboard (admin) Summary cards, employee ratings table, monthly trends chart (Recharts).
Employee portal Receipt folders by month, payout history, claimed/approved/paid in USD + original currency breakdown.
Rate limiting 29 receipts/day, atomic upsert + in-function semaphore (race-condition safe).
Auth Admin login + per-employee access codes (hashed). Employees scoped to own data.

The Fraud Engine (Deterministic, Explainable)

// src/lib/engine/fraudCore.ts
function calculateRiskScore(receipt, employee, history): RiskResult {
  let score = 0;
  const reasons: string[] = [];

  // Rule 1: Tier limit breach
  if (monthlyTotal(history) + receipt.amount > employee.tierLimit) {
    score += 40;
    reasons.push(`Monthly tier limit exceeded (${employee.tierLimit})`);
  }

  // Rule 2: Split receipt fraud
  if (sameVendorSameDay(history, receipt).reduce((a,b)=>a+b.amount,0) > SINGLE_RECEIPT_LIMIT) {
    score += 35;
    reasons.push('Split-receipt pattern detected');
  }

  // Rule 3: Temporal conflict
  if (overlappingClaims(history, receipt)) {
    score += 30;
    reasons.push('Physically implausible overlapping claims');
  }

  return {
    score,
    status: score > 70 ? 'DENIED' : score > 30 ? 'FLAGGED' : 'APPROVED',
    reasons,
    calculatedReimbursement: score > 70 ? 0 : receipt.amount,
  };
}
Enter fullscreen mode Exit fullscreen mode

Why rule-based? Every flag has a clear, auditable reason. Compliance teams need "why," not "the model said so."

Currency Handling — The Pain Point I Didn't Expect

Initially hardcoded INR→USD. Real receipts come in EUR, GBP, AED...
Solution: Convert at write-time, not read-time.

// src/lib/currency/fixedRates.ts
export const FIXED_FX_RATES: Record<string, number> = {
  USD: 1,
  INR: 0.0119,   // 1 INR = 0.0119 USD
  EUR: 1.085,    // 1 EUR = 1.085 USD
  GBP: 1.315,    // 1 GBP = 1.315 USD
  AED: 0.272,    // 1 AED = 0.272 USD
  SGD: 0.745,    // 1 SGD = 0.745 USD
  // ... rates as of 21 Oct 2026
};

export function convertToUSD(amount: number, currency: string): {
  usdAmount: number;
  rate: number;
  status: 'CONVERTED' | 'UNSUPPORTED';
} {
  const rate = FIXED_FX_RATES[currency];
  if (!rate) return { usdAmount: 0, rate: 0, status: 'UNSUPPORTED' };
  return { usdAmount: amount * rate, rate, status: 'CONVERTED' };
}
Enter fullscreen mode Exit fullscreen mode

Result: Fraud engine, payouts, summaries all work in USD. Original currency preserved. Unsupported currency = UNSUPPORTED status (currently not used — all test currencies covered).

Layer Choice Why
Framework Next.js 16 (App Router) Server components, API routes, Vercel-native
Database Neon (serverless Postgres) Scales to zero, works on Vercel
ORM Prisma + @prisma/adapter-pg Required for serverless connection pooling
AI Groq API (Qwen 3.8 27B Scout) Fast, free tier, vision support
FX Static rate table no external dependency
Charts Recharts Lightweight, Tailwind-friendly
Auth JWT (jose), httpOnly cookies Simple, no external dependency
Hosting Vercel Zero-config for Next.js

What I Learned

  1. Vision LLMs > OCR for receipts. OCR gives text; vision LLM gives structure. Prompt design matters more than model choice.
  2. Never trust LLM output. The fraud engine's validation layer caught hallucinated totals and impossible dates.
  3. Convert currency at ingestion. One USD column everywhere downstream > CASE WHEN chaos in every query.
  4. Serverless rate limiting needs a semaphore. Vercel functions run concurrently. DB counter alone races.
  5. Admin dashboard = aggregation that you have already. No new table required; just query the table differently from Expense/Audit/Monthly Payout.

Demo Walkthrough

  1. Open Sector Guard
  2. Click admin tab
  3. Login: password abc
  4. Explore: Company Summary - summary cards, employee ratings table, monthly trends chart, Employees - list, create, edit, delete (access codes are hashed) Payouts - monthly records, category breakdowns Click an employee → Financial Summary → claimed/approved/paid in USD + original currency breakdown

What's Next

  • Automated payout approval (admin one-click → paidAt)
  • Email/Slack notifications on payout close
  • Configurable fraud rules per department
  • E2E tests (Playwright)
  • Dark mode toggle

Feedback, issues, and PRs welcome. If you're building AI-powered finance tools or vision LLM pipelines, let's connect.
GitHub:

Sector Guard v1.5

An AI-powered expense reimbursement auditing platform. Employees upload receipts, a hosted vision-language model extracts the data automatically, and a rule-based fraud engine catches policy violations before finance ever sees them.

Live demo: https://sector-guard.vercel.app/


Overview

Sector Guard automates the expense reimbursement workflow that finance teams usually handle manually:

  1. An employee uploads a receipt (ride, food, or accommodation)
  2. A hosted vision-language model (Groq's Qwen 3.8 27B) extracts structured data — merchant, amount, currency, date, category, line items — with zero manual entry
  3. A rule-based fraud engine audits the expense against the employee's recent history, checking for policy violations, receipt-splitting fraud, and temporally impossible claims
  4. Each expense is scored, categorized (APPROVED / FLAGGED / DENIED), and the employee's trust rating adjusts accordingly
  5. At month-end, approved expenses are aggregated and locked into an immutable payout record — capped at the employee's monthly tier limit, with a category-wise (Travel /…




Top comments (0)