Skip to content

Developer guide

Walter Kaunda edited this page Oct 20, 2021 · 6 revisions

Developer Guide

This page introduces anyone interested in contributing to the HIS-EMR-API through the applications structure, data model, and other concepts to help you get started.

Setting up a development environment

Setting up the application for development is covered in the deployment page. Please go through that first before proceeding. In addition to the requirements specified in the deployment guide, you may find the following useful:

The tools listed above provide linting and intellisense sense capabilities for most editors. If you use vscode, the following extensions work with the two tools listed above:

Postman is recommended for manually testing the API. A postman collection containing endpoints and example requests is provided with the application. It is located at doc/src/index.json; import this file into postman.

man 7 hier

The following is the directory structure of HIS-EMR-API application (with some unused directories ommited).

.
├── app
│   ├── controllers
│   ├── exceptions
│   ├── jobs
│   ├── models
│   ├── services
│   └── utils
├── bin
├── config
├── db
│   ├── data
│   ├── initial_setup
│   ├── migrate
│   └── sql
├── doc
├── lib
├── log
├── public
├── spec
├── swagger
└── vendor

The structure is that of a typical Ruby on Rails application with slight additions. Under the app directory are the exceptions, services, and utils directories.

app/exceptions just contains various custom exceptions used through out the application. For example, if we need to flag an error communicating with an external service, a custom GatewayError exeption is raised. These exceptions can then be handled at the controller level with an appropriate error that's reported to users. You might want to see app/controllers/concerns/exception_handler.rb for how the exceptions are handled globally.

The app/services directory contains Plain Old Ruby Objects (POROs) and modules that make up the business service layer of the application. Controllers are simply used as a glue layer between the outside world and the service layer. Controllers get requests from users, process them and forward them to the necessary service object/module to do its thing. The reasons for this are best explained elsewhere but from our experience we find this approach eases unit testing and we don't have to think too much about where to place a method in cases where the method cuts across multiple models. In other words, service objects provide us a context for a given operation (for example you will find everything to do with drug dispensations under a dispensation service not models/drug_order, models/observation, nor models/patient).

app/utils contains various utility methods used across the entire project. These range from basic date processing operations to helpers for concurrency. These methods do not carry any domain logic, they could as well do in the /lib directory. The stuff from this directory is usually included in service objects/modules.

Under db are the data, initial_setup, and sql directories. These contain various *.sql files used to initialise the database. They were imported from the old ART application, most of these files are not used but no one is yet to summon the courage to get rid of them.

doc is supposed to contain the project's documentation and the source files for the documentation. doc\src contains a postman collection that can be loaded into postman.

Finally, spec contains the applications unit tests.

Data model

The application is built on a data model inspired by OpenMRS. The model is quite large and is divided into various domains serving different roles. We only make use of a subset of these domains and have added ours to serve other requirements like stock management. And within the domains that we use, we do not use everything OpenMRS offers and where necessary we do extend the data model to fit our needs. This section details what we use and how exactly we make use of it. Any changes that we have made are also documented accordingly.

Before proceeding there are a couple of things one should know. There are some properties that all entities in the OpenMRS model share:

  • Entities within OpenMRS can broadly be classified into metadata and data. Metadata mostly provides names of things and the data is information collected about patients.
  • All entities have a creator and date_created.
  • Some entities have an updated_by and a date_updated field. This only applies to entities that can be updated. Not everything is allowed to be updated, some entities you can only create and delete.
  • Nothing is ever deleted, entities are merely soft-deleted. Soft-delete is facilitated by the voided, voided_by, and date_voided for data. For metadata retired, retired_by, and date_retired provide that functionality. The distinction between voiding and retiring is that voided items become inaccessible whilst retired items remain accessible but can not be used to create new things. So if there is a data item referencing some metadata and the metadata is retired, the reference still remains valid. However, if the data item is referencing another data item which is voided, the reference then becomes invalid (maintenance of this data integrity is within the application, in our case to make life easier for ourselves we decided not to allow voiding of individual data elements like a patient's weight but rather void the entire tree this data item is within - more of this on encounters).

Concepts

Concepts data model

According to OpenMRS, "Concepts are defined and used to support strongly coded data throughout the system." In short concepts provides names of various things. They may also define questions and their answers (more on this in the Observations section).

Concepts comprise a number of entities but we make use of the following entities only: concept, concept_name, and concept_set. A concept is also linked to concept_datatype and concept_class. We mantain this structure but do not take advantage of these additional entities.

concept is the unit that everything else refers to. Where ever a name is required, a reference to a particular concept is made.

concept_name maps various names to a single concept, for example 'HIV' and 'Human Immunodeficiency Virus' are both names of the same concept (they name the same thing).

concept_set is just a grouping of concepts under one name (another concept). For example you can group all Antiretroviral drugs under one concept. Thus if you need to retrieve the concepts you can simply look up Antiretroviral drugs under concept_set.

Encounter

OpenMRS defines this as "metadata regarding health care providers intervention with a patient." An encounter is essentially a unit that groups together related data on a patient collected by a health care provider at a given location. This domain comprises two entities: encounter and encounter_type. encounter_type provides a name for an encounter, every encounter has a name. Besides a name an encounter has a provider, location, and an encounter datetime.

An encounter's provider is not necessarily the same as the creator of the encounter. A provider is more or less the source of the information being entered. In some cases a clinician may interact with a patient and have all the information about recorded in some other media like paper. The clinician in this case is the provider of the information but may not be the person that enters this information into the application.

Every encounter has a location. The location simply refers to the point of interaction between the provider and patient. For example a provider and a patient can interact at a clinic's reception and later on in the consultation room. In such a case then we will have two encounters: one at the reception and the next at the consultation room.

Finally, an encounter has an encounter_datetime. This just records the time when the encounter occurred. As has been explained for provider above, an encounter may not always be entered into the application at the time a provider interacts with a patient. The entry may be done at a later time. This field helps back date to the correct time.

Observation

[TODO]

Order

[TODO]

Patient

[TODO]

User

[TODO]

Person

[TODO]

Groups/Workflow

[TODO]

Other

[TODO]

More about services

[TODO]

Versioning and releases

Releases are primarily made quarterly in line with the Department of HIV/AIDS reporting timelines. In between quarters there may be additional releases that mostly fix bugs with last major release.

A CHANGELOG detailing all the changes between version is maintained. As a developer you are expected to log all significant changes you make to this document. The document contains information to guide you on how to go about making those changes but you can also refer to keepachangelog.com. To make a release the CHANGELOG is updated with the new version then committed (with a message like 'New release v4.12.0'). An annotated tag is then made on that commit with a summary of the changes on that tag.

Clone this wiki locally