Mar 22, 2022

Lessons from Building BitMedic

This past weekend, I attended HackGSU X with Sai and Sohum, where we built BitMedic. BitMedic is a patient management system that gives patients control and portability of their medical data. Out of the 37 projects submitted, we won first overall. However, the path to get here was definitely not without its challenges, so buckle up as I revisit the roller coaster that was this project.

What is BitMedic?

BitMedic UI

The goal of BitMedic is to be an all-in-one patient management system. BitMedic is a centralized system that securely holds all of your personal information, medical history, medical documents, prescriptions, and more. Usually, when you transfer doctors, it can take a long time to move all of your files and history over to your new provider. BitMedic solves this by giving the patient direct control of who has access to their data. If you move doctors, you can go into your dashboard and instantly add your new doctor and remove your old one. Right away, your new doctor will have access to all of your medical data, while your old doctor will no longer have any access to any patient information. In addition, we implemented functionality that allows doctors to prescribe prescriptions to patients using the Ethereum blockchain. This creates a cryptographically ensured record of all prescriptions, and makes it easy to audit that patients only have access to prescriptions that are authorized by their doctors.

BitMedic Doctors UI

What’s going on in the background?

BitMedic is built on Django, a Python-based web framework. All the backend logic is done using Python behind Django, and Django returns HTML templates that display the data to the user. The project is hosted on Google Cloud, using Compute Engine for the server and Cloud DNS and Storage for some assets.

When we were originally deciding how to build the frontend, we were originally planning to use React and TailwindCSS. However, Django mostly replaces the need for React, and we had trouble integrating Tailwind with our Django project. We ended up landing on Bootstrap and plain old CSS, which is considered a more old school and less ‘modern’ approach. However, this stack ended up working well for us. I was in charge of the frontend and user interface, and Bootstrap served as a nice base that I was able to build on. I was going for a very minimal and straightforward user interface, and I’m mostly happy with how it turned out.

So much debugging

While the project turned out well, the path to get here was very rocky at times. In fact, we probably spent more time this weekend debugging than actually coding. Here are some of the issues we ran into:

Python dependency weirdness

One of our first signs of trouble was when we were having trouble setting up the Python dependencies we needed for our blockchain integration to work. Some of our computers accepted the pip installations, but others did not. This meant some people were able to run locally while others couldn’t. After a lot of troubleshooting and going down a rabbit hole of installing extra dependencies, we mostly overcame this. In addition, we utilized Visual Studio Code’s Live Share feature heavily this weekend, so people with the app running could share their Visual Studio Code instance with everyone else.

Google Cloud, Django, and ambiguous error messages

One of my jobs this weekend was deploying our project to Google Cloud. Fair enough, I thought, we’ll use Google App Engine for our Django project and Google Cloud SQL for our database. To put it lightly, this was much easier said than done.

My first attempt was with App Engine, where I followed the Google Cloud guide to set up the necessary config files and deployed it. I used Google Cloud SQL’s proxy locally on my Mac and was able to get the SQL database working, but app engine wouldn’t take my app. After hours of debugging and cryptic error codes, I moved to Cloud Run.

Cloud Run is a similar service to app engine, but it’s a little different in that it uses the more standardized Dockerfile versus the proprietary system that App Engine uses. I made a lot more progress with Cloud Run, but this time got stuck with CSRF issues. The site ran and connected to the database, but every time we tried to log in we got a CSRF hostname invalid error. I was confident all the Django settings were right, and I spent probably 7-8 hours Saturday debugging this before deciding to drop Cloud Run and switch to Compute Engine.

Compute Engine is similar to a traditional VPS, where you have a Linux-based operating system and have full access and customization to the machine. At first when I attempted to deploy the app to Compute Engine, I ran into the same thing. However, after a lot more debugging, I found the issue.

Essentially, when Django verifies that a request is legitimate, one of the things it checks is that the request was made over a secure (HTTPS) connection. If it can’t get confirmation that the request came from a secure connection, it will reject it. When you set up Django hosting on a server, you usually set up a web server (I used Nginx) and that web server listens to connections from the internet and forwards them to the Django server. However, since the secure connection terminates at Nginx, the web server, Django sees all the requests as coming from insecure connections, even though in reality they aren’t. The solution to this is to go into the Nginx config and add a ‘X-Forwarded-Proto’ header, which tells Django if the request came from a secure environment. After I added this, users were able to authenticate on the app.

Cryptic error messages

A big theme in this project was cryptic error messages. In the Django hosting example I previously mentioned, the error message was that our domain wasn’t an allowed host. This was misleading because our hostname and CSRF policies were configured properly, but Django wasn’t able to verify that the connection was secure. On Google Cloud, I ran into issues with cryptic error codes as well. Cloud products are great resources when they work, but when debugging, because you have no control they can be hard to work with.

Wrap-up

BitMedic was one of the most challenging projects I’ve worked on in a while. I’m not too familiar with Django, so it was a new environment, but I’ve learned a lot about it and how the intricacies of how hosting apps work. In addition, I got some practice with designing good UIs and frontends. Again shout out to Sai and Sohum for being great partners to work with in building BitMedic. I’m very proud of what we built and am excited to see what we’ll do in the future.

Feel free to view our Devpost here and GitHub repo below.

GitHubView project on GitHub
Previous: Generating Preview Images for My Site