MDMUI is a user-facing application designed to make it easy for administrators to accept or refute links created by MDM (Master Data Management). It includes the ability to search for a particular resource, view a list of all potential matches and potential duplicates, and assign tasks to users for workload management.
MDMUI currently supports FHIR R4 endpoints only.
NOTE: if you are using a reverse / web proxy, please see step 10 at the very bottom (last step).
MDM UI will create FHIR resources for its own workflow management, these will be tagged with the tag https://smilecdr.com/fhir/ns/mdm/ui/NamingSystem/tags|MDM_UI.
It will create new resources in the following scenarios:
MDM UI depends on having certain components already configured in Smile. Please follow these steps to configure a fresh Smile install to work with MDMUI.
FHIR MDM Server in the On this page sidebar on the right of the page to navigate to MDM mode setting.  Enable MDM mode (this will allow MDM module to work).FHIR Subscription Persistence in the On this page sidebar on the right side of the page to navigate to Subscription setting. Enable Message Subscription.StructureDefinition, which will be used by the front application.SMART Authorization in the On this page sidebar. Disable Enforce approved scopes to restrict permissions.Cross-Origin Resource Sharing in the On this page sidebar. Enable CORS to future MDMUI app port (cannot use * here due to logout URL constraints) (ie. http://localhost:8080)./smartauth/smartauth to the endSMART Callback Script section, add to the Post Authorization Script Text the following script: Post Authorization Text Script JS Script/json-adminCross-Origin Resource Sharing (CORS) section. Enable CORS to * (for testing purposes) or MDMUI app url (ie. http://localhost:8080).OpenID Connect Security./fhir-requesthttp://localhost:8000/fhir-request or https://<base URL>/fhir-request/)OpenID Connect SecurityCORS to * or MDM UI port (ie. http://localhost:8080)Add Client button to add a new OIDC clientAuthorization Code, Refresh Token, and JWT Bearer Tokenhttp://localhost:8080/ or other
port/context path of your choice (NOTE: this requires the context path as well, if one has been set --
http://localhost:8080/mdm-ui/ -- this context path can be set in step 8 when setting up MDM UI Module)cdr_all_user_authorities launch/patient launch/practitioner offline_access openid profileCreate Client to create the OIDC client.system|identifierhttp://localhost:9000/json-admin)MDM_UI)http://localhost:9200/smartauth)http://localhost:8080/mdm-ui/ - this is also set in OIDC Client)/smartauth if this was the context path set) for smart auth with the correct logout url (ie. http://localhost:9200/smartauth/logout?cb=none&revoke=token&revoke=token_refresh)8080) - should match the redirect URL of the OIDC client and any CORS settings configured
above/mdm-ui/) -- this should match the redirect URL above, and the
OIDC Client Authorized Redirect URLS savedFederated OAuth2/OIDC Login in smart_auth module;Enabled to YesAuthorization Code, Refresh Token, and JWT Bearer Tokenhttp://localhost:8080/)Client Secrets to Yescdr_all_user_authorities launch/patient launch/practitioner offline_access openid profileRemember User Approved Scopes to Yes<base Url>/keycloak/auth/realms/master)<base Url>/keycloak/auth/realms/master/protocol/openid-connect/auth<base Url>/keycloak/auth/realms/master/protocol/openid-connect/token<base Url>/keycloak/auth/realms/master/protocol/openid-connect/userinfo<base Url>/keycloak/auth/realms/master/protocol/openid-connect/certsopenid profileonAuthenticateSuccess function, update username for admin to any username for user added that you want to be an admin; you can also add an else if condition for data stewards.function onTokenGenerating(theUserSession, theAuthorizationRequestDetails, theClientDetails) {
    const userRole = theUserSession.getUserData('user_role');
    Log.info('User Role : ' + userRole);
    theAuthorizationRequestDetails.addAccessTokenClaim('user_role', userRole);
}
function onAuthenticateSuccess(theOutcome, theOutcomeFactory, theContext) {
    const userRole = theContext.getClaim('user_role');
    if (userRole === 'data_steward') {
        addDataStewardAuthorities(theOutcome);
    } else if (userRole === 'admin') {
        addAdminAuthorities(theOutcome);
    }
    theOutcome.setUserData('user_role', userRole);
    return theOutcome;
}
function addDataStewardAuthorities(outcome) {
    addCommonAuthorities(outcome);
    const readResourceTypes = ['CodeSystem'];
    const readAndWriteResourceTypes = ['AuditEvent', 'Task'];
    addReadAuthorities(outcome, readResourceTypes);
    addReadAndWriteAuthorities(outcome, readAndWriteResourceTypes);
}
function addAdminAuthorities(outcome) {
    addCommonAuthorities(outcome);
    const readAndWriteResourceTypes = ['AuditEvent', 'Task'];
    const readResourceTypes = ['SearchParameter', 'CodeSystem'];
    addReadAndWriteAuthorities(outcome, readAndWriteResourceTypes);
    addReadAuthorities(outcome, readResourceTypes);
    addSmileSpecificAuthorities(outcome);
}
function addCommonAuthorities(outcome) {
    const commonResourceTypes = ['Patient', 'Practitioner', 'StructureDefinition', 'Organization', 'PractitionerRole'];
    addReadAndWriteAuthorities(outcome, commonResourceTypes);
    addSmileSpecificAuthorities(outcome);
}
function addReadAndWriteAuthorities(outcome, resourceTypes) {
    resourceTypes.forEach(resourceType => {
        outcome.addAuthority('FHIR_READ_ALL_OF_TYPE', resourceType);
        outcome.addAuthority('FHIR_WRITE_ALL_OF_TYPE', resourceType);
    });
}
function addReadAuthorities(outcome, resourceTypes) {
    resourceTypes.forEach(resourceType => {
        outcome.addAuthority('FHIR_READ_ALL_OF_TYPE', resourceType);
    });
}
function addSmileSpecificAuthorities(outcome) {
    const smileSpecificAuthorities = [
        'FHIR_OP_MDM_DUPLICATE_GOLDEN_RESOURCES',
        'FHIR_OP_MDM_LINK_HISTORY',
        'FHIR_OP_MDM_MERGE_GOLDEN_RESOURCES',
        'FHIR_OP_MDM_NOT_DUPLICATE',
        'FHIR_OP_MDM_QUERY_LINKS',
        'FHIR_OP_MDM_UPDATE_LINK',
        'ACCESS_ADMIN_JSON',
        'CHANGE_OWN_DEFAULT_LAUNCH_CONTEXTS',
        'VIEW_BATCH_JOBS',
        'VIEW_MODULE_CONFIG',
        'VIEW_USERS',
    ];
    smileSpecificAuthorities.forEach(authority => {
        outcome.addAuthority(authority);
    });
}