The question this engagement had to answer
*Can a firm move live, privileged, deadline-bound matters into custom software without losing a limitation date, a conflict, or the ability to prove who saw what?*
Firms of this size sit in a specific trap. Off-the-shelf practice management handles time, billing and basic matter records, and handles them adequately. It does not handle the firm's actual work — the immigration application with 40 evidence items and a government portal deadline, the client with six related matters across two entities, the paralegal workflow that currently lives in a spreadsheet and one person's memory.
So the firm bolts spreadsheets onto the practice management system. That works until someone leaves.
What was hard
The tradeoff: replace practice management, or sit beside it. The tempting scope is to replace everything, including time recording and billing. We reject that. Billing is regulated, deeply embedded, integrated with the firm's accounting, and replacing it puts revenue collection at risk to solve a problem that is not about billing. The build sits beside practice management and integrates. It owns matter workflow, documents and evidence. Practice management keeps owning client records, time and billing, and remains the system of record for both. That decision costs us. Integration is harder than ownership, reconciliation is a permanent obligation, and two systems can disagree. We take that cost because the alternative risks the firm's cash collection.
The rejected alternative: one flat "case" record. Almost every first draft of a legal data model has a case with a client, a status and a set of documents. It breaks within a month. A client is not a person — it can be a company, a family group, or an individual who is also a director of a corporate client. A matter has multiple parties with different roles, some of whom are adverse. Documents belong to a matter, but privilege attaches to the communication, not the folder.
What broke: our first retention implementation. We built retention as a scheduled deletion job against a retain_until date. It was wrong in a way that took a real file to expose. Retention periods restart on events — a matter reopening, a complaint, a regulatory hold — and destruction must be suspended entirely when litigation is reasonably anticipated. A job that deletes on a date will eventually destroy something under hold. We rebuilt it as an event-driven schedule with hard legal-hold blocking and a two-person approval before any irreversible destruction.
Deadlines are the real risk surface. In immigration and litigation work, a missed date is a negligence claim. Any feature touching dates gets treated as safety-critical, not as a convenience.
What we did
1. Modelled matters, parties and relationships properly. The core model separates four things that flat systems collapse into one. Entity — a person or organisation, existing once across the firm, regardless of how many matters they touch. Matter — the unit of work, with a matter type, a responsible fee earner, a jurisdiction and a lifecycle state. Party role — the join between an entity and a matter, carrying the role: client, opponent, dependant, sponsor, witness, third party, intermediary. Adverse roles are flagged at this layer, which is what makes conflict checking possible. Task and deadline — hung off the matter, with a source (statutory, court-ordered, internal) and an owner. Matter types carry their own required fields and evidence checklists. An immigration application matter demands items a probate matter does not. This is the part that makes immigration software different from generic law firm software: the checklist is the work.
2. Built conflict checking into matter opening, not alongside it. Conflict checking runs at three moments: enquiry, before engagement, and whenever a new party is added to an existing matter. It searches entities, former names, trading names, related corporate entities, and previously closed matters — including matters the searching user has no permission to open. That last point is the design problem. The search must surface that a conflict exists without disclosing the confidential matter causing it. So results return at two levels: a hit visible to the searcher showing that a potential conflict exists and who must clear it, and full detail visible only to the conflicts team or the responsible partner. The clearance decision, its reasoning and the approver are stored permanently on the matter.
3. Made privilege and access control explicit rather than role-based. Role-based access alone is not sufficient in a law firm. Two things break it: information barriers between teams acting on opposite sides, and privileged communications that must stay narrower than the matter team. Access resolves through three layers, evaluated in order: matter team membership, an ethical-wall exclusion that overrides membership, and a document-level privilege flag that narrows visibility further within the team. A privileged advice note is visible to the responsible partner and the named fee earners, not to everyone with matter access. Break-glass access exists, because emergencies exist. It requires a stated reason, it notifies the responsible partner immediately, and it is written to the audit log as a distinct event type.
4. Built the audit trail as an append-only event log. Every read of a document, every access grant, every field change, every deletion, every break-glass event. Append-only, no update path, no delete path, retained beyond the matter's own retention period. This is not a compliance checkbox. It is the artefact the firm produces when a client asks who saw their file, when a regulator asks how a conflict was cleared, or when an insurer asks what happened before a claim. If the audit trail is reconstructible from application logs rather than stored as first-class events, the answer is not defensible.
Architecture
flowchart TB
subgraph Client["Fee earner + paralegal"]
UI["Web app<br/>matter workspace"]
end
UI --> GW["API gateway<br/>authn + session"]
GW --> AUTHZ["Authorization service<br/>matter team + ethical wall + privilege flag"]
AUTHZ --> MAT["Matter service<br/>entities, parties, roles, lifecycle"]
AUTHZ --> DOC["Document service"]
AUTHZ --> CONF["Conflict check service"]
AUTHZ --> DEAD["Deadline + task service"]
MAT --> DB[("Postgres<br/>matters, entities, party roles")]
CONF --> DB
CONF --> IDX[("Search index<br/>names, aliases, former names")]
DOC --> S3[("Encrypted object store<br/>versioned, immutable objects")]
DOC --> RET["Retention engine<br/>event-driven schedules"]
RET --> HOLD{"Legal hold<br/>active?"}
HOLD -->|"yes"| BLOCK["Destruction blocked<br/>logged"]
HOLD -->|"no"| APPR["Two-person approval<br/>then destroy"]
DEAD --> NOTIF["Notification + diary service"]
MAT <-->|"sync: clients, matter numbers"| PMS["Practice management system<br/>time + billing, system of record"]
DOC -.-> AUDIT[("Append-only audit log")]
MAT -.-> AUDIT
CONF -.-> AUDIT
AUTHZ -.-> AUDIT
RET -.-> AUDITThe authorization service sits in front of everything. No service is reachable without an access decision, and the decision is one code path, not a check repeated in each service. A permissions model implemented four times is a permissions model with four different bugs.
Documents are immutable and versioned. A new version creates a new object. Nothing is overwritten, because a document that changed without a record of the change is a document that cannot be relied on in a dispute.
Practice management stays the system of record for clients, matter numbers and billing. The integration syncs both ways on a defined field set, with a nightly reconciliation report naming every divergence. We assume the systems will disagree and make disagreement visible rather than pretending it cannot happen.
How we evaluated it
The eval set. Twenty to forty real, anonymised matters supplied by the firm, spanning the messiest cases they have: a client who is also a director of an opposing company, a matter reopened after closure, a family group with shared and separate matters, a matter with a document under legal hold, a matter with a statutory deadline that moved. Every one is loaded into the system and every one must model cleanly without a free-text workaround. A matter that only fits in a notes field is a data model failure, and we find those before rollout.
The metric that mattered: conflict-check recall. Not precision. We measure recall against a set of known historical conflicts the firm has already identified, and we require that the system catches every one. False positives cost the conflicts team minutes. A false negative costs the firm a matter, a client and possibly a claim. We tune aggressively toward over-flagging, including fuzzy and phonetic name matching, and we accept the review burden.
The second measured number is deadline integrity: every statutory or court deadline in the migrated set present, correct, owned by a named person, and firing its reminders. This is checked by reconciliation against the old diary, item by item, not by sampling.
Latency where it is felt. Two interactions are gated on p95: matter workspace load and document open. Fee earners abandon a system that is slower than the shared drive, and adoption failure is the most common way legal software dies. Conflict checks run asynchronously with a visible progress state, because thoroughness matters more than speed there.
Failure modes and what happens when the system is wrong.
*A conflict is missed.* Containment: conflict checking is one of three controls, not the only one — matter opening still requires partner sign-off, and every clearance decision is logged with reasoning so a missed conflict is traceable and reviewable rather than invisible.
*A deadline reminder does not fire.* Containment: reminders are generated from a scheduled job with a heartbeat monitor; a missed run raises an operational alert. Deadlines also appear on a daily digest, so silence is itself visible.
*Someone accesses a file they should not have.* Containment: the access is recorded as a distinct audit event, break-glass notifies the responsible partner in real time, and the firm gets a weekly anomalous-access report. The system cannot always prevent it; it can always show it.
*Practice management and the case system disagree.* Containment: nightly reconciliation, divergences named in a report, and practice management wins on client and billing fields by rule.
How we measured. Migration and deadline-integrity checks are run against the firm's own source data and signed off by the firm, item by item. Nothing is sampled and nothing is estimated.
What we are not claiming. We do not claim a time saving, a utilisation improvement or a revenue figure for this scenario. Those depend on how the firm works, not on the software. We also do not claim the system prevents negligence — it reduces the number of places a date can hide.
What we would do differently
We would migrate one practice group, not the firm. On an early rollout we migrated everything at once because the firm wanted a clean cutover date. Two practice groups discovered model gaps in the same week and both were blocked. Phased rollout by practice group is slower, less satisfying, and correct.
We would build the retention engine after the first real destruction request, not before. We built it early, from the policy document, and it was wrong because policy documents describe the ordinary case. The exceptions — holds, reopenings, complaints — are the whole problem, and they only became concrete when a real file needed destroying.
We would spend more of the Blueprint with paralegals and less with partners. Partners describe how matters should run. Paralegals know how they actually run, where the spreadsheets are, and which fields get filled with nonsense because the real information has nowhere to go. The second group produces a better data model.
We would set the conflict-check threshold looser at launch and tighten it with evidence. We launched one build tuned for a manageable review volume, and it was tuned against assumptions rather than the firm's real name distribution. Starting noisy and tightening from data is the safer direction of travel.
What is still running
Reference work in this area continues on the parts that are never finished: better corporate-group resolution for conflict checking, structured extraction from incoming correspondence so evidence checklists update themselves, and matter-type templates for additional immigration categories. Anything touching automated document generation moves slowly and stays behind human review, because a generated document that goes out wrong is the firm's liability, not the software's.