Building a Modern Legal Case Management System: From Relational Schema to Role-Based Dashboards

Written by

in

Legal tech systems operate under uniquely demanding requirements: strict role segregation, chain-of-custody compliance, multi-version document drafting, and tamper-evident audit logging. When building a practice management platform for law firms and corporate legal departments, standard project management tools simply fall short.

In this post, we’ll walk through the architectural design, engineering decisions, and core workflows involved in building Apex Legal—a full-stack sovereign legal case management application built with PostgreSQL, Node.js (Express), and React.

🏛️ The Problem Space: Why Legal Workflows Need Specialized Tech

A law firm does not handle generic “tasks” or “tickets”—it manages Expedientes (Case Dockets). Within each legal docket, multiple stakeholders collaborate with radically different privileges:

  • Head Lawyers (Managing Partners / Admins) require executive oversight across practice areas (e.g., Federal Litigation, Adolescents / Juvenile Welfare, Corporate), advocate workloads, and final approval over court filings.
  • Junior Lawyers (Advocates) prepare legal drafts, review discovery materials, attend hearings, and record stenographic and audio transcripts.
  • Retained Clients require an isolated portal to inspect case milestones and download approved filings without ever seeing privileged internal attorney notes.

To solve this, we engineered an application around three foundational pillars: Strict Relational Data Modeling, a Layered Backend Architecture, and Role-Tailored Frontend Dashboards.


📊 1. Core Data Modeling: PostgreSQL Relational Schema

Rather than relying on loose document stores, legal compliance requires referential integrity, strong foreign key constraints, and relational indexing. Our architecture defines five central database entities:

  1. Users & Role Assignment: Houses credentials, state bar qualification numbers, and system roles (Admin, Advocate, Client).
  2. Cases (Expedientes): The central docket tracking practice area (Federal, Adolescents, Civil, Corporate), assigned junior advocate, client association, court jurisdiction, presiding judge, and case status.
  3. Deliverables & Document Versioning: Tracks formal iterations (e.g., v1.0 draft by Junior Advocate → v1.2 revised version → APPROVED by Head Lawyer → SUBMITTED to court).
  4. Transcripts: Associates isolated courtroom audio recordings (.mp3, .wav) with corresponding timestamped speech-to-text transcriptions for rapid keyword search and cross-examination review.
  5. Immutable Audit Ledger: A tamper-evident event store linked to each Expediente, capturing every creation, update, download, and login with user ID, role, IP address, and change payload.

⚙️ 2. Backend Architecture: Clean Layered Separation of Concerns

To keep the codebase maintainable and testable, the Node.js API layer was structured into strict operational layers:

Request → Express Routes → JWT & RBAC Middleware → Controllers → Database Models (DAO) → PostgreSQL

Key Highlights:

  • Data Access Layer (Models): Dedicated DAO classes (User.js, Case.js, Deliverable.js, Transcript.js, AuditLog.js) encapsulate all parameterized SQL queries away from HTTP controllers.
  • JWT Authentication & Security: Cryptographically signed tokens with 24-hour TTL, active status verification, rate limiting, and helmet security headers.
  • Role-Based Access Control (RBAC): Declarative route guards and case boundary verifiers ensure that client requests are strictly bounded to their own retained matters.

🖥️ 3. Frontend Engineering: Dynamic Role-Based Dashboards

A one-size-fits-all dashboard creates clutter and risks exposing sensitive operational metrics to clients. Built with React 18, Vite, and Tailwind CSS, the frontend dynamically evaluates the user’s role and renders a tailored workspace:

1. Head Lawyer (Admin)

Executive practice area metrics, staff oversight, and an interactive Deliverables Approval Queue with 1-click Approve/Reject controls for pending filings.

2. Junior Lawyer (Advocate)

Active assigned Expedientes, drag-and-drop document version uploader (v1.0 → v1.2), and hearing audio recordings with full stenographic transcripts.

3. Client Portal

Clean, distraction-free view of retained matters, direct downloads for approved court filings only, and verified attorney bar credentials.


💡 Key Takeaways

  • Domain-First Schema Design: Modeling concepts like version increments (v1.0 → v1.2) and isolated courtroom audio files directly in PostgreSQL prevents technical debt down the road.
  • Defense-in-Depth Security: Combining JWT tokens, declarative RBAC middleware, and query-level tenancy checks guarantees confidential legal data never leaks across boundaries.
  • Role-Tailored UX: Providing distinct dashboards for Head Lawyers, Junior Advocates, and Clients makes the software intuitive for every user without compromising security.

🚀 Update: Latest Architectural Additions

The system has recently been expanded with two major new capabilities to improve accessibility and deployment infrastructure:

1. Full UI Internationalization (i18n)

To support global legal practices and diverse clients, we introduced a seamless English / Spanish toggle built directly into the React frontend via a custom LanguageContext. This allows real-time, zero-reload translation across the entire application—dynamically switching role badges (Head Lawyer ↔ Abogado Principal), practice areas (Federal Practice ↔ Práctica Federal), and all dashboard widgets, without impacting the underlying backend database records.

2. Zero-Trust Network Infrastructure & Cloudflare Tunnels

To securely publish the application to a public domain without opening firewall ports, we migrated the legal_client and legal_server Docker containers directly into a shared bridge network alongside a cloudflared connector. This allows Cloudflare Zero Trust to route external HTTPS requests directly to the Nginx reverse proxy running inside the isolated Docker network, entirely avoiding host LAN hairpinning while keeping the Postgres database completely air-gapped from the public internet.

3. Dual-Track E-Billing (CFDI 4.0 & LEDES 1998BI)

To support complex cross-border or localized law firms, we engineered a unified billing architecture. The database now securely tracks timestamped itemized time logs and third-party disbursements using universal UTBMS task codes. From a single UI, the application can generate highly strict, machine-readable XML tax invoices for the Mexican SAT (CFDI 4.0) or standard international LEDES 1998BI text formats. Furthermore, a custom Node.js PDF rendering engine instantly translates this data into a beautiful, human-readable “Shadow Invoice” PDF companion grouped by case matter.

4. US-Native Terminology & Global Firm Settings

Transitioning the software into a versatile SaaS platform, we scrubbed the English localization of rigid “Expediente” phrasing, shifting to standardized US “Matter” management nomenclature. This is underpinned by a new “Firm Settings” global configuration module, allowing the administrative Head Lawyer to toggle the operating jurisdiction (US vs Mexico) and set a default currency, adapting the compliance engines and user interface dynamically based on regional requirements.

5. Comprehensive Pre-Bill Reporting & PDF Architecture

Moving beyond standard invoices, we introduced a highly requested feature for law firms: the Pre-bill & Timeslips Summary Report. This report provides a birds-eye view of all unbilled work-in-progress (WIP). The PDF engine intelligently iterates through all pending DRAFT invoices, generating a nested, highly detailed worksheet for each invoice that itemizes its time entries (tasks) and third-party expenses, complete with LEDES codes (UTBMS). It also aggregates a global “Unbilled Slips” section for any stray time entries not yet assigned to an invoice.

We also implemented a sleek “Dark Aesthetic” for our PDFs, dynamically injecting a dark slate background (#111827) and light text (#e5e7eb) using a custom doc.on('pageAdded') listener in pdfkit, proving that legal documents don’t always have to be plain white paper.


🚧 Obstacles & Technical Challenges

Scaling the complexity of our PDF engine did not come without some significant technical hurdles:

  1. PDFKit Multi-line Text Wrapping & Overlapping Rows: When generating our multi-column tables, long text (like combined Task/Activity codes or verbose descriptions) would automatically wrap to a second line. Because the Y-coordinate advancement was hardcoded to a single line height, this wrapped text bled directly into the row below it, creating garbled, overlapping text. The Solution: We engineered a clever functional wrapper around doc.text() that tracks the maximum Y-coordinate reached by any column in the current row (currentRowMaxY), ensuring the cursor only advances after the tallest cell has finished rendering.
  2. Unicode Font Support (Garbled Characters): We noticed that when our database contained time entries with Cyrillic (Russian) text or Spanish accents, the generated PDFs showed garbled “unknown character” squares. We discovered that PDFKit’s default Helvetica font only supports the Latin-1 (WinAnsiEncoding) charset. The Solution: We downloaded and explicitly bundled the Roboto TrueType font into our Docker image, registering it with PDFKit to seamlessly support all Unicode characters natively.
  3. Script Injection Syntax Errors: While trying to automate the injection of our row-height tracking wrapper across multiple endpoints using a Node.js text-replacement script, we accidentally injected a literal unescaped \n into the controller file. This seemingly minor syntax error brought down the entire Node.js server container, which in turn broke frontend authentication (since it couldn’t reach the backend to validate tokens). The Solution: We quickly reverted the change, used sed to surgically remove the syntax error, and learned a valuable lesson about the dangers of using raw string manipulation (instead of AST parsing) on live source code!

6. Architectural Modernization & Multi-Advocate Teams

Today, we executed a massive multi-step architectural refactor to ensure our growing SaaS platform remains secure, scalable, and maintainable. This overhaul addressed five critical areas of technical debt and user experience:

  • Service Decoupling: Our billingController.js had ballooned to nearly 1,000 lines. We decoupled all the heavy document generation logic by extracting it into dedicated pdfEngine.js and xmlEngine.js services.
  • Frontend State Management with React Query: We stripped out brittle, manual useState and useEffect fetching loops across our React dashboards, replacing them with @tanstack/react-query. This dramatically simplifies N+1 fetching logic and provides seamless caching and background data invalidation.
  • Strict Payload Validation (Zod): To harden security against malformed requests and overflow attacks, we introduced a global Express middleware that intercepts requests and passes them through strict Zod schemas, enforcing exact UUID structures, string boundaries, and enums before they ever reach our database layer.
  • Database Versioning via Knex.js: Transitioning away from raw SQL scripts, we integrated Knex.js for strict migration control. We successfully baselined the existing production schema and tracked missing tables using Knex’s type-safe schema builder, ensuring all future schema changes are strictly versioned.
  • Team-Based Case Collaboration: We resolved a major constraint where only a single Junior Lawyer could be assigned to a case. By generating a case_advocates junction table, refactoring our PostgreSQL models to use json_agg arrays, and upgrading our Access Control middleware, cases can now be seamlessly shared among entire teams of advocates!

⚖️ Deploy Sovereign Legal Tech for Your Firm

Are you evaluating legal practice management platforms but hesitant about public cloud compliance, vendor lock-in, and ballooning per-seat pricing? At OC Computer Fix, we engineer and deploy turnkey, sovereign legal platforms tailored to California law firms across Orange County, Los Angeles, and San Diego.

Ensure 100% adherence to California State Bar Rule 1.6, keep client privileged communications air-gapped on your own dedicated server, and experience our full interface live. Explore our dedicated Sovereign Legal AI & Case Management Platform or Request 14-Day Live Demo Access today.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *