Tanzania Mesh Hernia Registry, is a mobile-first website and database designed to record and track Mesh Hernia operations in Tanzania. It was built by and for the SWIFTSS charity who are focused on improving the availability and effectiveness of mesh hernia surgery across Tanzania.
The code is available under a GPL v3 license on git clone https://github.com/swiftss-org/registry.
A backlog of development to be done can be found at ./backlog.md.
Registry is a Python 3 Flask application using SQLAlchemy for persistence. It is hosted on AWS ElasticBeanstalk backed by an AWS RDS Aurora MySQL compatible database. Bootstrap is used as the front-end component library. The code is maintained in GitHub and licensed under GPL v3. VirtualEnv is used to maintain Python dependencies. PyTest is used as a unit testing framework.
Clone the source code from GitHub
$ git clone https://github.com/swiftss-org/registry.git
$ cd registry
Install virtualenv, create a new environment, and install the required dependencies
# From inside the 'registry' directory created by git clone
$ pip install virtualenv
$ virtualenv venv
$ venv\Scripts\activate [Windows]
$ source venv/bin/activate [Linux/Mac]
$ python -m pip install pip-tools
$ pip-sync
Optionally set environment variables to make testing & debugging easier
$ export ADMIN_RESET_DB=True # Creates a new local SQLite database
$ export ADMIN_GENERATE_DATA=True # Creates minimal test data
$ export DEFAULT_TEST_ACCOUNT_LOGIN=True # Disables end-user authentication
Initialise App
from application import create_app
app = create_app()
from app.initialise import initialise
initialise(app)
Run Flask
$ export FLASK_APPLICATION="application.py"
$ flask run
The Registry will now be running on http://127.0.0.1:5000
# From inside the 'registry' directory created by git clone
# Build the Docker container
$ docker build -t swiftss-registry:latest .
# Run the container, using the default development.env environment variables
$ docker run --detach --env-file development.env --publish 5000:5000 swiftss-registry
The Registry will now be running on http://127.0.0.1:5000
NOTE: The
development.env
setsADMIN_RESET_DB
,ADMIN_GENERATE_DATA
andDEFAULT_TEST_ACCOUNT_LOGIN
environment variables all to True.
The database to connect to is looked up at application start time (see create_app()
in application.py
).
It follows a priority sequence -
- If a full database URI is provided by
RDS_URL
use that. - If a set of MySQL parameters are provided by use those.
- Else create a local SQLLite file in the temp directory.
You can specify a single fully formed URL as RDS_URL
which is passed to SQLAlchemy as the SQLALCHEMY_DATABASE_URI
.
See https://flask-sqlalchemy.palletsprojects.com/en/2.x/config/ for syntax details.
Alternatively for MySQL you can specify the properties individually with -
RDS_DB_NAME
RDS_USERNAME
RDS_PASSWORD
RDS_HOSTNAME
RDS_PORT
Registry follows the standard layout for a Flask application.
application.py
provides Flask (WSGI) entry pointapp
defines the flask applicationapp/routes
defines the URL routing and is the main entry point for the applicationapp/forms
uses WTForms to define the form data modelapp/models
defines the underlying data models in SQLAlchemyapp/formatters
provides front-end formatters for types such as dates, datetimes, etc.
static
contains static files; css, js, images, etc.templates
contains the html templates used byapp/routes.py
.
The data model is built around Patients and Episodes.
Represents specific individuals.
Patients are designed with minimal assumptions on the uniqueness or structure of any specific characteristic. Whilst each Patient is unique and has a unique numeric id no uniqueness restrictions are placed on any other attribute. Names, phone numbers and addresses are all considered to be non-unique and with the exception of name are all optional. Date of birth is captured as a birth year and separate full date as many Patients are anticipated not to know their full dob. Names, phone numbers and addresses are captured as unstructured text for maximum flexibility. The primary consideration is to ensure all Patients can be recorded. Not being able to record a Patient because they do not meet an arbitrary system defined definition of their attributes is to be avoided, we would rather capture duplicate Patient records than not be able to capture a Patient.
The recorded medical events of Patients.
Episodes record any medical activity or medical event of a Patient. Each episode links together a Patient, on a date, at a Hospital with the list of attending health care staff and any Complications that were observed or occurred. Episodes have an episode type and each episode type can extend the attributes captured using an additional child table. Their are two primary Episode types modelled, Surgery and FollowUp. FollowUp records no additional fields whilst Surgery extends the Episode to capture which Procedure was performed and a number of operative and post-operative observations.
An optional dated log of events associated with an Episode.
An extension table to record surgery specific details for an Episode.
An extension table for procedure specific details of a Surgery.
Medical staff who can use the application and recorded as attendees at an Episode.
The medical team are stored as users. Their is currently no separation between people who use the system and people who attend episodes and it is not necessary for a user to login to be captured or associated with an Episode.
A place Episodes occur at and Patients are initially registered at.
All versions are retained and the updating user and time stamp are recorded on each version. Removal or deletion of a Patient or Episode is done via a soft-delete flag however this is just another attribute and so can be edited like any other property meaning that ‘deleted’ records are always available and can be restored at any point.
Not Yet Implemented!!!
Users, Patients and Episodes are never removed from the database but flagged as not longer active via. a soft-delete flag.
Incremental database backups are taken daily and archived into S3 (need more details here!).
Full backups are not currently taken!
The interface is built around the actions of finding a patient, creating a new patient or finding an episode. Recording, viewing or editing an episode happens off these launch points.
- To edit a Patients details -- Find the Patient, update their details and click save.
- To record a new Episode -- Find the patient, click record new episode
- To edit an existing episode -- Find the patient, pick the episode to edit, click view/edit, update the details and click save.
The application is deployed on AWS Elastic Beanstalk. The database is a mySQL db deployed in RDS but via. EB.
The load balancer fronts https to the world and redirect to http internally within EB. The https certificate is also setup through AWS for *.swiftss.org
.
Custom domain name routing is achieved by a CNAME entry on the swiftss.org domain pointing to the EB instance.
Please see the earlier section on Docker for instructions to build and run the regsistry as a Docker image.
Build a docker container
cd thmr
> _docker build -t mesh -f Docker/Dockerfile .
This builds an image tagged as mesh,
> docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mesh latest 2ab582b9f92f 2 hours ago 1.49GB
python 3.7 94c9a318e47a 5 days ago 876MB
python 3.8 9756fa8d7b9d 2 weeks ago 882MB
Run the container with default commands --flask --genereate --reset-db, mapping port 5000 to the external machine
> docker run -p 5000:5000 mesh
2020-11-23 15:45:28 [INFO] Initalising SQLAlchmeny with database URL sqlite:///:memory:
2020-11-23 15:45:28 [INFO] Completed Flask setup for <Flask 'app'>
2020-11-23 15:45:28 [INFO] Running data generator.
* Serving Flask app "app" (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: on
2020-11-23 15:45:30 [INFO] * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
2020-11-23 15:45:30 [INFO] * Restarting with stat
2020-11-23 15:45:30 [INFO] Initalising SQLAlchmeny with database URL sqlite:///:memory:
2020-11-23 15:45:30 [INFO] Completed Flask setup for <Flask 'app'>
2020-11-23 15:45:31 [INFO] Running data generator.
2020-11-23 15:45:32 [WARNING] * Debugger is active!
2020-11-23 15:45:32 [INFO] * Debugger PIN: 229-094-