Skip to main content

Protocols

The Healee platform includes a dedicated framework for creating Digital Health Protocols.

Digital Health Protocols are tailored care pathways (algorithms) focusing on specific conditions, procedures or therapeutic areas.

Patients install these pathways as separate apps within the platform, to start guided therapeutic or prophylactic journeys, and get expert advise, specialized content, and dynamic next-step reminders and notifications.

1. Used languages and frameworks

2. Protocol file structure

Main files

  • info.json: main information about the protocol (name, min Healee required version, etc.)
  • description.[xx].pug: the html for the protocol description (for the respective "xx" language (e.g. "en", "de", etc.) that appears as info before the patient installs the protocol
  • layout.pug: the protocol's html
  • templates.pug: custom Kendo UI item templates used (if used) by the protocol's Kendo UI widgets
  • stylesheet.less: the protocol's css
  • icon.svg: the protocol's icon
  • tabIcon.svg: the protocol's tab icon (if tabName is set)

Folders

  • components: components are split as subfolders within the components folder. The name of the folder is the id of the component.
  • res: protocol resource files - images, video files, etc.
  • mail-templates: mustache mail templates which could be used by reminders that send emails

Protocol info.json properties

name (required): Protocol's name. Could be localized, e.g.: en: My Protocol, de: Mein Protokoll
minVersion (optional): Min required version of user's Healee (for native apps mainly). Format: YYYY-MM-DD
maxVersion (optional): Max required version of user's Healee (for native apps mainly). Format: YYYY-MM-DD
preloads (optional): Array of strings - the resources that should be loaded before the protocols shows up when opened.
hasProviders (optional): Boolean value indicating whether when installed the protocol should be tied to a list of providers.
canRemove (optional): Boolean value indicating whether the user can uninstall the protocol.
isDefault (optional): Boolean value indicating whether the protocol is installed by default for every user.
tabName (optional): The name of the tab / section (if the protocol is available as part of Healee's main navigation).
tabIndex (optional): The tab's index (then tabName is set).
color (optional): The main protocol's color.
termsLink (optional): Link to the terms & conditions page. If set, the user will be asked for accepting the terms and conditions before installing the protocol.
privacyLink (optional): Link to the privacy policy page. If set, the user will be asked for accepting the privacy policy before installing the protocol.

Component files

Every component encapsulates the default model and the behavior behind protocol widgets used in the protocol's html.

  • meta.json: the meta information about the component. Supported fields: default, bindings, forms, actions
  • expressions.(jsx|tsx): a JavaScript / TypeScript class defining all the expressions used in bindings and actions. The name of the class should be in pascal case (e.g. MyComponent), while the name of the component's folder should be the same but in camel case (e.g. myComponent).
  • info.json: main information about the component (supported languages)

Component info.json properties

languages (optional): Array of strings (e.g. [ "en", "de" ]). The list of languages for which this component should be activated / used.

3. Protocol data structure

Every installed protocol instance holds two collections - clientItems and serverItems.

In clientItems go all the items pushed by the client side, e.g. returned by expressions or custom actions.

In serverItems go all the items pushed by the server, e.g. reminders for notifications.

4. Components

Bindings

Bindings are used for binding widgets' states (visibility, text, html, value, checked, etc.) to data selectors (short code snippets) or to expressions (JavaScript methods). Whenever the state of the protocol changes, bindings are reevaluated.

Expression bindings

The code for the binding evaluation is located in the expressions.jsx / expressions.tsx file. The binding type attribute could be boolean, text or any other string. When it's boolean or string it can be omitted when binding via the getBoolean or getText. Other methods that can be used in bindings are getObj (binding to an object - e.g. to a datasource) and getFunc (binding an event to a method).

E.g.


layout-implicit-binding.pug

.label(data-component-id="mylabel" data-bind="invisible: getBoolean('mylabel')") Label

components/mylabel/meta.json

{
"bindings": [
{
"type": "boolean",
"expression": "..."
}
]
...
}

layout-explicit-binding.pug

.label(data-component-id="mylabel" data-bind="invisible: getBoolean('mylabel.isInvisible')") Label

components/mylabel/meta.json

{
"bindings": [
{
"type": "isInvisible",
"expression": "..."
}
]
...
}
Note

Expression bindings are the default bindings and their declarations could be omitted from the meta.json file.

E.g.

layout.pug

.label(data-component-id="mylabel" data-bind="invisible: getBoolean('mylabel.shouldHideLabel')") Label

components/mylabel/expressions.jsx

export default class Mylabel {
shouldHideLabel() {
return (this.protocol.clientItems || []).some(x => x.welcome);
}
}

Data selector bindings

The code for the binding evaluation is located directly in the meta.json file.

E.g.

layout-explicit-binding.pug

.label(data-component-id="mylabel" data-bind="invisible: getBoolean('mylabel.isInvisible')") Label

components/mylabel/meta.json

{
"bindings": [
{
"type": "isInvisible",
"selector": "((clientItems || []).some(x => x.welcome) || (clientItems || []).some(x => x.medicalFormData))"
}
]
...
}

Actions

Actions are used for defining what happens after certain user actions - clicking a button, starting a medical form, completing a medical form, etc. Action's attributes are:

  • type - custom, remove, startComponent, load, expression or loadReact
  • expression - the name of the JavaScript method
  • event - the event that triggers this action. This could vary between widgets. For example the protocolform widgets support events start and complete
  • source - the source id of the inner component (e.g. one of the used forms) that triggered the event. Currently used only by the protocolform widget
  • items - used only by the remove action

Action types

custom

The result of this action - the object specified in the data attribute will be added to the protocol data.

e.g.

{
"actions": [
{
"type": "custom",
"data": {
"welcome": true
}
}
]
...
}
remove

The result of this action - the objects of the types specified in the type attribute will be removed from the protocol data.

e.g.

{
"actions": [
{
"type": "remove",
"items": [
"form",
"notification"
]
...
}
]
...
}
startComponent

The result of this action - the widget that is responsible for a component will be started when the specified event is triggered.

e.g.

{
"actions": [
{
"type": "startComponent",
"component": "[componentId]", // the id of the component to be started
"event": "complete"
}
]
...
}
copy

The result of this action - the result of the action triggered on a certain event will be added to the clientItems collections. Usually this action is used when there's no expression handling a particular event.

e.g.

{
"actions": [
{
"type": "copy",
"event": "complete"
}
]
...
}
load

The result of this action - start an expression when the protocol loads.

e.g.

{
"actions": [
{
"type": "load",
"expression": "start" // the JavaScript method to start on load
}
]
...
}
expression

The result of this action - the specified expression (JavaScript method) will be executed.

e.g.

{
"actions": [
{
"type": "expression",
"expression": "start",
"event": "start"
}
]
...
}
loadReact

The result of this action - A React component will be rendered, using the element having [elementId] as an ID, as a root element.

e.g.

{
"actions": [
{
"type": "loadReact",
"expression": "getComponent", // a JavaScript method in the expressions file that returns an instance of a React component
"elementId": "myReactRoot" // the id of the element placed in layout.pug that will be used as a root for the React component
}
]
...
}

Expressions

Expressions are JavaScript methods defined in the default exported class in the expressions.jsx file placed in the component's folder.

The class receives the whole protocol in its constructor.

e.g.

export default class MyComponent {
constructor(protocol) {
this.protocol = protocol;
}

isInvisible() {
return (this.protocol.clientItems || []).some(x => x.myCustomData);
}
}

Expressions that receive items to be recorded in the clientItems collections could manipulate the items by adding new items or deleting existing items before they got pushed to the server. For example an expression that is triggered upon medical form completion could add additional items to the items collection.

formCompleted(items) {
return [
...items,
{
type: "notification",
pushNotification: true,
group: "customGroup",
recurrence: {
startDate: new Date(),
period: "Month",
value: 1
}
}
];
}

Items

Items are special objects that can be added to the clientItems collection by intercepting the respective events (form completion, pages widget finish, etc.) thus triggering specific workflows.

Item types

notification

The notification item is used for triggering the pattern for reminders to be sent from the server (and added to the serverItems collection) at a specific date and time or having a pattern for recurrence.

{
type: "notification",
pushNotification?: boolean, // should the client be notified via a push notification (web or native)
group: string, // unique identifier which could be used for overwriting notifications/reminders of the same group
data: any, // object used for holding specific reminder data
date?: Date, // if the reminder should be send at a specific date (one time)
recurrence?: { // if reminders should be send with a recurrence pattern
startDate: Date,
period: string, // heal.client.protocolOperations.consts.[YEAR_PERIOD|MONTH_PERIOD|DAY_PERIOD|HOUR_PERIOD|MINUTE_PERIOD]
value: number, // the value that should be used for the period. e.g. 5 DAY_PERIOD
endBy?: Date, // end the recurrence by the end of this date
endAfter?: number, // end the recurrence after that many occurrences
skipEvery?: number // skip every X occurrence of this reminder
}
}

If notification.data contains a text field, it's used for sending the push notification message (if pushNotification is true).

If notification.data contains a mail field, it's used for sending an email when a reminder is triggered.

mail: {
to?: string, // the recipient's email address. If not provided, the email is taken from user's profile.
subject: string, // the subject of the email
template: string // the name of the mustache template in the [mail-templates] folder (without the .mustache extension)
}

If notification.data contains an sms field, it's used for sending an SMS message when a reminder is triggered.

sms: {
phoneNumber?: string, // the recipient's phone number. If not provided, the phone number is taken from user's profile.
message: string // the content of the SMS message that will be sent
}
remove

The remove item is used to remove specific client items (by their IDs) from the clientItems collection.

{
type: "remove",
items: [] // array of the client items' IDs
}
custom

The custom item is just a convention for marking an item holding custom data.

{
type: "custom",
data: {} // custom data object
}
startComponent

The startComponent item is used for starting a widget that is responsible for a specific component.

{
"type": "startComponent",
"component": "[componentId]" // the id of the component to be started
}

5. Widgets

Protocol widgets

Common attributes for all widgets:

  • data-component-id - the id of the used component
  • data-start-button - when true, a separate element / widget inside this widget's html should be marked as data-action="start" (the element that triggers the start action)

protocolform

A widget used to start one / one of several medical forms.

For example:

div(data-role="protocolform" data-component-id="myform") Click to start

Here is how you can define a form in the meta.json file

"forms": [
{
"id": "default",
"languages": [
"en"
],
"formName": "Main title goes here",
"patientDetails": {
"skip": true
},
"questions": [
{
"id": "birthDate",
"q": "Birthday",
"type": "form_select_date"
}
...
]
}
]

Find out more about the supported scenarios by Healee Forms here: Healee Forms Documentation

protocolpages

A widget used to show a separate view or a sequence of views.

Specific attributes for this widget:

  • data-pages - marks the holder of the elements which are used as pages / views
  • data-action - could be set to next or finish. Marks the element that shows the next page / view or the element that closes the nested pages
  • data-close-on-back - boolean property specifying whether the back button should take the user to the protocol's home page or to the previous page
  • data-stretched - boolean property specifying whether the new pages view should be stretched or not

e.g.

div(data-role="protocolpages" data-component-id="mypages" data-start-button="true")
div(data-action="start") Start
div(data-pages="true")
div
div Page 1
a(data-role="button" data-action="next") Page 2
div
div Page 2
a(data-role="button" data-action="finish") Finish

protocolproviders

A widget used to display the providers (doctors / specialists) associated with this protocol. Additional filters could be applied.

Kendo UI widgets

Kendu UI widgets that could be typically used in a protocol are: Button, ListView

7. Localization

Localization files

Localization files should be placed in the protocol's root folder and should comply to the following naming convention: local.[xx].jsx (e.g. local.en.jsx, local.de.jsx, etc.)

Example (local.es.jsx):

export default {
hello: "Hola"
};

Localization in layout

Localization strings could be used in the layout using Kendo UI's template syntax.

local is always the localization object for the user's currently selected language.

Example (layout.pug):

div #: local.hello #

Localization in expressions

All localizations are passed as the second argument for each expression's constructor (the first argument being the protocol itself).

E.g.

export default class Initial {
constructor(protocol, locals) {
this.protocol = protocol;
this.locals = locals;
}
...

locals.current could be used for accessing the currently selected language but the other languages could also be accessed through locals.[xx] (e.g. locals.en, locals.de, etc.)

7. Deep linking

Users can be navigated to a specific protocol via deep links.

E.g.

https://[my-healee-domain]/app-request/protocol/[protocol-id]+[component-id]+[parameter]

Where:

  • protocol-id is the id of the protocol (e.g. my-protocol)
  • component-id is the id of the component (e.g. welcome)
  • parameter is the parameter that will be passed to the onNavigate method that is part of the expressions' class for this component

When navigating to a tabbed protocol (protocol which appears as part of Healee's main navigation), protocol-id should be prefixed by tab-.

E.g.

https://[my-healee-domain]/app-request/protocol/tab-[protocol-id]+[component-id]+[parameter]

8. Resources

Resource files

Resource files (images, videos, etc.) could be placed in a res folder under the protocol's root folder.

Example:

info.json
layout.pug
res
hello.png
videos
world.mp4
...

Resource files in layout

When setting the src attribute for images, videos, etc., the getResUrl method should be used.

Example (layout.png):

img(src="#: getResUrl('hello.png') #"

Resource files in expressions

When constructing resource urls in expressions' code, the heal.client.protocolOperations.getResUrl method should be used.

Example:

const src = heal.client.protocolOperations.getResUrl(this.protocol, "hello.png");

Waiting for resources to load

When some resources should be loaded before the protocol becomes visible, the preloads attribute in the root (main protocol's) info.json file should be used, together with the resourceLoaded binding.

Example (info.json):

{
"name": "My protocol",
"preloads": [ "hello.png" ],
...
}

Example (layout.pug):

img(src="#: getResUrl('hello.png') #" data-bind="events: { load: resourceLoaded }")

9. Debugging

You can inspect the current object representation of the protocol you are developing directly in the browser.

You just need to open Healee's staging environment, open the debug console and type heal.client.protocolService.installedProtocols