MatchFlow – Zero Paperwork, 100% Confidence
MatchFlow is a web-based invoice reconciliation platform built to eliminate the tedious, error-prone process of manual invoice checking. Born from the real-world frustrations of a busy café owner juggling dozens of ingredients and line items, MatchFlow empowers any business—whether a small restaurant or an enterprise finance team—to:
- Upload a vendor’s PDF invoice in seconds
- Extract structured data (invoice number, date, line items, totals) via Azure Form Recognizer
- Compare against pre-recorded Purchase Orders
- Flag any discrepancies for rapid human review
The entire end-to-end flow—PO entry through discrepancy resolution—takes just one click, turning hours of spreadsheet work into instant confidence that you’re only paying exactly what you ordered.
- Small-to-medium businesses and enterprise procurement teams
- Restaurant owners and café operators
- Accounting and finance departments seeking to automate invoice matching
- Save Time — replace 1–2 hours of manual checks with a single click
- Reduce Risk — catch pricing mistakes, duplicate invoices, or fraud before they post
- Full Audit Trail — every upload, extraction, and approval is logged for compliance
- Anywhere Access — responsive web app works on desktop and mobile
- OCR Accuracy: Powered by Azure Form Recognizer to convert PDF invoices into queryable data
- Modern Stack: React + Vite frontend, .NET 6 Web API backend, Azure Blob Storage, and SQL Server
- Secure: JWT-based authentication and role-based access controls
MatchFlow delivers real, measurable value by automating repetitive finance tasks—so you can focus on your business, not on paperwork.
-
One-Click Invoice Upload
Drag-and-drop or browse your PDFs in seconds—no fiddly forms required.
Why It Matters: Cuts upload time by up to 95%. -
AI-Powered OCR Extraction
Instantly pulls out invoice number, date, line items and totals via Azure Form Recognizer.
Why It Matters: Eliminates manual data-entry errors—>99% field accuracy in our tests. -
Automated PO Matching
Cross-checks extracted invoice data against your stored Purchase Orders.
Why It Matters: Flags mismatches (vendor, amount, quantities) before they hit your ledger—reduces payment errors by 90%. -
Real-Time Discrepancy Alerts
Any mismatch is pushed into an internal review queue and notifies your finance team instantly.
Why It Matters: Ensures exceptions are caught and resolved in minutes, not days. -
Secure Cloud Storage
All invoices live safely in Azure Blob Storage with role-based access controls.
Why It Matters: Keeps sensitive financial documents locked down and audit-ready. -
Interactive Dashboard & Reporting
Search, filter and export full audit logs, match-rate charts and spend summaries.
Why It Matters: Provides complete visibility into your payables pipeline—perfect for month-end close.
Database
Frontend
- React 19.1.0
- Vite (
@vitejs/plugin-react 4.4.1
)
UI / Styling
Cloud Services
Web Server / Proxy
Authentication
- JWT Bearer tokens
API Documentation
Local Dev & Scripts
- Docker Compose for local end-to-end testing
Testing
- xUnit (backend)
CI/CD
- GitHub Actions
- Fly.io automatic deploy
Monitoring
MatchFlow’s architecture is described in two C4-style component views plus a layer breakdown:
- System Context & High-Level Components
- Detailed Clean-Architecture Components
- Layer-by-Layer Breakdown
Who uses the system and the major “boxes” it interacts with
- Users (Invoice Managers) in their browser
- React SPA + Nginx (Fly.io container “React+Nginx”): serves UI, terminates TLS, forwards API calls
- .NET 6 API Gateway (Fly.io container “Backend”): hosts all Controllers and Services
- Redirector (Fly.io): 301-redirects
matchflow.app
→www.matchflow.app
- Azure Cloud Services:
- Blob Storage (PDF persistence)
- Form Recognizer (OCR)
- SQL Database (POs, invoices, audit logs)
- Service Bus (discrepancy messaging)
- Application Insights (telemetry & logging)
Internal layering and dependencies
- Controllers
- AuthController, PurchaseOrderListController, InvoiceListController, InvoiceMatchController, InvoiceUploadController
- Application Services (Use-Cases)
- CreatePurchaseOrderService
- MatchingService
- UploadInvoiceService
- JWT issuance & validation via UserService
- Ports / Interfaces
- IInvoiceRepository, IPurchaseOrderRepository
- IFormRecognizer, IBlobStorage
- IExceptionRecordRepository, IServiceBusClient, IUserService
- Infrastructure
- EF Core Repositories: InvoiceRepository, PurchaseOrderRepository, ExceptionRecordRepository (via AppDbContext)
- Azure SDK Clients: BlobStorageService, FormRecognizerClient, ServiceBusClient
- UserService (JWT key management & refresh logic)
- Domain Entities
- Invoice, PurchaseOrder, InvoiceLineItem, PurchaseOrderLineItem, ExceptionRecord, User
- Browser (React SPA)
- Pages: AuthPage, LandingPage, CreatePOPage, PurchaseOrdersPage, PurchaseOrderDetailsPage, DashboardPage, InvoicePage, AutoMatchPage, UploadInvoicePage, UploadResultPage
- Communicates over HTTPS+JWT with Nginx
- Nginx Reverse Proxy
- TLS termination, static-file serving, API forwarding
- Redirector
- 301 redirects apex domain →
www
- 301 redirects apex domain →
All inside the .NET API Gateway container
- AuthController
- PurchaseOrderListController
- InvoiceListController
- InvoiceMatchController
- InvoiceUploadController
- Use-Case Services
- CreatePurchaseOrderService
- MatchingService
- UploadInvoiceService
- Dependency-Inverted Ports
- IInvoiceRepository, IPurchaseOrderRepository, IFormRecognizer, IBlobStorage, IExceptionRecordRepository, IServiceBusClient, IUserService
- EF Core Repositories (Invoice, PO, ExceptionRecord)
- Azure SDK Clients (BlobStorage, FormRecognizer, ServiceBus)
- UserService (JWT management)
- Plain C# business entities: Invoice, PurchaseOrder, InvoiceLineItem, PurchaseOrderLineItem, ExceptionRecord, User
Figure 1: User logs in by entering username & password, then is taken to the main dashboard.
A simple, secure login step that grants access to the rest of the MatchFlow app.
Figure 2: Central dashboard where you can:
- Create a new Purchase Order
- Upload invoices
- Run Auto-Match and see results
- Quickly view all invoices and POs in one place
A single screen to kick off every step of your MatchFlow workflow.
Figure 3: Fill out the PO form, submit it, and immediately land on the detailed Purchase Order page.
A quick, end-to-end demo of creating a PO and reviewing its details in one seamless flow.
Figure 4: Cropped PDF showing invoice number, date, line items and totals used in our demo (all data is fictitious).
Figure 5: Upload your invoice PDF and instantly see its extracted details labeled “Ready to Match.”
Now you’re all set to run the auto-match and reconcile against your purchase orders.
Figure 6: The Auto-Match engine processes your invoice and then confirms a 100% match—every line item and the total perfectly aligned with your Purchase Order.
Instant peace of mind knowing your invoice is exactly what you ordered.
Follow these steps to get MatchFlow up and running locally via Docker Compose.
- Docker Engine ≥ 20.10
- Docker Compose ≥ 1.29
- A modern web browser (Chrome, Firefox, Safari, Edge)
Before running MatchFlow, you need to set up these Azure services:
-
Azure Blob Storage
- Create a storage account
- Create a container for PDF storage
- Get the connection string and container name
-
Azure Form Recognizer
- Create a Form Recognizer resource
- Get the endpoint URL and API key
Note: These Azure resources are required for PDF storage and OCR processing. You'll configure them in the
.env
file during installation.
-
Clone the repository
git clone https://github.com/datpham0412/invoice-processor.git cd invoice-processor
-
Create environment file
Copy or create
InvoiceProcessor.API/.env
with the following configuration:# Database Connection CONNECTIONSTRINGS__DefaultConnection=Server=(localdb)\\MSSQLLocalDB;Database=InvoiceProcessorDev;Trusted_Connection=True;MultipleActiveResultSets=true # Development Settings DISABLE_HTTPS_REDIRECT=true AZUREBLOB__ConnectionString= AZUREBLOB__ContainerName= FORMRECOGNIZER__Endpoint= FORMRECOGNIZER__ApiKey= # JWT Authentication JWT__Key=your-secret-key-here JWT__Issuer=matchflow JWT__Audience=matchflow-users JWT__ExpiresInMinutes=60
- The Docker Compose network
invoice-net
connects both services. - backend (host 8080 → container 80) reads your
.env
and runs in Production mode. - web (host 3000 → container 80) uses
VITE_API_URL=http://backend/api
.
Note: Populate the
AZUREBLOB__*
andFORMRECOGNIZER__*
keys in your.env
file with the Azure resource details you set up in the Prerequisites section.
From the project root:
docker-compose up --build
Run in background:
docker-compose up --build -d
View logs:
docker-compose logs -f
Stop services:
docker-compose down
Once up, the frontend is available at:
and the API listens on:
Attaching to backend-1, web-1
web-1 | 2025/07/03 02:36:11 [notice] nginx/1.28.0
backend-1 | info: Now listening on: http://[::]:80
backend-1 | info: Application started. Press Ctrl+C to shut down.
This project is licensed under the MIT License - see the LICENSE file for details.
For any inquiries, please open an issue in the GitHub repository.
Made by Dat Pham