← All work
LedgerDrop
Invoice processing with a human in the loop. An async FastAPI pipeline extracts and validates invoices, and a Next.js review screen handles the ones it isn't sure about.
- Role
- Full stack developer
- Team
- Solo
- Status
- Live
- Links
- Live app ↗ · Code ↗

Problem
- Invoices arrive as PDFs and scans in no fixed format, and the data that matters (supplier, dates, line items, totals) has to end up in a database that can be trusted.
- Fully automatic extraction is never fully correct, so the app is built around review rather than pretending the model is always right.
What I built
- FastAPI service with an async upload endpoint: the file is stored, a processing job is queued, and the client polls job status instead of blocking on the request.
- Extraction through the OpenAI API, then validation; invoices the pipeline is uncertain about are routed to a human review queue instead of being saved as-is.
- Next.js and TypeScript review screen to approve, reject or correct extracted fields next to the source document, with a full audit trail.
- PostgreSQL through SQLAlchemy with Alembic migrations. Deployed with Docker on Render, with uploaded files stored in Cloudflare R2.
Key decisions
- A status-driven job model instead of one long request, so a slow or failed extraction never takes the upload down with it.
- Validation rules run before a human sees a document, so review time goes to genuine ambiguity rather than arithmetic.
- Every extracted field keeps its origin, so a correction is traceable instead of silently overwriting the model's output.
Stack
- FastAPI
- SQLAlchemy
- PostgreSQL
- Alembic
- Next.js
- TypeScript
- Docker
- Render
- Cloudflare R2
- OpenAI API