AI Automation
30+ parallel LLM pipelines turn 8 kinds of legal document into one auditable data model
A wealth-management firm’s legal documents arrive as PDFs of wildly different shapes — wills, trusts, insurance policies, powers of attorney. This is the engine that reads them, classifies them, and writes them into a database an operations team can trust.
Stack
- n8n
- Supabase
- PostgreSQL
- OpenAI
- TypeScript
- Node.js
65+
PostgreSQL tables
200+ JSONB fields, 15+ entity types resolved
30+
parallel LLM extraction pipelines
30 prompt templates, across 8+ document types
2→8 / 10
security score
reliability 3/10 → 7/10 alongside it
The problem
Overview
A wealth-management firm’s legal paperwork — wills, trusts, insurance policies, powers of attorney, healthcare proxies, asset schedules, datasheets — arrived as unstructured PDFs, reviewed by hand, and typed up into Word and PowerPoint documents by an operations team.
Owned solo over seven months: an event-driven pipeline that ingests any of 8+ document types, classifies them, extracts their content through parallel LLM passes, and writes the result into a data model auditable enough for a wealth-management firm to actually rely on.
Architecture
How a document becomes structured data
One webhook, one dispatch workflow, four modules, thirty parallel extraction pipelines.
Inbound webhook — any of 8+ unstructured legal document types
Centralised dispatch workflow — n8n orchestration, event-driven
Classified into 4 core modules
- Data Sheet
- Insurance
- Assets
- Trust Flow Diagram
30+ parallel LLM extraction pipelines — across 30 specialised prompt templates
Structured into type-safe JSONB — three-tier confidence scoring: validated / not_validated / missing
PostgreSQL write — deterministic entity resolution, provenance tracked
65+ tables, 200+ JSONB fields, entity resolution held across 15+ entity types — every extracted fact traceable back to the document and pipeline pass that produced it.
The architecture trade-off
Why confidence-scored JSONB, not a rigid schema
Eight document types, each with their own fields, could mean eight rigid table schemas. Why route them all through a type-safe JSONB layer instead?
The documents themselves are not uniform — a trust has fields an insurance policy never carries, and a rigid per-type schema means a migration every time a new document variant surfaces.
Type-safe JSONB with a three-tier confidence flag (validated / not_validated / missing) on every field lets the schema stay flexible while the DATA stays trustworthy — a downstream consumer can tell the difference between "the model extracted this and it checked out" and "this field is present but unverified," which a rigid schema has no way to express at all.
The alternative
A dedicated relational schema per document type, migrated as new variants appear.
What it cost
JSONB fields are less queryable than dedicated columns — the trade the confidence-scoring layer and the 65+ table data model exist to manage.
The hardening pass
Outcome
Selected results
65+
PostgreSQL tables
200+ JSONB fields
30+
parallel LLM extraction pipelines
30 prompt templates, 8+ document types
15+
entity types resolved
deterministic, conflict-free merge
23–35 → 5–8
queries per page load
after the hardening pass
Retrospective
What I would take to the next build
Confidence scoring is cheaper than perfect extraction — A three-tier flag on every field bought more trust than chasing 100% extraction accuracy would have, and it degrades honestly when the model is wrong.
Hardening is a measurable, not a vibe — Security and reliability moved from named scores (2/10, 3/10) to named scores (8/10, 7/10) — the same discipline this site’s own honesty rule asks for applied to an internal platform, not just a public one.
Built as sole engineer on the pipeline, data and integration layer over seven months, syncing weekly with the client’s leadership. Client and infrastructure identifiers omitted.
