LedgerLens
AI-assisted transaction mapping for messy financial data.
The problem
Real-world transaction data is not clean. A bank or payment processor hands you strings like these:
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.
- 01 Normalize
Strip noise characters, collapse whitespace, uppercase the description. Turn
SQ *LOCAL COFFEEintoLOCAL COFFEE. - 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.
- 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.
- 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.
- 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.
- 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.
- 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.
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
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.
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
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