Portfolio project · C# / .NET + AI integration

LedgerLens

AI-assisted transaction mapping for messy financial data.

Live demo available C# / .NET 9 ASP.NET Core EF Core + SQLite Mock AI

The problem

Real-world transaction data is not clean. A bank or payment processor hands you strings like these:

AMZN Mktp US*8H2K91 SQ *LOCAL COFFEE PAYPAL *DIGITALOCEAN OPENAI *CHATGPT SUBSCRIPTION WM SUPERCENTER #2857

Categorizing these by hand is tedious and error-prone at scale. Handing the problem entirely to an AI model introduces a different risk: opaque decisions, inconsistent outputs, and no way to audit why a transaction was labeled the way it was.

Neither extreme fits real enterprise software. You want deterministic rules where rules work, AI assistance where they don't, and a human in the loop before anything gets committed.

The solution

LedgerLens routes every transaction through a fixed, ordered pipeline. Each step only runs if the previous one didn't resolve the transaction.

  1. 01
    Normalize

    Strip noise characters, collapse whitespace, uppercase the description. Turn SQ *LOCAL COFFEE into LOCAL COFFEE.

  2. 02
    Match existing rules

    Walk the rule library in priority order — exact match first, then contains rules, then regex patterns. First match wins. No suggestion call needed.

  3. 03
    Ask the suggestion provider

    If no rule matches, the normalized description goes to a suggestion provider behind a single interface, which returns a structured result: vendor, category, confidence, and a reason. The public demo uses a deterministic mock provider; a real model slots in behind the same contract.

  4. 04
    Queue for review

    AI output never goes directly into the database. It enters a review queue. A human sees the suggestion before anything is committed.

  5. 05
    Approve, edit, or reject

    The reviewer accepts the suggestion, modifies the category, or rejects it. Every outcome is recorded with a timestamp and user identifier.

  6. 06
    Write a rule

    An approved suggestion becomes a new mapping rule. The next identical or similar transaction matches the rule and never touches the AI layer.

  7. 07
    Append to audit log

    Every action — rule match, AI suggestion, approval, rejection, rule creation — is written to an append-only audit table with timestamp and user. Nothing is overwritten.

Architecture

Five focused project layers, each with one job and one direction of dependency. The core business logic has no infrastructure dependencies — no EF Core, no HTTP, no AI client. Fully unit-testable.

LedgerLens.Web
ASP.NET Core host: Minimal API endpoints (health, dashboard, transactions, suggestions, rules, audit) plus a server-rendered Razor Pages UI for the review queue. No client-side framework. Depends on Core, Data, and AI.
LedgerLens.Tests
xUnit suite, 85+ tests, runs with no database server, network, or secrets. Covers the normalizer, rule matcher, workflow, and the startup guardrail.
LedgerLens.Core
Business logic only. Normalizer, RuleMatcher, ReviewQueue. No infrastructure dependencies — no EF Core, no HTTP, no AI client. Fully testable in isolation.
LedgerLens.AI
The suggestion provider behind one interface. The public demo ships a deterministic mock, and the app refuses to start if any other provider is configured, so a misconfigured deploy can never make paid API calls. A real model provider slots in without touching the pipeline.
LedgerLens.Data
EF Core DbContext and migrations. SQLite for local development and the live demo. Swappable for SQL Server or Postgres with no application-layer changes.

Interactive demo

The full .NET app is deployed and running. Import a transaction, watch the pipeline normalize and classify it, generate a mock AI suggestion, then approve or reject it to create a reusable mapping rule.

Open live demo →

shippedbysayre.com/ledgerlens is this writeup. ledgerlens.shippedbysayre.com is the deployed app.

Demo safety

  • All transactions are synthetic — fabricated for demo purposes.
  • The AI provider is a local mock. No external AI service is called.
  • No paid APIs are used. No API keys are required.
  • No real financial data is stored or processed.
  • Data entered is visible to other demo visitors — do not enter personal information.

From the deployed app

LedgerLens transaction queue: raw and normalized descriptions, amounts, and a status of pending review, rule matched, or approved on each row
The queue. Rows that matched a rule never needed a suggestion; the rest wait for a reviewer.
LedgerLens review cards showing vendor, category, subcategory, confidence, and the mock provider's reasoning, with approve and reject buttons
Pending suggestions. Approving one writes a reusable rule; low-confidence results are flagged for a closer look.

Why this project

The transaction mapper is the vehicle. The point is to show what responsible AI integration looks like inside a real .NET codebase — the engineering parts that actually matter in production.

Validation at the boundary
AI responses are validated against a strict schema before they touch the application. Malformed or out-of-schema outputs are rejected and logged, not silently accepted.
Human review
No AI output is written directly to the database. Every suggestion passes through a queue and requires a human decision. The AI assists — it doesn't decide.
Deterministic fallback
Rules are evaluated first. Predictable, auditable, and free. AI is the fallback, not the primary path. The rule library grows over time and AI calls become rarer.
Auditability
Every categorization is traceable to a specific rule match or a specific reviewer decision at a specific timestamp. Nothing is a black box.
Cost-conscious AI usage
Approved suggestions become reusable rules. The next similar transaction never hits the API. Token usage decreases as the rule library matures.
Clean persistence
EF Core with a focused DbContext, append-only audit table, and no God-object repositories. The data layer is deliberately boring.

Status and what's next

Version 0.1.0 is deployed. The pipeline, review flow, audit log, and dashboard are done. What remains is a real AI provider behind the existing interface and quality-of-life features.

Shipped

v0.1.0

  • Normalizer and priority-ordered rule matcher (exact, contains, regex)
  • EF Core schema and migrations on SQLite
  • Review queue with approve, edit, and reject
  • Approved suggestions written back as reusable rules
  • Append-only audit log
  • Dashboard metrics in the UI and API
  • Server-rendered Razor Pages UI
  • Docker image, Fly.io deploy, automated CI/CD
  • Startup guardrail that enforces the mock provider on the public demo
Next

Planned

  • Real AI provider (structured outputs) behind the existing interface, off by default
  • CSV transaction upload
  • Rule priority editor and conflict detection
  • Confidence threshold to skip review on high-confidence suggestions
  • Export approved mappings