Creating and activating plan v2.0 - Action Refactor

Creating and activating plan v2.0 - Action Refactor



Document Revision

Date

Version

Description of change

Author

22 December 2021

1.0

Initial document

Stefanus Heath

Overview

This document outlines the process of creating a plan within the Reveal platform.

Definitions, Acronyms and Abbreviations

Name

Description

 

 

 

Form

A form refers to the json representation of the process of collecting data against a task.  The form is stored as a JSON object.  This form will be sync’d to the Reveal Client for use in task presentation.

We will create a form library which contains pre-built forms that can be easily copied into the plan creation process.

For all resources where isTemplate is true, the form_template permission must be present in the token.

THOUGHTS ON THE WORD QUESTIONNAIRE

Form list

GET /api/v1/form

Search parameters as path parameters can be any combination of:

  • search

  • isTemplate

{    "content": [...],

    "totalItems": 100,

    "totalPages": 4,

    "currentPage": 1}

Form fetch

GET /api/v1/form/{identifier}

{    "identifier": guid,

    "name": string,

    "title": string,

    "isTemplate": boolean,    "payload": jsonb}

Form create

GET /api/v1/form

{    "name": string, // ^[0-9a-z](\d|[0-9a-z]|-){2,30}$ and immutable

    "title": string,

    "isTemplate": boolean, // immutable    "payload": jsonb,

    "version": string}

Form update

PUT /api/v1/form/{identifier}

{

    "title": string,    "payload": jsonb}

Form delete

DELETE /api/v1/form/{identifier}

Plan

Plan refers to the definition of a target group of objects, whether by geographic or other criteria, for which a set of tasks are generated.  These tasks define the collection of data against the target objects within the plan.  Typical examples are:

Indoor Residual Spray (IRS)

  • Visit each structure in the operational area and attempt to spray

Mass Drug Administration (MDA)

  • Register all families & family members in all residential structures enumerated (100%) within the operational area

  • Visit all residential structures (100%) and dispense prophylaxis to each registered person

  • Visit all residential structures (100%) and confirm adherence of each registered person

Each task completion results in an event describing the output of the task.  The event is populated from the form associated with the task.

What are we doing, what goals do we want to achieve, against actions, that creates tasks to accomplish this goal

Within the planned current usage of the plan object, although changes will be made to the existing model, the plan definition model fully adheres to the FHIR definitions as defined in https://www.hl7.org/fhir/plandefinition.html .

What is required is that the backend validates the complete freeform nature of the plan object, in order to make it more resilient to usage.  The frontend must be better controlled in terms of templating, in order to avoid the freeform nature of the plan object.

Goal

A goal is a component of a plan that provides a target against a due date which tracks the trajectory of a plan.  A plan can have several goals, which can be driven by different actions.  This means that a plan can be a multi-dimensional construct that has several goals to achieve.  Each set of processes can be tracked against individual goals, but this has not been typically the case in the past.

The example below shows the typical implementation of a goal for IRS over 2020 and 2021, which uses goal as a soft placeholder without real meaning.   The due date is not part of the actual planning process and has no real meaning in terms of the on the ground planning.  Also goals are here mapped to be an ideal end state, which can be implemented with more meaning on the front-end to provide significant power to the planners.  Goals have been historically loaded against the core task such as spray, where the other tasks have been treated as ad-hoc and/or ancillary, but using a correct planning approach other tasks can be brought into their own goals and form part of the complete plan.

Recommendation of the writer:  a full and proper discussion should be scheduled to provide full context of how this could work, and the power that could be derived from this construct.  Please bear in mind that this construct comes from the FHIR concept of plan, it does cater for implementations such as IRS very effectively, and thus could improve the thought process around planning. 

example:

"goal": [

    {

        "id": "IRS_Verification",

        "description": "Submit one verification form per operational area",

        "priority": "medium-priority",

        "target": [

            {

                "measure":"Percent of forms submitted",

                "detail": {      

                    "detailQuantity":{

                        "value": 100.0,

                        "comparator":"gt;",

                        "unit": "Percent"

                    }

                },

                "due": "2022-05-31"

            }

        ]

    }

]

 

concept one:  

"goal": [

    {

        "id": "IRS_Verification",

        "description": "Submit one verification form per operational area",

        "priority": "medium-priority",

        "target": [

            {

                "measure":"Percent of forms submitted",

                "detail": {      

                    "detailQuantity":{

                        "value": 70.0,

                        "comparator": "gt;",

                        "unit": "Percent"

                    }

                },

                "due": "2022-05-31"

            },

            {

                "measure":"Percent of forms submitted",

                "detail": {      

                    "detailQuantity":{

                        "value": 85.0,

                        "comparator": "gt;",

                        "unit": "Percent"

                    }

                },

                "due": "2022-06-31"

            },

            {

                "measure":"Percent of forms submitted",

                "detail": {      

                    "detailQuantity":{

                        "value": 100.0,

                        "comparator": "eq;",

                        "unit": "Percent"

                    }

                },

                "due": "2022-07-31"

            }

        ]

    }

]

 

concept two:  

"goal": [

    {

        "id": "IRS_Verification",

        "description": "Submit one verification form per operational area",

        "priority": "medium-priority",

        "target": [

            {

                "measure":"Percent of forms submitted",

                "detail": {      

                    "detailQuantity":{

                        "value": 100.0,

                        "comparator": "gt;",

                        "unit": "Percent"

                    }

                },

                "due": "2022-05-31"

            }

        ]

    },

    {

        "id": "IRS_daily_summary",

        "description": "Submit one daily summary form per operational area",

        "priority": "medium-priority",

        "target": [

            {

                "measure":"Percent of forms submitted",

                "detail": {      

                    "detailQuantity":{

                        "value": 100.0,

                        "comparator": "gt;",

                        "unit": "Percent"

                    }

                },

                "due": "2022-05-31"

            }

        ]

    }

]

 

Action

The Action component of a plan defines the tasks that need to be performed to accomplish the goal.  It is used to determine the conditions and triggers under which tasks should be generated.  Triggers refer to the preceding function that would cause the evaluation of the plan to determine if new tasks need to be generated. The conditions determine under which circumstances the task generation process will generate the required task, such as location, jurisdiction or person with certain criteria.  Action links a form to a goal in order to create a task.

Trigger definition

The trigger section defines the condition under which a task must be generated.  The trigger is ENUM that defines when an action item is evaluated.

List of ENUMS:

  • plan-activation

  • plan-jurisdiction-modification

  • event-submission

Condition definition

The condition section defines under which conditions a subject is considered to receive a task.  The current condition implementation implements the targeting of subjects using FHIR path expressions.  This functionality needs to be abstracted.

Process:

  • Inspect the trigger causing the evaluation

  • Inspect the if the subject is covered by the plan

  • Inspect if the status of the subject is within the conditions

  • Inspect if the trigger should affect other tasks on other plans of the same action against the same 

Recommendation of the writer:  Using FHIR path expressions makes the current system unusable without explicit development and FHIR coding experience.  This element should be abstracted into predetermined conditions.   All of the below require intensive understanding in order to know the meaning.

Previous examples of FHIR path expressions

Elements:

  • Questionnaire

    • questionnaire = 'Register_Structure' meaning that questionnaire is the name of the response

  • QuestionnaireResponse

    • $this.is(FHIR.QuestionnaireResponse) meaning 

  • Location

    • $this.is(FHIR.Location) meaning that the location must exist which seems to be pointless in terms of joining

    • $this.item.where(linkId='structureType').answer.value = 'Residential Structure' meaning that an answer in the questionnaire must be something specific

Condition examples to consider

  • Location

    • Location is in the active plan

    • Location has been registered and falls within the active plan

  • Person

    • birthDate evaluation to determine a certain age; here we should consider the fact that age as considered at the start of the plan

    • gender evaluation

    • location evaluation; to determine if a person requires a task based on a relationship to a specific location

    • previous state evaluation; to determine if a person requires a task based on a previous state contained in metadata

  • Event

    • the Event of specified name is triggered

    • the Event is evaluated based on payload values



Plan search

GET /api/v1/plan

Search parameters as path parameters can be any combination of:

  • title

  • status

  • interventionType

  • jurisdiction

{    "content": [...],

    "totalItems": 100,

    "totalPages": 4,

    "currentPage": 1}

Plan count aggregate

GET /api/v1/plan?_summary=count

Supports all the search parameters as above

{    "count": 8}

Plan fetch

GET /api/v1/plan/{planIdentifier}

Path parameters for _summary=true will not return the jurisdiction, goal and action objects, _summary=false (default) will return jurisdiction, goal and action objects.

{    "identifier": guid,

    "name": string, // [a-z0-9\-]

    "title": string, // [a-zA-Z0-9\-\ ]

    "status":  enum, // draft, active, retired, unknown

    “status”: {

        “identifier” :guid,

        “name”: string

    }

    "date": date, // last_modified_date (YYYY-MM-DD)

    "effectivePeriod": {

        "start": date, // (YYYY-MM-DD)

        "end": date // (YYYY-MM-DD)

    },

    “interventionType”:{

          “Identifier”:guid,

          “name” :string,

          “description”:string

    },

    “locationHierarchyIdentifier”:guid

    "useContext": [

        {

            "code": "interventionType",

            "valueCodableConcept": enum // IRS, IRS-Lite, MDA, MDA-Lite

        },

        {

            "code": "locationHierarchy",

            "valueCodableConcept": guid // the identifier of the locationHierarchy in use

        }

    ],

    "jurisdiction": [

        {

            "code": [guid,guid,guid]

        }

    ],

    "jurisdiction": [guid,guid,guid],

    "goal": [

        {

            "identifier": string,

            "description": string,

            "priority": enum, // high-priority, medium-priority, low-priority

            "target": [

                {

                    "measure": string,

                    "detail": {

                        "detailQuantity": {

                            "value": int,

                            "comparator": "gt;=",

                            "unit": enum // percent

                        }

                    },

                    "due": date

                }

            ]

        }

    ],

    "goal": [

        {

            "identifier": string,

            "description": string,

            "priority": enum, // high-priority, medium-priority, low-priority

            "target": [

                {

                    "measure": string,

                    "detail": {

                        "detailQuantity": {

                            "value": int,

                            "comparator": "gt;=",

                            "unit": enum // percent

                        }

                    },

                    "due": date

                }

            ],

            “entityType” :{

               “identifier” : guid,

               “name”: string

            },

            "action": [

                {

                  "identifier": guid,

                  "title": string,

                  "description": string,

                  "code": string,

                  “trigger”:????

                  "timingPeriod": {

                     "start": date,

                     "end": date

                   },

                   "reason": enum

                },

               “form” : {

                  “identifier”: guid,

                  “name”: string

               },

               "target": [

                   {

                    "description":string,

                    "priority": enum, // high-priority, medium-priority,low-priority

                    "measureType": string,

                    “metaDataTag”:string, 

                    “metric”:integer,                   

                    "due": date

                }],

            ],

            "type": enum // create, update, remove

        }

    ],



    "action": [

        {

            "identifier": guid,

            "title": string,

            "description": string,

            "code": string,

            "timingPeriod": {

                "start": date,

                "end": date

            },

            "reason": "Routine",

            “goal”: {

               "identifier": string,

               "description": string,

               "priority": enum, // high-priority, medium-priority, low-priority

               "target": [

                   {

                       "measure": string,

                       "detail": {

                          "detailQuantity": {

                            "value": int,

                            "comparator": "gt;=",

                            "unit": enum // percent

                        }

                       },

                       "due": date

                   }

              ]

         }

            "goalId": fk_to_goalIdentifier,

            "subjectCodableConcept": {

                "text": enum, // location, person

            },

          "trigger": [

                {

                    "type": "named-event",

                    "name": enum // plan-activation, plan-jurisdiction-modification, event-creation

                }

            ],

            "condition": [

                {

                    "kind": "applicability",

                    "expression": {

                        "description": "Structure type does not exist",

                        "expression": "$this.is(FHIR.Location)"

                    }

                }

            ],



            "definitionUri": string, // path to json,

            "type": enum // create, update, remove

        }

    ]

}

 

Plan create

POST /api/v1/plan

A plan can only be created with a status of DRAFT, due to the fact that planning and targeting must be done before the plan can be activated.

The jurisdiction fields may be empty as it will come from planning, but screens to step through the selection of jurisdictions will work similar to the current functionality.  Future enhancements refer to documentation on the planning module.

Due to the nature of the link between goal and link the plan should be loaded over several forms that complete with a POST and subsequent PUT operations.  Until all minimum requirements have been met a plan cannot be changed to ACTIVE

{

    "name": string, // [a-z0-9\-] IMMUTABLE

    "title": string, // [a-zA-Z0-9\-\ ]

    "status": enum, // draft, active, retired, unknown

    "effectivePeriod": {

        "start": date, // (YYYY-MM-DD)

        "end": date // (YYYY-MM-DD)

    },

    "useContext": [

        {

            "code": "interventionType",

            "valueCodableConcept": enum // IRS, IRS-Lite, MDA, MDA-Lite

        },

        {

            "code": "locationHierarchy",

            "valueCodableConcept": guid // the identifier of the locationHierarchy in use

        }



    ],

    "hierarchy": [

        {

            "code": [guid,guid,guid]

        }

    ],

    "goal": [

        {

            "identifier": string,

            “title” : string,

            "description": string,

            "priority": enum, // high-priority, medium-priority, low-priority

            "target": [

                {

                    "measure": string,

                    "detail": {

                        "detailQuantity": {

                            "value": int,

                            "comparator": "gt;=",

                            "unit": enum // percent

                        }

                    },

                    "due": date

                }

            ]

        }

    ],

    "action": [

        {

            "title": string,

            "description": string,

            "code": string,

            "timingPeriod": {

                "start": date,

                "end": date

            },

            "reason": "Routine",

            "goalId": fk_to_goalIdentifier,

            "subjectCodableConcept": {

                "text": enum, // location, person

            },

            "trigger": [

                {

                    "type": "named-event",

                    "name": enum // plan-activation, plan-jurisdiction-modification, event-creation

                }

            ],

            "condition": [

                {

                    "kind": "applicability",

                    "expression": {

                        "description": "Structure type does not exist",

                        "expression": "$this.is(FHIR.Location)"

                    }

                } 

            ],

            "definitionUri": string, // FK to form

            "type": enum // create, update, remove

        }

    ]

}

 

 

GET /api/v1/plan/{identifier}

GET /api/v1/plan/{identifier}/goal

POST /api/v1/plan/{identifier}/goal

PUT /api/v1/plan/{identifier}/goal/{identifier}

GET /api/v1/plan/{identifier}/action

POST /api/v1/plan/{identifier}/action

PUT /api/v1/plan/{identifier}/action/{identifier}

GET /api/v1/plan/{identifier}/jurisdiction

POST /api/v1/plan/{identifier}/jurisdiction

PUT /api/v1/plan/{identifier}/jurisdiction/{identifier}

Activating a plan

Once a plan has at least one jurisdiction, one goal and one action before it can be activated.  In order to have an action at least one form is required.  Each action must have a form.

Once plan has been activated the following elements become immutable:

  • effectivePeriod => start

  • useContext => interventionType

  • ??GOAL??

  • action => code

  • action => timing??

  • action =>

Task evaluation

On plan activation

On plan activation the task generation executes.  It selects all conditions that are loaded into the plan and evaluates whether a task should be created.  This includes checking if a duplicate task exists for the element, then if no task exists then if the conditions are met for the evaluation.

On plan modification

Each time the plan is modified the task generation function should re-evaluate task generation.

On event submission

Each time a new location or person is created, then task generation should evaluate that object.

Task

Task refers to the object that links and drives the questionnaire against the target object.

Within the planned current usage of the task object, although minor changes will be made to the existing model, the task definition model fully adheres to the FHIR definitions as defined in https://www.hl7.org/fhir/task.html .

Task search

GET /api/v1/task

Search parameters as path parameters can be any combination of:

  • planIdentifier

  • status

  • code

  • for

  • groupIdentifier/location??

{    "content": [...],

    "totalItems": 100,

    "totalPages": 4,

    "currentPage": 1}

Task count aggregate

GET /api/v1/task?_summary=count

Supports all the search parameters as above

{    "count": 8}

Task fetch

GET /api/v1/task/{taskIdentifier}

{

    "identifier": guid,

    "planIdentifier": guid,

    "focus": guid, // What task is acting on (fk of target object) -> Location

    "action": {

       “identifier”: guid,

       “form” : {}   

    },

    "code": string, // fk of action code from plan

    "status": enum, // ready, cancelled, completed

    "status": {

       “identifier”: guid,

       “name” : string    

    }, 

    "priority": enum, // routine, urgent, asap, stat

    "description": string, // as defined by the action of the plan

    "businessStatus": enum, // needs definition

    "executionPeriod": {

        "end": datetime, // as defined by plan

        "start": datetime // as defined by plan

    },

    "groupIdentifier": guid // refers to the Operational Area’ identifier for sync

    "form": form_URI // as defined in the plan action

}

 

 

NOTES ON DEFINITION OF ACTION:

We should look at the code that actually does task duplication so that we can look at effectively growing and shrinking tasks.  Also we need to understand the impact of creating many tasks that are not being acted upon.

Task create

POST /api/v1/task

{

    "planIdentifier": guid,

    "focus": guid, // What task is acting on (fk of target object)

    "code": string, // fk of action code from plan

    "status": enum, // ready, cancelled, completed

    "priority": enum, // routine, urgent, asap, stat

    "description": string, // as defined by the action of the plan

    "businessStatus": enum, // needs definition

    "executionPeriod": {

        "end": datetime, // as defined by plan

        "start": datetime // as defined by plan

    },

    "groupIdentifier": guid // refers to the Operational Area’ identifier for sync

    "instantiatesUri": form_URI // as defined in the plan action

}

Task update

PUT /api/v1/task/{identifier}

{

    "status": enum, // ready, cancelled, completed

    "priority": enum, // routine, urgent, asap, stat

    "description": string, // as defined by the action of the plan

    "businessStatus": enum, // needs definition

    "executionPeriod": {

        "end": datetime, // as defined by plan

        "start": datetime // as defined by plan

    }

}

Related content