Architecture

A boring stack, designed to stay boring.

Five services. One database. One codebase for API and worker. A gateway that lets you swap LLM providers without touching the service layer. This is what’s under the hood.

01 · Browser02 · API + Worker Plane03 · Data Plane04 · LLM ProvidersNext.js 15 · App RouterMarketing site · Product UI · Server components + React 19Deployed on Railway · standalone Node outputFastAPI · Backend/api/v1/* REST endpoints28 service functions, uniform signatureLLM tool registry maps 1:1 to servicesJWT auth · org-scoped queriesAlembic migrations · Pydantic validationArq WorkerSame codebase as backendRedis-backed job queueDocument parsing (PDF, DOCX)Chunking + embedding pipelineScheduled compliance sweepsPostgres 16pgvector extension for embeddingsorganization_id on every rowDocuments · Contracts · EntitiesIP · Litigation · Filings · HoldsOrg preferences · feedsRedisArq job queueSession cacheRate limitsBucketS3-compatibleShared by API + workerRegion-lockedKeys only in DBLLM Gatewayapp/llm/factory.pyOne env var swaps providersOpenRouterSonnet 4.5gpt-4o-miniEmbeddingsOpenAI-shape APIMiniMaxM2.7M2.7-highspeedAnthropic-compatNative SDKObject storage (S3)Shared by API + workerUploaded PDFs · DOCX draftsOnly object keys in PostgresRegion-locked by tenantHTTPS · JWT authTool-use loopSQLAlchemy

Rendered live as SVG · zoom, screenshot, and paste into your board deck.

Design principles

Six non-negotiables.

The invariants we ship every commit against. Break one and the PR doesn’t merge.

One database, all objects

Postgres 16 with the pgvector extension. Contracts, entities, embeddings, and audit logs all live in the same instance. No separate vector DB, no sync jobs, no drift.

The service function is the atom

Every capability is a Python function with the signature (args, ctx) → dict. The REST layer and the LLM tool registry both call the same function. There is one source of truth.

LLMs behind a gateway

All model calls go through app/llm/factory.py. OpenRouter is default; MiniMax M2.7 is one env var away. Retries with exponential backoff live in the wrapper, and every call is grounded in the customer's own documents.

Multi-tenancy is a filter, not a hope

Every table has organization_id. Every query filters by it. The RequestContext carries the org through the whole stack; it is impossible to write a service function that forgets to scope its query.

Migrations, not ORM magic

Alembic manages every schema change. Base.metadata.create_all() is banned in production. If the diff isn't in a migration, it doesn't ship.

AI disclaimers on generated work

Every LLM-generated contract, offer letter, and review carries a visible AI-generated notice reminding the reader to have it reviewed by qualified counsel. It's a liability boundary, not a UX detail.

The data model

14 tables. One shape.

Every row carries an organization_id. Every query filters by it. Multi-tenancy is a database invariant, not a hope pinned to a middleware.

TableNotes
organizationsOne row per tenant
legal_entitiesEvery entity you operate under
shareholdersCap table entries
contractsMSAs, SOWs, NDAs, subscriptions
documentsUploaded files with parsed text
document_chunksText + 1536-dim pgvector embedding
ip_assetsTrademarks, patents, copyrights
litigation_casesMatter records with filings
regulatory_filingsGST, ROC, ESI, PF, custom cadences
legal_holdsCustodians, scope, acknowledgement log
vendor_msasVendor paper hub
chat_sessionsCopilot conversations
chat_messagesMessage ledger with tool calls
org_preferencesPer-tenant settings · jurisdictions · feeds

Deployment

Five services. One project. One command.

LawDep ships as five Railway services in one project. Volumes for uploads, internal DNS between services, health-checks on every deploy.

ServiceImage or buildRole
postgrespgvector/pgvector:pg16Data plane
redisredis:7-alpineQueue + cache
backendbackend/DockerfileFastAPI · uvicorn
workerbackend/DockerfileArq worker · same image
frontendfrontend/DockerfileNext.js standalone

Security posture

Where we are, and where we’re going.

Shipping today

  • · Multi-tenant isolation on every table
  • · Encrypted at rest via managed Postgres
  • · TLS everywhere between the browser and API
  • · JWT auth with bcrypt hashing and login lockout
  • · AI disclaimers on generated contracts, letters, and reviews
  • · Citation verification against US Code, CourtListener, and eCFR
  • · 17-stage matter lifecycle with append-only audit
  • · SLA breach tracking with penalty calculation

On the roadmap

  • · SSO (SAML / OIDC) for enterprise teams
  • · SCIM provisioning
  • · SOC 2 Type I → Type II certification
  • · EU and India data residency
  • · Full audit export as evidence for e-discovery

Try it

Stop running a legal department out of a shared drive.

Click through a live demo workspace — no login, no credit card. Browse contracts, run an AI review, watch it flag an invented citation. When you’re ready, we’ll stand up a workspace for your team.

Or explore a free tool: compliance calendar · watch AI catch a fake case

LawDep is not a law firm and does not provide legal advice. All AI-generated content is marked as such and should be reviewed by qualified counsel before use.