How to get LedgerFlow running from a clean machine. The local path (steps 1–4) needs no Azure account — SQL Server and blob storage run in Docker, and every Azure boundary is behind an interface, so the domain and the API work offline. The Azure path (step 5) is needed only for live document extraction and the Functions pipeline.
For what LedgerFlow is and how the three-way match works, see README.md.
| Tool | Version | Needed for |
|---|---|---|
| .NET SDK | 8.0 | every C# project |
| Node.js | 20 LTS | web/ — the review-queue UI |
| Docker Desktop | latest | local SQL Server + Azurite |
| Git | any recent | clone |
| Azure Functions Core Tools v4 | v4 | only to run the Functions worker locally |
dotnet --version && node --version && docker --version
git clone https://github.com/NickZivkovic1993/invoice-processing-pipeline.git
cd invoice-processing-pipeline
dotnet restore LedgerFlow.sln
dotnet build LedgerFlow.sln
cd web && npm ci && cd ..
No Docker, no Azure, no network — the tests run against an in-memory database and a fake ERP. This is exactly what CI runs:
dotnet test LedgerFlow.sln # matcher, per-supplier policy, pipeline orchestration
cd web && npm run build && cd ..
InvoiceProcessorTests covers the whole extract → match → post-or-queue path including
duplicate suppression, so a green run means the core is genuinely working — not just
compiling.
docker compose up -d # SQL Server :1433 + Azurite :10000/:10001
dotnet run --project src/LedgerFlow.Api # exception-queue API on :5080
cd web && npm run dev # review UI on :5173, proxied to the API
docker-compose.yml brings up SQL Server 2022 (SA password
Your_strong_Pass123 — local only, never reuse it) and Azurite. Give SQL Server ~30
seconds on first start before the API connects.
What works locally: the exception queue, approve/reject, the analytics aggregates, and the matcher itself. What doesn’t: live extraction and the queue-triggered Functions — Document Intelligence and Service Bus have no local emulator, so they’re stubbed at their interfaces in tests and need real resources to run for real.
az login
az deployment group create -g <resource-group> -f infra/main.bicep
infra/ provisions the whole estate with managed identity throughout — no
secrets in app settings. Then LedgerFlow.Functions reads (via managed identity in
Azure, local.settings.json locally):
| Setting | Purpose |
|---|---|
DocumentIntelligenceEndpoint |
Azure AI Document Intelligence resource URL |
ServiceBusConnection |
Service Bus namespace |
BlobServiceUri |
storage account holding the invoice inbox |
SqlConnectionString |
Azure SQL exception-queue database |
ErpBaseUrl |
ERP posting + reference-data API |
To run the Functions worker locally against those resources:
cd src/LedgerFlow.Functions
# create local.settings.json with the settings above (it is gitignored — never commit it)
func start
docker compose logs sql to confirm it’s accepting connections.docker-compose.yml.dotnet build restores net6.0 projects — those are Functions tooling targets, not
application code. You still only need the 8.0 SDK.DocumentIntelligenceEndpoint is unset. The API and UI show the queue; the worker is
what drains it.SupplierPolicies; per-supplier
overrides beat the defaults.