Master Data Management (cFTE)

Main Scope of Problem

Master Data Management (MDM) is a method of managing an organization's critical data. A Master Data Management system is a comprehensive solution designed to create and maintain a single, consistent, accurate, and complete version of master data across an organization. Government and healthcare institutions provide a unique challenge for MDM systems as their workflows are often process driven based on current affairs. Correctly managing their data requires dynamic full stack frameworks that can quickly manage and implement complex workflows. These workflows can have user entry and visualization requirements based on time, location, employment and other fluid relationships.

Technical Requirements

  1. User Interface: Quickly generate interfaces that are personalized to each users requirements.
  2. API: Generate API endpoints for automated and coding based interfaces
  3. Analytics: Provide personalized views for analytic systems such as PowerBI or Tableau.
  4. Dynamic Permissions: Quickly enable and change user permissions on any set of given rules.
  5. Historical Record: Backup and recovery of data as well as seeing time based snap shots

cFTE Definitions

Clinical full-time effort (cFTE) typically refers to the amount of time a healthcare professional, such as a physician or researcher, dedicates to clinical activities. It implies that the individual is engaged in clinical work on a full-time basis, which may include patient care, consultations, procedures, and other clinical responsibilities. The specific definition can vary depending on institutional or contractual agreements.

A current data management issue in healthcare that rquires MDM like features is how to best maintain and update cFTEs. cFTEs are not strictly defined and there can be hundreds of definitions within an organizaiton. Each definition can be indepedently assigned to a provider at different points in time. The individuals responsible for maintaining a given providers cFTE changes daily. The cFTE system requires rules that can be quickly implmeneted to track responsibilities and accuracy of entered data. This cFTE information is often distributed at a system level to monitor productivity and distribute hospital resources to a department. Below are a few example calculations and their corresponding definitions.

Definitions

  1. cFTE = Total_FTE - (Academic_FTE + Research_FTE + Administrative_FTE)
  2. cFTE = clinical_effort/total_effort
  3. cFTE = (hrs_per_session*assigned_sessions + hrs_per_shift*assigned_shifts)/(hrs_per_session*max_sessions + hrs_per_shift*max_shifts)

Description

  1. The total effort is subtracted from the sum of sub appointment values. All parameters must be between 0 and 1
  2. Fraction of hours assigned for clinical work divided by the providers total appointment
  3. Shifts and sessions are nomenclature for a full and half days worth of work. Each shift and session is assigned a duration. The cfte is calculated as fraction of hours worked based on appointed shifts and sessions

Data Schema Structure

Below is an example structure of the schema used to managed provider cfte data. The users table maintains information of the organizations staff. Users can be providers, managers and/or other employees of the company. Each user belongs to one or more departments. The time that a user is employed by a department are stored in the start and end dates. A manager can maintain a providers cfte information based on if the provider is managed by the user based on departamental and employment overlap. Each user can modify their own cfte data. Each record change for each table is stored indefinitely. The time the record was created/modified and the endpoint of activity is stored in each tables valid column. Managers are generally responsible for the provider_effort and cfte_definitions table. Everything else is managed by the systems active directory. The person who last changed the record is stored in the last_modified_by column.

Centered image

Fast Apps

The user interfaces for data collection are powered by AgGrid. The table and data entry structure for a given cfte rule is stored in the cfte_definitions.definition column. This column is a json configuration that defines the cfte and user interface rules. AgGrid allows for custom data components to be created for more complicated use cases. The important note is that any created cfte rule will automatically map to a UI display and API endpoint. Below is an example json configuration and how the entry form would be displayed by the end user.

        [
  {field: 'name',  type: 'string'},
  {field: 'sport', type: 'json'  }, 
  {field: 'date',  type: 'date'  },
  {field: 'wins',  type: 'int'   }
]

    
Centered image

Time Travel, Row Level Security and Dynamic views

A core component of an MDM system is the ability to time travel. Seeing how the state of data has changed between iterations. This is achieved in postgres by changing the default behavior of crud operations using views, indexes and triggers. User information are contained in JWT tokens. User credentials are dynamically injected into dynamic views to create the proper RLS restraints. Below is an example of creating RLS and as of queries with the provider_effort table. This approach is added to each table individually.

        --base table structure for storing all effort data
CREATE EXTENSION IF NOT EXISTS btree_gist;
CREATE TABLE provider_effort
(
    id               big serial,    --record id should not be changed
    "valid"          tstzrange,     --maintains record version
    user_id          big integer,   --user_id in this context should be a provider
    effective_date   date,          --when the cfte values should take precedence
    cfte_def_id      big integer    --the cfte definition id from the cfte_definitions table
    cfte             json,          --contains the cfte information. 
    last_modified_by big integer    --the user who made the last change
    EXCLUDE USING gist (id WITH =, valid WITH &&)
);
/*
EXCLUDE USING gist (id WITH =, valid WITH &&)
EXCLUDE: Indicates that an exclusion constraint is being defined.
USING gist: Specifies that the constraint will use a GiST index.
(id WITH =, valid WITH &&): Defines the exclusion condition. In this case, it's a combination of two conditions:
id WITH =: Specifies that the id column values must be equal for the rows being compared.
valid WITH &&: Specifies that the valid column values must have overlapping ranges. The && operator is the "overlaps" operator for range types.
*/

    
        --the current valid cfte records
CREATE VIEW current_provider_effort as
SELECT user_id, effective_date, cfte_def_id, cfte, last_modified_by
FROM provider_effort
WHERE current_timestamp <@ valid

    
        /*
The version trigger overwrites the basic insert, update and delete operations inorder to maitain
the provider_effort historical record.
*/
CREATE FUNCTION version_trigger() RETURNS trigger AS
$$
BEGIN
    IF TG_OP = 'UPDATE'
    THEN
        IF NEW.id <> OLD.id
        THEN
            RAISE EXCEPTION 'the ID must not be changed';
        END IF;
 
        UPDATE  provider_effort
        SET     valid = tstzrange(lower(valid), current_timestamp)
        WHERE   id = NEW.id
            AND current_timestamp <@ valid;
 
        IF NOT FOUND THEN
            RETURN NULL;
        END IF;
    END IF;
 
    IF TG_OP IN ('INSERT', 'UPDATE')
    THEN
        INSERT INTO provider_effort (id, valid, user_id, effective_date, cfte_def_id, cfte, last_modified_by)
            VALUES (NEW.id,
                tstzrange(current_timestamp, TIMESTAMPTZ 'infinity'),
                NEW.user_id,
                NEW.effective_date,
                NEW.cfte_def_id,
                NEW.cfte,
                NEW.last_modified_by
                );
        RETURN NEW;
    END IF;
 
    IF TG_OP = 'DELETE'
    THEN
        UPDATE  provider_effort
        SET     valid = tstzrange(lower(valid), current_timestamp)
        WHERE id = OLD.id
            AND current_timestamp <@ valid;
 
        IF FOUND THEN
            RETURN OLD;
        ELSE
            RETURN NULL;
        END IF;
    END IF;
END;
$$ LANGUAGE plpgsql;
 
CREATE TRIGGER vtrigger
    INSTEAD OF INSERT OR UPDATE OR DELETE
    ON current_effort
    FOR EACH ROW
    EXECUTE PROCEDURE version_trigger();

    
        /*
Using the current_settings overload the view and transaction below provides a method to view
the cfte records at any given point in time.
*/
CREATE VIEW as_of_provider_effort AS
    SELECT  user_id, effective_date, cfte_def_id, cfte, last_modified_by
    FROM    provider_effort
    WHERE   current_setting('app.as_of_time')::timestamptz <@ valid;

--Run Query
BEGIN;
SET app.as_of_time = {datetime value};
SELECT * FROM as_of_provider_effort;
COMMIT;

    
        /*
Updatable views provide a way to cleanly enforce column and row level security. Any data modification that
invalidated the where condition will be rejected. This has three conditional change requirements
1.) The user is a manager of a provider. The user was a manager of a department when the provider was employed by
the department. The effective date used falls withing that overlap.
2.) The user modifiying the data is the provider
3.) The user is an admin. 

*/
CREATE VIEW user_department as
SELECT * FROM department_employees
WHERE user_id = current_setting('app.user_id');


CREATE VIEW provider_effort_user_perms
SELECT * FROM current_effort
WHERE 
( 
  
  EXISTS 
  ( 
    --provider in users department
    SELECT 1
    FROM  users 
    WHERE current_effort.provider_id  = users.id
      AND users.is_provider = true
      AND  current_effort.provider_id IN
      (SELECT user_id
        FROM department_employees
        WHERE department_id IN (select department_id FROM user_department )
        AND current_effort.effective_date BETWEEN department_employees.start_date AND department_employees.end_date    
      )
  )
  AND
  EXISTS (
    --is manager
    SELECT 1
    FROM users
    WHERE users.id = current_setting('app.user_id') AND users.is_manager = true
  )

) OR
EXISTS ( 
--user is provider  
SELECT 1
FROM users
WHERE users.id = provider_id AND users.id = current_setting('app.user_id')
) OR
current_setting('app.user_is_admin') = true

    
        --enforces rls permissions on all modification queries
BEGIN;
SET app.user_id = {user_id};
--crud_statement i.e. select/insert/update/delete--
COMMIT;

    

Conclusion

The integration of Postgres, JWT and AgGrid provides an easily extensible environment for managing MDM systems. With a little work any use case can be implemented. The primary advantage is that things are really easy from an application point of view to implement. Implementing time travel can be done quite generically and most applications might not have to be changed at all. Most changes can be made live through changes to json configuration files. New UI components will require the standard DevOps CI/CD approach. However, once all unique components have been implemented, any standard SQL user can maintain and extend the cfte collection process.