Client platform (in progress)

Legal case platform

Filing a law practice’s email against the right case, where the interesting half turns out not to be classification at all, and a wrong answer misfiles a document into another client’s matter.

  • Python
  • FastAPI
  • PostgreSQL
  • pgvector
  • Vertex AI
  • Gmail API
  • OAuth 2.0 + PKCE
  • Angular PWA
Legal case platform Incoming mail is filed against a case, not a topic. Cheap rules resolve the obvious, a model sees only the remainder, and a person confirms before any label is applied. TWO DIFFERENT PROBLEMS SHE APPROVES EXT Mailbox metadata only, no body Rules first model sees the remainder Case type small closed set Which case entity resolution Confirm on chat reference id, never the body Label applied Where the risk is The firm's mailbox Pipeline step
Cheap rules resolve the obvious and the model only sees the remainder. The two highlighted boxes are where the risk sits: identifying which matter an email belongs to, and the human confirmation that stands between a guess and a filed document.

Overview

An in-progress platform for a small law practice that wants its case work to stop living in a mailbox. The first deliverable is deliberately narrow: file incoming email against the right matter, ask a human to confirm, and apply the label. Everything the practice eventually wants, a procedural deadline engine, drafted replies, questions answered over the document archive, sits behind that one loop working. Client details are abstracted here; the engineering is not.

Problem

The design assumption was wrong, and finding that out was the most valuable hour of the project. The practice does not sort mail by topic. It sorts by matter, with one label per case, and that splits into two problems that only look like one. Deciding the type of case is ordinary classification over a small closed set. Deciding which case is entity resolution over a set that grows with every new client, and a model choosing between a couple of dozen options from a sender and a subject line is the wrong instrument for it. One client turning up with two matters of different types settles it: the sender address alone can never decide. And the consequence of guessing wrong is not a tidy-up job, it is a document filed into another client’s matter, which in a practice handling criminal work is a confidentiality problem rather than an inconvenience.

Solution

Split the two problems and use a different mechanism for each. Cheap deterministic rules run first and resolve the obvious, so the model only ever sees the remainder, and high-confidence rules can be promoted out of the model entirely over time. The model is allowed to abstain, and abstaining is not a failure: it means asking the human instead of inventing an answer. Every proposal goes to a person on a chat channel for confirmation before any label is applied, and each confirmation or correction feeds a growing rules document, so the system gets more deterministic with use rather than more dependent on the model.

Architecture

A Python and FastAPI service holding the mail integration, the classifier and a case registry, with PostgreSQL and row-level security because per-matter access control is a legal requirement here rather than a feature. Mail is read by polling the history API rather than push, which avoids standing up a message queue for no benefit at this stage, and the poller detects an expired cursor and re-baselines instead of silently stalling. Refresh tokens are encrypted at rest and the token store was built multi-tenant from the first commit. Document search, when it arrives, is self-hosted pgvector in the same database rather than a managed vector service, which costs nothing per query against an always-on endpoint billing by the hour.

Key decisions

The evaluation harness was written before the classifier, on purpose, so that any future backend is measured from its first commit against the same interface. It scores accuracy and coverage together, always against a naive baseline, because a model that beats a majority-class guess by a few points is not a product. It also separates two errors that are not equally bad: real mail discarded is never seen again, while junk given a real label merely costs an interruption. Categories are configuration rather than constants, which is why the taxonomy discovery meant rewriting a data file instead of the classifier. Model reasoning is switched off for classification and there is a test asserting it, because that reasoning is billed as output at several times the visible token count.

Challenges

The privacy guarantee cannot come from the permission scope. Applying a label requires broad mailbox access and no narrower scope exists, so promising to read only headers has to be enforced by the code and backed by a written commitment, not implied by the consent screen. Then a specific trap: the mail API returns a short extract of the message body even when asked for metadata only, so requesting metadata is not by itself sufficient and the extract has to be discarded explicitly before anything is stored. Only a reference identifier, the sender and a truncated subject ever reach the chat channel; the body never does. The deadline engine has the same shape of risk and is being handled the same way: procedural time limits are not encoded from memory, because a miscounted criminal deadline is a malpractice-grade error, so the lawyer is the source of truth for the rules and the system only applies them mechanically.

Outcome

In progress. The mail integration, label application, the evaluation harness and the first classification level are built and tested; matter identification and the confirmation bot are the current work. It is included here for the judgement rather than the finish: recognising that half the problem was misframed, refusing to solve an identity question with a classifier, and treating access control and data minimisation as design constraints to settle before indexing anything rather than as features to add later.

Wondering if Daniel is a fit? Ask his assistant, hiring, contracts, or collaboration.