TrialBridge AI

A clinical-trial matching dashboard that turns dense eligibility criteria and scattered patient records into a prioritized, explainable shortlist for research coordinators.

Inspiration

Clinical trials fail for a frustratingly mundane reason: they cannot find the right patients.

Roughly 80% of trials miss their enrollment timelines, and a huge share of that delay comes from manual, error-prone matching work. Coordinators spend hours per patient flipping between a protocol PDF and an EHR, mentally checking:

"Is the HbA1c in range? Is the eGFR above the cutoff? Are they on an excluded medication?"

We wanted to take that mechanical matching work off the coordinator's plate, not to replace their judgment, but to give them a prioritized, explainable shortlist so they can spend their time on the patients who actually have a chance of qualifying.

What it does

TrialBridge AI is a clinical-trial matching dashboard for research coordinators. It:

  • Ingests trials and their structured eligibility criteria (inclusion and exclusion), each with a measurable field, operator, and threshold.
  • Ingests patients along with their conditions, medications, and lab results.
  • Runs a deterministic matching engine that evaluates every patient against every active trial and produces a match score, a status, and, critically, a per criterion explanation of why each rule was met, not met, or missing data.
  • Surfaces results in a dashboard: active trials, patients screened, high confidence matches, and a queue of coordinator tasks (e.g. "missing lab needed to confirm eligibility"). > Every screen carries a clear disclaimer: the output is decision support, not a medical determination. A human coordinator confirms every match.

How we built it

The stack is a single Next.js 16 (App Router) application written end to end in TypeScript.

Layer Choice
Database Amazon Aurora PostgreSQL
ORM Drizzle ORM with the pg driver
DB auth AWS IAM authentication via Vercel OIDC, with no static password anywhere
UI Server Components for data heavy pages; matching results rendered as prioritized cards and tables

Schema: a normalized model of organizations, users, trials, eligibility_criteria, patients, patient_conditions, patient_medications, lab_results, matches, and match_criteria_results.

The matching engine

The core is a deterministic, explainable scoring function, not a black box. For a patient p and trial t with criteria set C_t, each criterion c is evaluated to one of three states:

$$ \text{eval}(p, c) = \begin{cases} 1 & \text{- met;} \ 0.5 & \text{ - missing data;} \ 0 & \text{ - not met;} \end{cases} $$

The match score is the weighted average across all criteria, scaled to a percentage:

$$ \text{score}(p, t) = \frac{\sum_{c \in C_t} w_c \cdot \text{eval}(p, c)}{\sum_{c \in C_t} w_c} \times 100 $$

The half credit term for missing data is the key design decision. A patient missing a single lab value is not the same as a patient who clearly fails a hard exclusion:

Case Outcome
Missing a lab value Becomes a task: "order this lab"
Fails a hard exclusion Filtered out, regardless of overall score

A hard exclusion criterion being met forces the status to ineligible no matter the numeric score; the engine never "averages away" a disqualifier.

Each evaluation is persisted to match_criteria_results, so the dashboard can show the coordinator exactly which rules drove the score.

Challenges we ran into

The biggest challenge wasn't the application logic, it was database connectivity.

The app initially expected a DATABASE_URL connection string, but our database used Amazon Aurora PostgreSQL with IAM token authentication, which provides no static URL or password. The page crashed on every database call.

Getting IAM auth working end to end was a multi step battle:

  1. Rewired the Drizzle connection to use @aws-sdk/rds-signer and awsCredentialsProvider, generating a short lived auth token as the password at connection time.
  2. Hit AccessDenied: Not authorized to perform sts:AssumeRoleWithWebIdentity, a trust policy mismatch between the Vercel OIDC identity and the AWS IAM role.
  3. Stood up a clean AWS environment from scratch: OIDC identity provider, then an IAM role with correct aud/sub conditions, an Aurora Serverless v2 cluster (which required a scaling configuration before the instance would even create), security group ingress, and an rds_iam mapped database user. Each layer failed in its own way:
  • A one slash file:/ typo
  • A region mismatch (us-east-2 vs us-east-1)
  • The Serverless v2 scaling prerequisite Lesson learned: with IAM auth, a "connection refused" is almost never the code.

Accomplishments that we're proud of

  • A matching engine that is explainable by construction: every score traces back to individual criteria, which is non negotiable in a clinical context.
  • Zero static database credentials. Authentication is entirely IAM and OIDC, with rotating short lived tokens.
  • A safety first UX that consistently frames the tool as decision support and keeps a human in the loop.
  • A fully normalized schema that cleanly separates trials, criteria, patients, and the clinical facts (conditions, meds, labs) needed to evaluate them.

    What we learned

  • Cloud auth is the hard part of "serverless Postgres." OIDC, STS, and RDS token signing have many places to misconfigure, and the error messages point at the database when the real fault is in IAM trust policies.

  • Determinism beats cleverness in healthcare. A transparent, weighted scoring model that a coordinator can audit is far more valuable than an opaque model with a marginally better hit rate.

  • Modeling "unknown" explicitly matters. Treating missing data as a distinct state, rather than a pass or a fail, is what turns the tool from a filter into a workflow that tells coordinators what to do next.

    What's next for TrialBridge AI

  • LLM assisted criteria ingestion: parse free text protocol documents into structured eligibility_criteria rows automatically.

  • FHIR / EHR integration to pull patient conditions, medications, and labs directly instead of seeding them.

  • Confidence intervals and recency weighting on lab based criteria, so a stale value counts for less than a fresh one.

  • Coordinator collaboration features: assignment, audit trails, and status tracking as patients move from "potential match" to "screened" to "enrolled."

  • Multi tenant hardening so multiple research organizations can run on the same platform with strict data isolation.

Built With

  • amazon-aurora
  • aws-iam
  • aws-rds-signer
  • aws-secrets-manager
  • aws-sts
  • drizzle-orm
  • git
  • github
  • nextjs
  • node-postgres
  • postgresql
  • radix-ui
  • react
  • shadcn-ui
  • tailwindcss
  • typescript
  • vercel
  • vercel-oidc
  • vo.app
Share this project:

Updates