Alerts
Links
- MTB-651Getting issue details... STATUS
- BRIDGE-3316Getting issue details... STATUS
https://sagebionetworks.jira.com/wiki/spaces/MTB/pages/2624421937
MobileToolbox: Website & Research-Facing App Screens (alerts UI Figma design)
Overview
Alerts are shown to researchers to notify them of important events in the study. Alerts are not shown to study participants. Alerts are currently study only (not app-level). Alert triggers and alerts themselves are not customizable by researchers.
Alerts have a read/unread state and can be resolved (deleted). Alerts cannot be recovered after deletion. APIs exist to mark alerts as read, mark alerts as unread, and delete alerts (all 3 are batch operations).
Alerts have a creation timestamp. When fetched, they are sorted by that creation timestamp (newest first).
Alerts have an associated participant which is referenced in the alert message (e.g., “Participant X enrolled in the study”). Alerts have a category determining what type of alert is shown, and alerts are filterable by alert category when fetched. A separate API exists which can fetch a list of alert categories which have at least 1 alert, and the number of alerts which exist in that category (read or unread).
Alerts are unique by app, study, associated participant, and category. New alerts which have the same app, study, associated participant, and category as an existing alert overwrite the existing alert, whether the existing alert is read or unread.
Alerts have associated data which is used to display the alert. For example, low adherence alerts will have an object with an “adherenceThreshold” which maps to a number. This allows the alert to be displayed with the adherence threshold in the message (e.g., if adherenceThreshold was 60, the alert could be displayed as “Participant X has adherence under 60%”). The associated data is JSON which has a category-specific schema.
Alert Categories
New enrollment
Triggered whenever a new participant has been enrolled in the study.
Associated data is null.
Low adherence
A participant has a lower weekly adherence than is specified by the study-configured adherence threshold value.
The adherence threshold (adherenceThresholdPercentage) must be set for the study in order for this alert to be triggered.
Triggered by the adherence worker, which runs periodically (specifically getWeeklyAdherenceReportForWorker).
Associated data is an object with a single key, “adherenceThreshold,” which contains the adherenceThresholdPercentage configured by the study at the time the alert was triggered.
Upcoming study burst
Not implemented
Timeline access
Triggered whenever a participant accesses their timeline and causes a “timeline retrieved” event to be fired.
Associated data is null.
Study burst update
Triggered whenever a “study burst” event is fired.
Associated data is null.
Steps To Trigger An Alert
New enrollment
Create a study.
Enroll a participant in the study.
Low adherence
Create a study.
Set the study’s adherenceThresoldPercentage to X%.
Create a schedule for the study.
Create an assessment.
Create N sessions for the schedule, each session referencing the assessment.
Enroll a participant in the study.
Have the participant submit M adherence records, such that M/N <= X%.
Wait for the adherence worker to run.
Upcoming study burst
Currently not triggerable.
Timeline access
Create a study.
Enroll a participant in the study.
Have the participant retrieve their timeline.
Study burst update
Create a study.
Create a schedule for the study.
Create a study burst for the schedule, with the study burst having a custom origin event.
Publish the custom event.
APIs
POST /v5/studies/{studyId}/alerts
Fetch alerts for a given study. Submit offsetBy and pageSize for paging. Submit an AlertFilter (containing a list of alert categories) to only retrieve alerts which match the categories in the AlertFilter. Returns an AlertList, which is a paged list of alerts.
POST /v5/studies/{studyId}/alerts/delete
Delete a batch of alerts. Submit an AlertIdCollection which contains a list of alert IDs. The alerts with those IDs will be deleted.
POST /v5/studies/{studyId}/alerts/read
Mark a batch of alerts as read. Submit an AlertIdCollection which contains a list of alert IDs. The alerts with those IDs will be marked as read.
POST /v5/studies/{studyId}/alerts/unread
Mark a batch of alerts as unread. Submit an AlertIdCollection which contains a list of alert IDs. The alerts with those IDs will be marked as unread.
GET /v5/studies/{studyId}/alerts/categories/counts
Fetch a list of alerts categories which have at least 1 alert, regardless of the read/unread state. The number of alerts in that category are also returned, regardless of the read/unread state. Returns an AlertCategoriesAndCounts.
Deletion
Alerts are deleted in the following cases:
Participant withdraws consent: all alerts referencing that participant are deleted for all studies in the app
Participant withdraws from app: all alerts referencing that participant are deleted for all studies in the app
Participant unenrolls from study: all alerts referencing that participant are deleted from the study
External ID is deleted: all alerts referencing that participant are deleted from the study
Study is deleted physically: all of that study’s alerts are deleted (not done in code, should be cascaded in SQL)
Study is deleted non-physically: all of that study’s alerts are deleted
Study is transitioned to “completed” phase: all of that study’s alerts are deleted
Internals
Alert model is not validated because users do not submit alerts. However, the AlertIdCollection and AlertFilter are validated.
AccountRef is injected before returning Alert; only userId is stored.
AlertCategoriesAndCounts is a list of objects instead of a map from category to count so that we can control the order they appear (alphabetical by category) and so that we can make category an enum in the SDK.
APIs to fetch and delete alerts are POST because GET and DELETE do not allow request bodies.
Table
CREATE TABLE IF NOT EXISTS `Alerts` (
`id` varchar(60) NOT NULL,
`createdOn` bigint(20) NOT NULL,
`studyId` varchar(60) NOT NULL,
`appId` varchar(60) NOT NULL,
`userId` varchar(255) NOT NULL,
`category` varchar(255) NOT NULL,
`data` varchar(2048) NOT NULL,
`isRead` boolean NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY (`appId`, `studyId`, `userId`, `category`),
INDEX (`appId`, `studyId`),
INDEX (`appId`, `studyId`, `userId`),
INDEX (`appId`, `studyId`, `category`),
INDEX (`appId`, `userId`),
CONSTRAINT `Alert-Account-Constraint` FOREIGN KEY (`userId`) REFERENCES `Accounts` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `Alert-Study-Constraint` FOREIGN KEY (`studyId`, `appId`) REFERENCES `Substudies` (`id`, `studyId`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;