docu-ai-flow
A .NET 10 Worker Service that watches a folder, extracts PDF invoice data via Google Document AI, persists it in SQLite, and sends quarterly ZIP archives to your tax advisor by email. What makes it singular: every development phase was planned and executed by a Claude Code agent flow — orchestrator, planners, coders and reviewer — following strict TDD.
The problem
Managing supplier invoices is repetitive manual work: downloading PDFs, opening them one by one, copying data into a spreadsheet, sending everything to the advisor each quarter. One mistake at any step means incorrect tax filings. I needed a system that did this work automatically — and that would also serve as a real-world test bed for an AI-assisted development workflow.
The solution
-
Folder watcher
Detects PDFs in ./data/inbox/ in real time. A filesystem watcher plus a polling fallback guarantee no invoice is ever missed. A concurrency gate prevents processing the same file twice.
-
AI extraction
Google Document AI (Invoice Parser) extracts supplier, tax ID, invoice number, date, net amount, VAT and total as typed fields, behind a single IInvoiceDataExtractor port. The LlamaParse adapter is kept as a reference. A configurable confidence threshold automatically discards uncertain extractions and moves them to ./data/failed/.
-
Excel export
ClosedXML generates a quarterly Excel file with native types — real dates and numbers ready to sort, filter and sum. A cumulative master spreadsheet is regenerated on every new invoice.
-
Advisor dispatch
Resend packages the quarter's PDFs into a ZIP and emails them to the tax advisor. If the ZIP exceeds Resend's 40 MB limit, it splits automatically by month and sends one email per part.
Tech stack
Backend
- .NET 10
- C#
- Hexagonal
- Result/Error
- SQLite
- Google Document AI
- Resend
- Polly
Tests
- xUnit
- NSubstitute
- WireMock.Net
- NetArchTest
AI Workflow
- Claude Code
- Agents
- Skills
- TDD
Technical decisions
-
Hexagonal architecture
Google Document AI, SQLite, the file archiver and Resend are swappable adapters behind interfaces (ports). Application use cases know no implementation detail. A NetArchTest architecture test enforces these boundaries on every build.
-
Swappable extraction
The extractor started out as LlamaParse, but its accuracy fell short. Swapping it for Google Document AI was a single line in the composition root: the domain, the use cases and the pipeline tests were left untouched, because they depend on the IInvoiceDataExtractor port, not the provider. LlamaParse stays in the repo as a proof-of-result, with its contract tests still green.
-
Result/Error for business failures
A low-confidence extraction, incoherent total or missing invoice number is an expected business case, not an exception. Result<TValue, TError> expresses it as a return value. Exceptions are reserved for transient failures — API down, disk full — which Polly retries automatically.
-
Built with Claude Code agents
Every feature followed the same cycle: the orchestrator explored and debated the approach, planner-backend designed the architecture, coder-backend implemented in TDD, and reviewer audited against the approved plan. The result: consistent code and a commit history that tells the story of every decision.
Built with Claude Code
The project is also an experiment in how to organise AI-assisted development. The agents and skills live in .claude/ and are part of the public repo.
-
Orchestrator
Coordinates the full flow: explore, debate, plan, implement, review. No phase starts without explicit human agreement. The plan lives in workflow/ and moves through plans/ → in-progress/ → reviewing/ → done/.
-
Specialised agents
planner-backend designs the architecture and contracts; coder-backend implements in strict TDD; reviewer audits against the approved plan. Each agent has its own system prompt under .claude/agents/.
-
Reusable skills
Markdown skills loaded at session start: commit.md defines the commit format, tdd.md encodes the Red-Green-Refactor cycle, orchestrate.md the full orchestration flow.
-
AI-assisted TDD
Every feature starts with a failing test. The coder writes the minimum code to pass, then refactors. 111 tests across three layers: Domain (pure), Application (use cases with NSubstitute doubles) and Integration (SQLite, Excel, zip, watcher, mapper golden-master and an end-to-end pipeline driven by a fake extractor).
Interested in the AI workflow?
The repo is public. The agents, skills and orchestration flow are in .claude/ alongside the source code. Use them as a template for your own projects.