Code Monkey home page Code Monkey logo

cabolabs-ehrserver's Introduction

EHRServer is the first open source Clinical Data Management and Sharing Platform, compliant with the openEHR standard. Use it as a:

  • Primary clinical data repository for web and mobile clinical apps.
  • Secondary repository for backup or analysis.
  • Centralized repository to share clinical information between many systems.
  • Fast prototyping of new health related apps, removing the need of creating the clinical repo yourself.
  • Main or proxy repository for wearable and other monitoring-based clinical data.
  • Standardized aggregation repository as a data source for ETL to datawarehouses and analytics tools.
  • Research and training clinical data repository.
  • Backend for Clinical Decision Support tools (e.g. rule engines)

EHRServer was designer for developers by developers. You don't need to be an openEHR guru to use it. Easy to install, use, manage and integrate.

Stargazers over time

Stargazers over time

Screenshots

Dashboard

Quick look at what is happening in the EHRServer.

Template Manager

Manage clinical document definitions from the Template Manager, defining what data could be stored and queried.

Query Builder

Very simple point and click query creation in seconds, no programming needed.

Manage it on the go

Mobile friendly user interface, adapts to small screens.

EHRServer Architecture (simplified)

Quick architecture reference

  • REST API provides services to integrate the EHRServer to your systems and apps (documentation).
  • Web Console provides a user interfaces for administrators of the EHRServer (check the screenshots above).
  • Query Builder is the component in charge of creating, managing and executing queries over openEHR data stored in the EHRServer.
  • SNOMED Query is a component in charge of processing the terminologic constraints in queries that contain SNOMED CT Expressions. This component is part of the SNQUERY tool developed by VeraTech
  • EHR Base is where data is managed, indexed, versioned and stored.

Main features

  • openEHR compliant clinical data repository
  • Administrative Web Console
  • Simple but powerful REST API
  • Supports XML and JSON
  • Full audit access for traceability
  • Versioned clinical documents
  • Query Builder from the Web Console to create data queries (no programming needed!)
  • Support of SNOMED CT Expressions on openEHR queries (simplifies complex queries)
  • Supports any structure of clinical document (following the openEHR standard information model)
  • Vendor Neutral Archive
  • Multitenancy

Based on Open Source Technologies

Community

Support the project!

One way of supporting this project and our vision for building a completely open e-health platform, is through community donations. This is used for servers, dev tools, pay for dev time, maintain the website, updated documentation and guides.

Another way of supporting the project is by subscribing to the CloudEHRServer

Thanks for your support!

Community support

Try it

Want to try EHRServer?

  • Installing EHRServer
  • Subscribe to CloudEHRServer
  • Run with docker-compose:
    1. $ grails war
    2. $ cd docker-compose
    3. $ docker-compose up
    4. localhost:8080 will be Adminer (a MySQL manager) (default user: ehrserver2/ehrserver2)
    5. localhost:8888 will be Tomcat (running EHRServer) (default user: [email protected]/admin)
    6. Change the ports and SMTP configuration in the docker-compose file (optional, for user management like password reset)

Quick install, configure, run locally (step by step)

This guide is based on a Linux environment, should be adapted for other OS.

Dependencies

  1. curl -s get.sdkman.io | bash
  2. source "$HOME/.sdkman/bin/sdkman-init.sh"
  3. sdk install grails 3.3.10
  4. set version by default: Y
  5. grails -version

Note: Grails should be 3.3.10!

Database for development

Install MySQL

MySQL >= 5.7

  1. sudo mysql -u root
  2. CREATE DATABASE ehrserver2;
  3. exit

MySQL < 5.7

  1. from the installation process, copy the default root password
  2. ./mysql -u root -p
  3. enter default root password, and proceed to change it
  4. ALTER USER 'root'@'localhost' IDENTIFIED BY 'NEW-ROOT-PASSWORD';
  5. CREATE DATABASE ehrserver2;
  6. exit

On any version you can also create a non-root user and use that to access your EHRServer database.

  1. create user 'user'@'localhost' identified by 'your_password';
  2. grant all on ehrserver2.* to 'user'@'localhost';
  3. select host, user from mysql.user;
  4. exit
  5. mysql -u user -p

EHRServer configuration

  1. nano ehrserver/conf/application.yml
  2. change development password to NEW-ROOT-PASSWORD
  3. save

EHRServer environment variables

Mandatory:

  export EHRSERVER_REST_SECRET="6067dba9-1417-41c5-b1af-92208c77ce77"
  export EHRSERVER_SNQUERY_KEY="22222222-2222-2222-2222-222222222222"

Optional:

  export EHRSERVER_EMAIL_FROM="[email protected]"
  export EHRSERVER_EMAIL_HOST="mail.yourdomain.com"
  export EHRSERVER_EMAIL_PORT=1234
  export EHRSERVER_EMAIL_USER="[email protected]"
  export EHRSERVER_EMAIL_PASS="youruserpassword"
  export EHRSERVER_ALLOW_WEB_USER_REGISTER=false

Conditional:

  If EHRSERVER_ALLOW_WEB_USER_REGISTER =>
      export EHRSERVER_RECAPTCHA_SITEKEY="generate a recaptcha v2 site key"
      export EHRSERVER_RECAPTCHA_SECRETKEY="generate a recaptcha v2 secret key"

  If you want to use AWS S3 for file storage =>
      export EHRSERVER_S3_ACCESS="your config in S3"
      export EHRSERVER_S3_SECRET="your config in S3"
      export EHRSERVER_S3_BUCKET="your config in S3"
      export EHRSERVER_S3_REGION="your config in S3"

EHRServer run (dev environment)

  1. cd ehrserver
  2. grails run-app
  3. open http://localhost:8090
  4. login with admin/admin/123456

Atomik Server

I you need more speed and mono-tenancy EHR server, please check this Atomik! https://atomik.app/

cabolabs-ehrserver's People

Contributors

betanzos avatar casiodbx avatar dngferreira avatar dudanogueira avatar echosalik avatar jaykola avatar mariadeanton avatar ppazos avatar roliveira29 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cabolabs-ehrserver's Issues

Consider slots to Elements in OperationalTemplateIndexer

If a OPT has a slot to another archetype on an ELEMENT node (**) do not create an index for that node because it will not have a RM_TYPE_NAME associated with it and the type is needed by queries to know how to process data.

(**)
allow_archetype ELEMENT[at0058] occurrences matches {0..1} matches {
include
archetype_id/value matches {/openEHR-EHR-ELEMENT.last_normal_menstrual_period.v1|openEHR-EHR-ELEMENT.menstrual_cycle_day.v1/}
}

descarga

REST queryData and queryComposition should be executed using a Query instance

Right now the query execution is done using query data as params (because are invoked from the UI) but those services should use the data from a Query instance and receive only a queryUid as param (that's for invoking query services from external clients, not from the UI).

Query data by params or by queryUid could coexist, we can use the first for query testing from the server UI and the latter for external invocation.

Put each resource's URL on REST list services output

For lists of ehr, patient, query, composition, etc., put a link to the resource details, so if a client gets a list of e.g. ehrs, it already gets the data needed to get the details of one particular ehr without knowing the name of the service.

Use this notation:

<resourceList>
 <resource>
  <link href="http://domain/path_to_ehrserver/rest/resource_class/resourceUid/xxx" />
  </resource>
 ...
</resourceList>

Add archetypeId to retrieved data from queries

E.g. data retrieved grouping by path, in json: has the path but no the archetypId that gives the context to that path. That info is in the DataIndex used to create the DataGet on the query.

 "/content[at0002]/activities[at0003]/description[at0004]/items[at0005]/value": {
    "type": "DV_CODED_TEXT",
    "name": "categoria",
    "serie": [
      {
        "value": "sangre",
        "date": "2013-09-18T12:55:17Z"
      }
    ]
  }, ...

RestController.queryCompositions should use Query.executeComposition

queryCompositions should create a temp Query and call executeComposition to execute it, instead of having all the logic to create the SQL query in queryCompositions as it is right now.

The logic is already implemented, what should be changed and tested is the queryCompositions action.

Sometimes XML processing on commit shows an XML error

| Error Warning: validation was turned on but an org.xml.sax.ErrorHandler was not
| Error set, which is probably not what is desired. Parser will use a default
| Error ErrorHandler to print the first 10 errors. Please call
| Error the 'setErrorHandler' method to fix this.
| Error Error: URI=null Line=1: Document root element "version", must match DOCTYPE root "null".
| Error Error: URI=null Line=1: Document is invalid: no grammar found.
=== getArchetypes( composition, .* ) ===
No se encuentra el arquetipo que corresponda con .*, se intenta cargarlo
Carga desde: archetypes\composition\openEHR-EHR-COMPOSITION.orden_de_estudios_imagenologicos.v1.adl
Cargado el arquetipo: openEHR-EHR-COMPOSITION.orden_de_estudios_imagenologicos.v1.adl de archetypes\composition\openEHR-EHR-COM
POSITION.orden_de_estudios_imagenologicos.v1.adl
Carga desde: archetypes\composition\openEHR-EHR-COMPOSITION.orden_de_estudio_de_laboratorio.v1.adl
Cargado el arquetipo: openEHR-EHR-COMPOSITION.orden_de_estudio_de_laboratorio.v1.adl de archetypes\composition\openEHR-EHR-COMP
OSITION.orden_de_estudio_de_laboratorio.v1.adl
Carga desde: archetypes\composition\openEHR-EHR-COMPOSITION.signos.v1.adl
Cargado el arquetipo: openEHR-EHR-COMPOSITION.signos.v1.adl de archetypes\composition\openEHR-EHR-COMPOSITION.signos.v1.adl
IndexDataJob
Indexacion de composition: d2a898df-5791-43c3-af0d-4e065faeef61
| Error Warning: validation was turned on but an org.xml.sax.ErrorHandler was not
| Error set, which is probably not what is desired. Parser will use a default
| Error ErrorHandler to print the first 10 errors. Please call
| Error the 'setErrorHandler' method to fix this.
| Error Error: URI=null Line=2: Document root element "data", must match DOCTYPE root "null".
| Error Error: URI=null Line=2: Document is invalid: no grammar found.

  • index created: openEHR-EHR-COMPOSITION.orden_de_estudio_de_laboratorio.v1/content[at0002]/activities[at0003]/description[at0004
    ]/items[at0009]/value for compo d2a898df-5791-43c3-af0d-4e065faeef61
  • index created: openEHR-EHR-COMPOSITION.orden_de_estudio_de_laboratorio.v1/content[at0002]/activities[at0003]/description[at0004
    ]/items[at0006]/value for compo d2a898df-5791-43c3-af0d-4e065faeef61
  • index created: openEHR-EHR-COMPOSITION.orden_de_estudio_de_laboratorio.v1/content[at0002]/activities[at0003]/description[at0004
    ]/items[at0005]/value for compo d2a898df-5791-43c3-af0d-4e065faeef61

Add support for OPTs

OPTs are like the current flat archetypes used in EHRServer, but the difference is that there are references to slots in paths.

A path from a COMPOSITION to an ELEMENT inside the OPT might look like:

/data[at0001]/events[at0006]/state[at0007]/items[openEHR-EHR-CLUSTER.sample_level_of_exertion.v1]/items[at0010]/items[at0011]

So, when creating index definitions, the system should create all the possible paths from the root archetype to the leaf nodes, considering that everytime that an archetype id is found (i.e. a slot is found) the path should have the reference to the archetype id instead of the node_id inside brackets [...], and from there calculate the paths inside that archetype.
So paths are absolute from root to leaf.

Verificar tipos asociados a las paths utilizadas para queryCompositions

Para queryCompositions las condiciones deben especificarse sobre paths que apuinten a DataValues y no a otros tipos.

En el create de Query debería verificarse esa condición para que en el test o execute de Query no lleguen paths que apunten a otros tipos que no son DataValue.

Ahora lo que pasa es que RestController.queryCompositions está tirando una excepción si el tipo de la path no es correcto, y no debería tirar excepciones desde un servicio REST.

Soportar búsquedas para múltiples EHRs

Si se realiza una búsqueda sin definir el ehr_uid, los resultados tanto de datos como de documentos deberían estar agrupados por EHR, para no mezclar datos de distintos pacientes (no tiene sentido).

Esto permite:

  • Mostrar datos de múltiples pacientes (ej. hospitalizados)
  • Mostrar documentos de múltiples pacientes (ej. los que va a atender un médico en la consulta de mañana)
  • Realizar agregaciones sobre los datos de múltiples EHRs (ej. estadísticas en informes)
    • Este tipo de agregaciones por ahora no se hacen en EHRServer

Locale should be considered to use OPTs

Each OPT instance has it's own locale/language, so the configured locale for the server should be the language in which the templates are designed. Only those should be loaded in the system.
Also, the client apps should only send compositions in the locale configured in the server.
Rules should be written down to check that those rules are met.

Maybe in the future we can support that one server instance accepts templates in different locales and client submits using those locales.

Throw exception if SLOT is found on OPTs

OperationalTemplateIndexer should work only with flat OPTs. If a slot is found, it should throw an error.

This happens when tags with type ARCHETYPE_SLOT are found:

<children xsi:type="ARCHETYPE_SLOT">

Agregar servicio de sincronización de servidores

Servicio HTTP/XML,JSON para sincronización de:

  • datos
    • registros commiteados
    • índices de datos de registros
    • información de contribuciones
    • historias clínicas
    • versiones
  • consultas (definición de consultas)
  • definiciones de índices (se crean desde arquetipos)
  • personas (por ahora mientras no tengamos servidor demográfico)

Soporte para versionado de datos

Los tipos de cambios a soportar inicialmente, que pueden crear versiones, son:

  • creation: nueva versión (esto ya es soportado)
  • amendment: corrección de un registro eventual (ver composition category "event")
  • modification: modificación de un registro persistente (ver composition category "persistent")

Tareas:

  1. Ver cómo hacer el checkout de un registro para que luego pueda ser corregido o modificado (según su categoría).
  2. Investigar la semántica de corrección y modificación en la doc de openEHR para ver si hay ejemplos o sugerencias de cómo hacerlo.
  3. Crear tests de commit para corrección y modificación.
  4. Modificar todas las consultas para que consideren versionado:
  5. Las consultas comunes o que no especifican versión, deben obtener siempre la última versión.
  6. Deben agregarse consultas que permitan ver todas las versiones de un registro.

openEHR Terminology: 2.3.2 Audit Change Type
This vocabulary codifies the kinds of changes to data which are recorded in audit trails.

Terminology: openehr Group_name(“en”): “audit change type”

Concept id Rubric (en) Description (en)
249 “creation” Change type was creation.
250 “amendment” Change type was amendment, i.e. correction of the previous version.
251 “modification” Change type was update of the previous version.
252 “synthesis” Change type was creation synthesis of data due to conversion process, typically a data importer.
523 “deleted” Change type was logical deletion.
666 “attestation” Existing data were attested.
253 “unknown” Type of change unknown.

Permitir filtrar búsquedas por datos demográficos

Hay un conjunto de datos demográficos mínimos que deben estar disponibles para hacer filtros de búsquedas sobre múltiples EHRs:

  • rangos de edad (configurables por consulta, pero debe haber una definición por defecto)
  • sexo (por defecto M, F, U)

Un filtro puede ser de valor vacío, para poner en una bolsa todos los datos o registros que no tienen el valor para poder filtrarlos.

Esto es tanto para las búsquedas de datos como para las búsquedas de documentos.

Antes debe implementarse el issue #4

Use the link response header to reference a description of a REST error

Each REST service has some preconditions and if the call doesn't meet those an error is retrieved.
There is a respose header "Link" that can be used to reference more information about the error, maybe a long description or an error log.
Use the link header to put stacktraces, exception messages and other usefull information that is not in the error response itself.

Some useful resources:

Folder copy rules

  1. We need to add rule support to specify how committed COMPOSITIONs should be included in FOLDERs.
  2. Those rules should be specified from the admin console.
  3. Proposal:

FOR Document d, IF d.isOfType(optId) THEN d.copyTo(folderId).

  1. More complex conditions and operations can be specified, like:

FOR Folder f, IF f.doesntExists() THEN f.create().

  1. We need to add support for FOLDER querying and define the FOLDER result set structure.

Ofrecer lista de codigos / nombres para criterio de queries por DV_CODED_TEXT

Cuando se selecciona un nodo DV_CODED_TEXT como criterio de búsqueda para una query de tipo "composition", el input de value debería convertirse en un select con los valores posibles (definidos en el arquetipo, si los hay) para seleccionar uno de esos (crear otro issue que permita seleccionar varios codigos para hacer OR).

Improve REST services URLs

Right now, URLs are like these:

  • /rest/ehrList
  • /rest/ehrForSubject?subjectUid=xxx
  • /rest/ehrGet?ehrUid=xxx
  • /rest/patientList
  • /rest/queryList
  • /rest/queryShow?queryUid=xxx
  • /rest/queryData?...
  • /rest/queryCompositions?...

These URLs should be changed to something more simple and easy to remember, and to make space partitions of the entities we have based on the URL parts:

  • /rest/ehrs -- list of all EHRs
  • /rest/ehrs/ehrUid/xxx -- one EHR based on ehrUid partition
  • /rest/ehrs/subjecUid/xxx -- one EHR based on the subjectUid partition
  • /rest/patients -- list of all patients
  • /rest/queries -- list of all queries
  • /rest/queries/queryUid/xxx -- one query based on queryUid partition
  • /rest/queries/queryUid/xxx/execute -- executes query xxx, each query knows its own type, this can be a queryData or a queryComposition

-- ideas for retrieveing queries (also for other entities to query by other pertitions and search criteria)

  • /rest/queries/name/this.is.a.name -- list queries which name is equal to "this.is.a.name" (spaces transformed into ".")
  • /rest/queries/descriptionContains/a.text.to.find -- list of queries that contains the "a.text.to.find" text ("description" partition with "contains" criteria)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.