Skip to content
All work

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
Still: inbound scanned documents OCR'd, scored by practice area, and routed to staff with a human-review fallback lane.

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

  1. Arrive

    From a monitored inbox, a direct upload, or a stored file.

  2. Read

    Asynchronous OCR, so multi-page scans do not block anything.

  3. Score

    Scored against each practice area — see below.

  4. Review when unsureHuman

    Low confidence goes to a review inbox rather than a best guess.

  5. Route and claim

    Emailed to the right person with a signed one-click claim link, and logged as an audit row.

  6. 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.