Case study
Document Classification & Routing
OCR pipeline that classifies inbound legal faxes by practice area and routes each to the right staff, with human fallback and escalation.
- Role
- Lead developer
- Domain
- Data & Document Intelligence · Automation & Agents · Cloud & Production
- Stack
- Python · FastAPI · AWS Textract · Amazon S3 · SQS / SNS
- Result
- ~93% routing accuracy
Overview
A service that reads every inbound fax at a multi-practice law firm, works out which practice area it belongs to, and sends it to the right person — and hands it to a human instead whenever it is not confident.
The problem
Faxes arrived as unlabelled scans and were sorted by hand. Slow, but the real cost was risk: a misrouted legal document can sit unseen in the wrong inbox while a deadline passes.
One document, end to end
Arrive
From a monitored inbox, a direct upload, or a stored file.
Read
Asynchronous OCR, so multi-page scans do not block anything.
Score
Scored against each practice area — see below.
Review when unsureHuman
Low confidence goes to a review inbox rather than a best guess.
Route and claim
Emailed to the right person with a signed one-click claim link, and logged as an audit row.
Escalate
Unclaimed documents are re-sent to administrators on a schedule until someone owns them.
What the score is made of
Rules, not a trained model — every routing decision can be explained line by line.
- Keywords, in context
- Longer phrases weigh more than single words, and matches in the header weigh more than the body.
- Names
- A named lawyer or staff member is the strongest signal, boosted further in a signature, cc or attention line.
- Document type
- Recognised document patterns — a medical report, mortgage instructions — push toward their practice area.
- Confidence
- The final score maps to a confidence band, with a fixed tie-break order when areas score level.
My Role
Role
Lead developer
Contribution
- Built three intake paths — inbox polling and REST upload — with async OCR over a queue
- Built a weighted scoring engine over keywords, staff names and document type, weighting header and signature context
- Routed low-confidence documents to human review instead of guessing
- Added signed claim links, an audit trail, and scheduled escalation for unclaimed documents
Team Context
Lead developer, roughly 19 of 22 commits.
Decisions
Weighted rules instead of a trained classifier.
There was no labelled history to train on, only a few practice areas, and a client who needed to understand and adjust the routing. Rules were explainable on day one.
- Instead of
- A trained text classifier
- An LLM per document
Uncertain documents go to a person.
A confident misroute is worse than a slow correct one. The fallback costs a few minutes of someone's time; a lost document can cost a deadline.
- Instead of
- Always route to the top score
Results
~93%
routing accuracy
~1,500
documents in production
45–60s
end to end per document
Limits
Accuracy was measured on test samples by me, but the labelled set and scoring script are not committed alongside the code, so it cannot be independently re-run. The rules need manual upkeep as staff and document types change, and the system covers the three practice areas that were actually configured.
What I'd Improve
- Commit the labelled evaluation set and a scoring script, so accuracy is reproducible. First fix.
- Use claim data as labels. Every claimed document records where it truly belonged — a free training set for learning the weights instead of hand-tuning them.
- Add automated tests around the scoring, where a small weight change can silently reroute a class of documents.