Multi-tenant clinical trial recruitment platform
At a clinical trial recruitment software company, I worked across the full stack of one Django platform serving several leading US clinical research institutions, each with its own database, features and branding.
- Client
- Clinical trial recruitment software company
- Role
- Software engineer, full stack
- Year
- 2022
In brief#
For several years up to 2022 I was a full-stack software engineer on a small team, working on a clinical trial recruitment platform then used by several leading US clinical research institutions. One Django codebase served every institution, each with its own database, its own features and its own look and feel. I worked across trial data, search and matching, the volunteer registry and the investigator dashboard, and I designed most of the two-way messaging between volunteers and study teams.
The challenge#
Clinical research institutions recruit volunteers for many trials at once, and each wants a recruitment site under its own name and branding. Building a separate product for each one would mean writing the same software many times over.
The trials themselves are registered in a public registry, ClinicalTrials.gov, and their records change over a study's life. A recruitment platform has to stay in step with that registry, match the right volunteers to the right trials, and give volunteers and study teams a way to talk once a match is made.
What I did#
I joined a product that already had a volunteer registry and investigator dashboards, and spent my time building on and substantially extending them. The work spanned the whole stack: Django and Django templates on the server, JavaScript and jQuery in the browser (and React later on), PostgreSQL for data, Apache Solr for search, all served by Apache HTTP Server.
Trial data. Trials were imported from ClinicalTrials.gov by their NCT ID (the registry's unique trial identifier) and refreshed from the same source. This was the classic ClinicalTrials.gov API, which NLM has since replaced: the modern API arrived in 2024 and the classic site and API were retired in June 2024.
Search and matching. Matching volunteers to trials took every facet into account: condition, age, gender, location and the rest. Solr sat behind the platform's search.
Volunteer registry. A volunteer registers once and can add sub-profiles for the people they register on behalf of. Matching trials appear later in their dashboard, where they can enroll in the ones that suit them.
Investigator dashboard. Researchers got insights and analytics on their trial listings, and a way to find and connect with matching volunteers.
Messaging. I substantially designed the two-way messaging between volunteers and investigators: threaded, with several conversations running at once. It synced with Gmail, so a volunteer or an investigator could simply reply from their email and the reply appeared in the right conversation thread in the dashboard.
Performance. As load grew, I worked on PostgreSQL and API performance so the platform kept up.
How it works#
Trials and volunteers live in each institution's own database; matching connects them, and conversations continue in the dashboard or by email.
Each institution had its own database while sharing the same Django code, so its trials, volunteers and settings stayed separate from every other institution's. Each institution also had its own features and its own look and feel.
Trials came in from ClinicalTrials.gov by NCT ID and were stored in that institution's database, alongside the volunteers who had registered there. Matching connected the two: volunteers saw matching trials in their dashboard, and investigators saw matching volunteers in theirs. From there, a conversation could continue in the app or from either person's inbox.
Results#
- Several leading US clinical research institutions ran their own branded recruitment sites on a single codebase, with their data kept in separate databases.
- Trial listings stayed tied to their ClinicalTrials.gov records through import and refresh by NCT ID.
- Registered volunteers saw matching trials in their dashboard and could enroll, while investigators found matching volunteers in theirs.
- The two-way messaging I designed let volunteers and study teams keep several threaded conversations going, with email replies landing in the right thread.
What I learned#
One codebase with a database per tenant trades operational overhead for isolation. Every schema change has to land on every database, and every new tenant is more to provision and watch. In return, one institution's data never shares a table with another's, which made each tenant easier to reason about.
Threading email replies into an app is mostly about the inbound side: reliably attaching a reply to the right conversation, so people can answer however suits them without the thread falling apart.