An AI-assisted pipeline that turns bank-transfer emails and PDFs into normalized, reviewable transaction data.
LedgerMail connects mailbox providers, detects a bank format, sanitizes message content, extracts structured fields, records confidence and cost, and exposes the result in an operations dashboard.
Open the seeded dashboard demo · Run locally · Test the pipeline
Note
LedgerMail is an MVP. Banco de Chile is the actively implemented provider; the other registered banks are scaffolding for expansion. The public dashboard uses seeded demo records and illustrative benchmark values rather than a connected production mailbox.
flowchart LR
Mail["Gmail / Outlook / PDF"] --> Detect["Provider fingerprint"]
Detect --> Sanitize["HTML and text sanitizer"]
Sanitize --> Prompt["Versioned bank prompt"]
Prompt --> LLM["OpenAI / Gemini / Anthropic"]
LLM --> Validate["Zod validation + normalization"]
Validate --> Confidence["Deterministic confidence"]
Confidence --> DB["Prisma + PostgreSQL"]
DB --> Dashboard["Review dashboard"]
DB --> Webhook["Optional CondoSync webhook"]
- Gmail OAuth and Microsoft Graph mailbox connectors
- Provider detection using sender, subject, HTML, footer, and logo fingerprints
- Sanitization that removes scripts, styles, comments, and repeated boilerplate before model calls
- Pluggable OpenAI, Gemini, and Anthropic adapters
- Versioned prompts and normalized transaction validation
- Deterministic confidence fields plus latency, token, and model-cost audit data
- PostgreSQL persistence, deduplication hashes, review states, and parse-attempt history
- Next.js dashboard for mailbox connection, parsing, review, replay, and metrics
- Optional webhook dispatch to a downstream system such as CondoSync
- Synthetic HTML fixtures and Vitest regression coverage
| Workspace | Responsibility |
|---|---|
apps/dashboard |
Next.js operations and review interface. |
apps/api |
Express ingestion, parsing, mailbox, replay, and webhook routes. |
packages/core |
Pipeline orchestration, sanitizer, parser, normalizer, confidence, and webhook client. |
packages/providers |
Bank fingerprints and provider registry. |
packages/llm |
OpenAI, Gemini, and Anthropic adapters. |
packages/gmail |
Gmail OAuth, message retrieval, and PDF extraction. |
packages/outlook |
Microsoft Graph OAuth and mailbox retrieval. |
packages/validation |
Shared Zod transaction schemas. |
packages/database |
Prisma schema and client. |
packages/shared |
Configuration and logging. |
Prerequisites: Node.js 20+, npm, and PostgreSQL.
git clone https://github.com/VicenteBarrientos/Ledgermail.git
cd Ledgermail
npm install
cp .env.example .envOn Windows PowerShell:
Copy-Item .env.example .envAt minimum, configure a database and one LLM provider:
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/ledgermail?schema=public"
OPENAI_API_KEY="replace-with-your-key"
DEFAULT_LLM_PROVIDER="openai"
DEFAULT_MODEL_NAME="gpt-4o-mini"
NEXTAUTH_SECRET="replace-with-a-long-random-value"
CRON_SECRET="replace-with-a-long-random-value"Initialize Prisma, then start the API and dashboard in two terminals:
npx prisma db push --schema=packages/database/prisma/schema.prisma
npm run dev --workspace @ledgermail/apinpm run dev --workspace @ledgermail/dashboard- Dashboard: http://localhost:3000
- API: http://localhost:3001
Mailbox OAuth and downstream webhook variables are documented in .env.example. Leave an integration unconfigured if you are not testing it.
Run the workspace test suites:
npm testThe core fixture tests mock database and model boundaries while exercising provider detection, sanitization, parsing, and normalization. The API suite separately exercises route behavior. Add only unequivocally synthetic or documented-anonymized fixtures.
The repository also contains a manual synthetic canary:
npm run canaryIt requires the dedicated CANARY_* variables in .env.example and makes real network/model calls. No scheduled GitHub Actions workflow is included in the public repository at this time.
- Add a provider fingerprint in
packages/providers/src/. - Register it in
packages/providers/src/registry.ts. - Add a versioned prompt under
packages/core/prompts/<bank>/. - Create unequivocally synthetic HTML and expected JSON fixtures.
- Run
npm testand inspect field-level errors before enabling the provider in a deployment.
Email bodies, attachments, mailbox tokens, and transaction data are sensitive. Before connecting a real production mailbox, a deployment needs:
- authentication and authorization on every mailbox, parse, replay, download, and chat route;
- encryption and rotation for OAuth tokens and application secrets;
- tenant isolation, audit logging, retention limits, and deletion workflows;
- strict CORS, request-size, rate-limit, and webhook controls;
- verified synthetic/anonymized test fixtures with documented provenance;
- a threat-model and privacy review appropriate to the target jurisdiction.
Never commit OAuth client files, .env, real messages, payroll documents, or exported mailbox data.
- The product is an MVP and should not be described as production- or enterprise-ready without the controls above.
- Non-Banco-de-Chile providers are expansion scaffolding, not equivalent validated integrations.
- Model output is probabilistic; deterministic validation and human review remain required.
- Demo metrics are illustrative and do not constitute an accuracy benchmark.
