Service - Notification Manager: Difference between revisions

From Izara Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
Line 11: Line 11:
= DynamoDB tables =
= DynamoDB tables =


== [[Standard Config Table Per Service]] ==
== PendingConsolidation Table ==


=== Configuration tags ===
; partition key
* notificationGroupId
: type: string
: {reciverTag} + "_" + {groupingId}
; sort key
* time
: type: number
: {timestamp activity handled in Activity Switchboard}_{small random UUID}


<syntaxhighlight lang="JavaScript">
= Object Schemas =
{
 
configKey: "ActivitySwitchboardServiceName"
; Additional Information: [[Per Service Schemas]]
configTag: "ActivitySwitchboardServiceName"
 
configValue: {eg: "ActivitySwitchboard"}
== objType ==
}
</syntaxhighlight>


== NotificationGroups ==
=== notificationGroup ===


* Groups many notificatons together
* Groups many notificatons together
Line 29: Line 34:
* Allows for consolidation of notifications at notification group level
* Allows for consolidation of notifications at notification group level


=== Fields ===
<syntaxhighlight lang="JavaScript">
{
objectType: "notificationGroup",
canDelete: false,
    complexFilterServiceTag: "complexFilter",
addOnDataStructure: [
{
type: "versionedData",
versionedDataLabel: "notificationGroupSetting",
storageResourceTag: "myGraph",
fieldNames: [
{ // fieldName in versionedData should now same in main objectSchema
fieldName: "notificationGroupName"
},
{
fieldName: "consolidated",
},
{
fieldName: "consolidatedType"
},
{
fieldName: "consolidatedFrequency"
},
{
fieldName: "consolidatedSendIfEmpty"
}
]
}
    ],
    overwriteGeneratedMainFunction: ["create", "get", "update"],
    storageResources: {
myGraph: {
storageType: "graph",
graphServerTag: "GraphHandler"
}
    },
    fieldNames: { // see Per Service Schemas
notificationGroupId: {},
additionalData: {}
    },
    identifiers: [
{
type: "identifier",
fieldName: "notificationGroupId"
}
    ]
}
</syntaxhighlight>
 
==== fieldNames ====


; notificationGroupId
; notificationGroupId (identifier)
: (partition key)
: comes from: {receiverTag}_{groupingId} (Old)
: comes from: {receiverTag}_{groupingId}
: eg receiverTag: ContactMethodEmail
: eg receiverTag: ContactMethodEmail
: eg groupingId: {userId}, cannot include underscores
: eg groupingId: {userId}, cannot include underscores
; uniqueId
: '''New Idea! comes from use notificationGroupUniqueId as notificationGroupId'''
: (sort key)
: ''' eg {"ContactMethodEmail_randomIdA_randomIdB"}'''
: given by the receiver service, expected to be unique partition key. Partition key is set by receiver so up to receiver to make sure this is unique
: eg for emails [[Service - User Contact Manager]] creates this as: {userContactId}_{uuid created by UCM service}, userContactId is ContactMethodEmail_{uuid created by Email service}, this allows filtering for a specific email record using beginsWith
; notificationGroupName
; notificationGroupName
: string name set by reciever service, optional
: string name set by reciever service, optional
; notificationIds
; additionalData
: String Set of notificationIds in this group (https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html)
: set by the creating service, gets added to notifications sent to the receiver
: eg: can include the actual userId and  used to make the groupingId
; consolidated
; consolidated
: true|false
: true|false
Line 49: Line 101:
; consolidatedType
; consolidatedType
: overview|detailed
: overview|detailed
: overview sends a count of each type of notification, detailed lists each activity message
: ''overview'' sends a count of each type of notification, ''detailed'' lists each activity message
; consolidatedFrequency
; consolidatedFrequency
: not sure, maybe use some sort of standard like cron
: not sure, maybe use some sort of standard like cron
Line 56: Line 108:
; consolidatedSendIfEmpty
; consolidatedSendIfEmpty
: true|false
: true|false
; additionalData
: set by the creating service, gets added to notifications sent to the receiver
: eg: can include the actual userId and  used to make the groupingId
; timeDisabled
: timestamp when disabled or 0 for enabled


== Notifications ==


* no sort key
=== notification ===
 
<syntaxhighlight lang="JavaScript">
{
objectType: "notification",
canDelete: false,
complexFilterServiceTag: "complexFilter",
    overwriteGeneratedMainFunction: ["create", "get", "update"],
    storageResources: {
myGraph: {
storageType: "graph",
graphServerTag: "GraphHandler"
}
    },
    fieldNames: {
notificationId: {},
notificationName: {}
    },
    identifiers: [
{
type: "identifier",
fieldName: "notificationId"
}
    ]
}
</syntaxhighlight>


=== Fields ===
==== fieldNames ====


; notificationId
; notificationId (identifier)
: (partition key)
: hash of object containing {notificationName, triggers}
: hash of object containing notificationGroupId, notificationName, triggers
; notificationGroupId
; notificationName
; notificationName
: string name set by reciever service, optional
: string name set by reciever service, optional
; triggers
: array/list of triggers that must match for this notification to happen, see [[#Triggers structure]]
; timeDisabled
: timestamp when disabled or 0 for enabled


== PendingConsolidation ==


=== Fields ===
=== notificationTrigger ===
 
array/list of triggers that must match for this notification to happen, see [[#Triggers structure]]
 
<syntaxhighlight lang="JavaScript">
{
objectType: "notificationTrigger",
canDelete: false,
    complexFilterServiceTag: "complexFilter",
    overwriteGeneratedMainFunction: ["create", "get"],
    storageResources: {
myGraph: {
storageType: "graph",
graphServerTag: "GraphHandler"
}
    },
    fieldNames: {
notificationTriggerId: {},
propertyName: {},
valueType: {},
value: {},
values: {}
    },
    identifiers: [
{
type: "identifier",
fieldName: "notificationTriggerId"
}
    ]
}
</syntaxhighlight>
 
==== fieldNames ====
 
; notificationTriggerId (identifier)
: '''New Idea; comes from: {notificationId}_{small random UUID}'''
; propertyName
: can be a nested property, use dot notation
: "serviceName" and "topicName" valueTypes do not have propertyName
; valueType
: property|attribute|serviceName|topicName
; value
: {string or number}
; values
: {array/list of value}


; notificationGroupId
 
: (partition key)
=== consolidated ===
; time
 
: (sort key)
<syntaxhighlight lang="JavaScript">
{
objectType: "consolidated",
canDelete: false,
    complexFilterServiceTag: "complexFilter",
    storageResources: {
dynamoDB: {
storageType: "dynamoDB",
graphServerTag: "PendingConsolidation"
}
    },
    fieldNames: {
notificationGroupId: {},
time: {},
activityMsg: {}
    },
    identifiers: [
{
type: "partitionKey",
fieldName: "notificationGroupId"
},
{
type: "sortKey",
fieldName: "time"
}
    ]
}
</syntaxhighlight>
 
==== fieldNames ====
 
; notificationGroupId (partition key)
: '''comes from use notificationGroupUniqueId as notificationGroupId (by Pong 2/7/2024)'''
: '''eg {"ContactMethodEmail_randomIdA_randomIdB"}'''
; time (sort key)
: comes from {timestamp activity handled in Activity Switchboard}_{small random UUID}
: comes from {timestamp activity handled in Activity Switchboard}_{small random UUID}
: adding the UUID to ensure no clashing records with the same timestamp and notificationGroupId
: adding the UUID to ensure no clashing records with the same timestamp and notificationGroupId
; activityMsg
; activityMsg
: copy of the message delivered from Activity Switchboard
: copy of the message delivered from Activity Switchboard
== Object Relationships ==
=== has_notificationGroup ===
<syntaxhighlight lang="JavaScript">
{
"has_notificationGroup": {
properties: {
originTimestamp: {...}
},
storageResources: {
myGraph: {
storageType: "graph",
graphServerTag: "graphHandler"
}
},
links: [
{
storageResourceTags: ["myGraph"],
from: {
objType: {
serviceTag: "ContactMethodEmail",
objectType: "email"
},
linkType: "one",
},
to: {
objType: {
serviceTag: "NotificationMgr",
objType: "notificationGroup"
},
requiredOnCreate: true,
linkType: "many",
handler: true
}
}
]
}
}
</syntaxhighlight>
=== disabled_notificationGroup ===
<syntaxhighlight lang="JavaScript">
{
"disabled_notificationGroup": {
properties: {
originTimestamp: {...}
},
storageResources: {
myGraph: {
storageType: "graph",
graphServerTag: "GraphHandler"
}
},
links: [
{
storageResourceTags: ["myGraph"],
from: {
objType: {
serviceTag: "ContactMethodEmail",
objectType: "email"
},
linkType: "one"
},
to: {
objType: {
serviceTag: "NotificationMgr",
objType: "notificationGroup"
},
linkType: "many",
handler: true
}
}
]
}
}
</syntaxhighlight>
=== has_notification ===
<syntaxhighlight lang="JavaScript">
{
"has_notification": {
properties: {
originTimestamp: {...}
},
storageResources: {
myGraph: {
storageType: "graph",
graphServerTag: "GraphHandler"
}
},
links: [
{
storageResourceTags: ["myGraph"],
from: {
objType: {
serviceTag: "NotificationMgr",
objectType: "notificationGroup"
},
linkType: "one",
handler: true
},
to: {
objType: {
serviceTag: "NotificationMgr",
objType: "notification"
},
requiredOnCreate: true,
linkType: "many",
handler: true
}
}
]
}
}
</syntaxhighlight>
=== disabled_notification ===
<syntaxhighlight lang="JavaScript">
{
"disabled_notification": {
properties: {
originTimestamp: {...}
},
storageResources: {
myGraph: {
storageType: "graph",
graphServerTag: "graphHandler"
}
},
links: [
{
storageResourceTags: ["myGraph"],
from: {
objType: {
serviceTag: "NotificationMgr",
objectType: "notificationGroup"
},
linkType: "one",
handler: true
},
to: {
objType: {
serviceTag: "NotificationMgr",
objType: "notification"
},
linkType: "many",
handler: true
}
}
]
}
}
</syntaxhighlight>
=== has_notificationTrigger ===
<syntaxhighlight lang="JavaScript">
{
"has_notificationTrigger": {
properties: {
originTimestamp: {...}
},
storageResources: {
myGraph: {
storageType: "graph",
graphServerTag: "graphHandler"
}
},
links: [
{
storageResourceTags: ["myGraph"],
from: {
objType: {
serviceTag: "NotificationMgr",
objectType: "notification"
},
linkType: "one",
handler: true
},
to: {
objType: {
serviceTag: "NotificationMgr",
objType: "notificationTrigger"
},
requiredOnCreate: true,
linkType: "many",
handler: true
}
}
]
}
}
</syntaxhighlight>


= Triggers structure =
= Triggers structure =
Record of the triggers for a notification, saved in Notifications table


<syntaxhighlight lang="JavaScript">
<syntaxhighlight lang="JavaScript">
Line 110: Line 449:
== value or values array ==
== value or values array ==


Either value or values should be set, not both, if values is used it means any of the elements in the values array can match.
* Either 'value' or 'values' should be set, not both, if 'values' is used it means any of the elements in the 'values' array can match.


To achieve this on Activity Switchboard a new trigger group is created for each element, each activity group has the full list of other triggers, and one option from this trigger's ''values'' array. If a notification has multiple ''values'' type triggers than a new trigger group on Activity Switchboard is created for each combination.
* To achieve this on Activity Switchboard a new trigger group is created for each element, each activity group has the full list of other triggers, and one option from this trigger's ''values'' array. If a notification has multiple ''values'' type triggers than a new trigger group on Activity Switchboard is created for each combination.


serviceName topicName valueTypes do not have propertyName
* "serviceName" and "topicName" valueTypes do not have propertyName  


= serviceName and topicName triggers =
= serviceName and topicName triggers =

Revision as of 06:19, 4 July 2024

Overview

Consolidates and sends notifications to any number of receiver services. Will be used for user notifications but can have other types of receiver services added. Activities are received from Activity Switchboard service.

Notification groups set whether activities are considated (eg per day/per month/per x number of activities), if considated activities are stored here until sending is triggered, according to the considation rules. If not consolidated they are sent on immediately.

Repository

https://bitbucket.org/stb_working/notification-manager/src/master/

DynamoDB tables

PendingConsolidation Table

partition key
  • notificationGroupId
type: string
{reciverTag} + "_" + {groupingId}
sort key
  • time
type: number
{timestamp activity handled in Activity Switchboard}_{small random UUID}

Object Schemas

Additional Information
Per Service Schemas

objType

notificationGroup

  • Groups many notificatons together
  • Simplifies management of similar notifications
  • Allows for consolidation of notifications at notification group level
{
	objectType: "notificationGroup",
	canDelete: false,
    complexFilterServiceTag: "complexFilter",
	addOnDataStructure: [
		{
			type: "versionedData",
			versionedDataLabel: "notificationGroupSetting",
			storageResourceTag: "myGraph",
			fieldNames: [
				{ // fieldName in versionedData should now same in main objectSchema
			 		fieldName: "notificationGroupName"
				},
				{ 
					fieldName: "consolidated",
				},
				{
					fieldName: "consolidatedType"
				},
				{
					fieldName: "consolidatedFrequency"
				},
				{
					fieldName: "consolidatedSendIfEmpty"
				}
			]
		}
    ],
    overwriteGeneratedMainFunction: ["create", "get", "update"],
    storageResources: {
		myGraph: {
			storageType: "graph",
			graphServerTag: "GraphHandler"
		}
    },
    fieldNames: { // see Per Service Schemas
		notificationGroupId: {},
		additionalData: {}
    },
    identifiers: [
		{
			type: "identifier",
			fieldName: "notificationGroupId"
		}
    ]
}

fieldNames

notificationGroupId (identifier)
comes from: {receiverTag}_{groupingId} (Old)
eg receiverTag: ContactMethodEmail
eg groupingId: {userId}, cannot include underscores
New Idea! comes from use notificationGroupUniqueId as notificationGroupId
eg {"ContactMethodEmail_randomIdA_randomIdB"}
notificationGroupName
string name set by reciever service, optional
additionalData
set by the creating service, gets added to notifications sent to the receiver
eg: can include the actual userId and used to make the groupingId
consolidated
true|false
optional, if excluded (or value not true), defaults to false
consolidatedType
overview|detailed
overview sends a count of each type of notification, detailed lists each activity message
consolidatedFrequency
not sure, maybe use some sort of standard like cron
consolidatedNextSendDue
timestamp for next due time to send notification
consolidatedSendIfEmpty
true|false


notification

{
	objectType: "notification",
	canDelete: false,
	complexFilterServiceTag: "complexFilter",
    overwriteGeneratedMainFunction: ["create", "get", "update"],
    storageResources: {
		myGraph: {
			storageType: "graph",
			graphServerTag: "GraphHandler"
		}
    },
    fieldNames: {
		notificationId: {},
		notificationName: {}
    },
    identifiers: [
		{
			type: "identifier",
			fieldName: "notificationId"
		}
    ]
}

fieldNames

notificationId (identifier)
hash of object containing {notificationName, triggers}
notificationName
string name set by reciever service, optional


notificationTrigger

array/list of triggers that must match for this notification to happen, see #Triggers structure

{
	objectType: "notificationTrigger",
	canDelete: false,
    complexFilterServiceTag: "complexFilter",
    overwriteGeneratedMainFunction: ["create", "get"],
    storageResources: {
		myGraph: {
			storageType: "graph",
			graphServerTag: "GraphHandler"
		}
    },
    fieldNames: {
		notificationTriggerId: {},
		propertyName: {},
		valueType: {},
		value: {},
		values: {}
    },
    identifiers: [
		{
			type: "identifier",
			fieldName: "notificationTriggerId"
		}
    ]
}

fieldNames

notificationTriggerId (identifier)
New Idea; comes from: {notificationId}_{small random UUID}
propertyName
can be a nested property, use dot notation
"serviceName" and "topicName" valueTypes do not have propertyName
valueType
property|attribute|serviceName|topicName
value
{string or number}
values
{array/list of value}


consolidated

{
	objectType: "consolidated",
	canDelete: false,
    complexFilterServiceTag: "complexFilter",
    storageResources: {
		dynamoDB: {
			storageType: "dynamoDB",
			graphServerTag: "PendingConsolidation"
		}
    },
    fieldNames: {
		notificationGroupId: {},
		time: {},
		activityMsg: {}
    },
    identifiers: [
		{
			type: "partitionKey",
			fieldName: "notificationGroupId"
		},
		{
			type: "sortKey",
			fieldName: "time"
		}
    ]
}

fieldNames

notificationGroupId (partition key)
comes from use notificationGroupUniqueId as notificationGroupId (by Pong 2/7/2024)
eg {"ContactMethodEmail_randomIdA_randomIdB"}
time (sort key)
comes from {timestamp activity handled in Activity Switchboard}_{small random UUID}
adding the UUID to ensure no clashing records with the same timestamp and notificationGroupId
activityMsg
copy of the message delivered from Activity Switchboard


Object Relationships

has_notificationGroup

{
	"has_notificationGroup": {
		properties: {
			originTimestamp: {...}
		},
		storageResources: {
			myGraph: {
				storageType: "graph",
				graphServerTag: "graphHandler"			
			}
		},
		links: [
			{
				storageResourceTags: ["myGraph"],
				from: {
					objType: {
						serviceTag: "ContactMethodEmail",					
						objectType: "email"
					},
					linkType: "one",
				},
				to: {
					objType: {
						serviceTag: "NotificationMgr",				
						objType: "notificationGroup"					
					},
					requiredOnCreate: true,					
					linkType: "many",
					handler: true
				}
			}
		]
	}
}


disabled_notificationGroup

{
	"disabled_notificationGroup": {
		properties: {
			originTimestamp: {...}
		},
		storageResources: {
			myGraph: {
				storageType: "graph",
				graphServerTag: "GraphHandler"			
			}
		},
		links: [
			{
				storageResourceTags: ["myGraph"],
				from: {
					objType: {
						serviceTag: "ContactMethodEmail",					
						objectType: "email"
					},
					linkType: "one"
				},
				to: {
					objType: {
						serviceTag: "NotificationMgr",				
						objType: "notificationGroup"					
					},			
					linkType: "many",
					handler: true
				}
			}
		]
	}
}


has_notification

{
	"has_notification": {
		properties: {
			originTimestamp: {...}
		},
		storageResources: {
			myGraph: {
				storageType: "graph",
				graphServerTag: "GraphHandler"			
			}
		},
		links: [
			{
				storageResourceTags: ["myGraph"],
				from: {
					objType: {
						serviceTag: "NotificationMgr",					
						objectType: "notificationGroup"
					},
					linkType: "one",
					handler: true					
				},
				to: {
					objType: {
						serviceTag: "NotificationMgr",				
						objType: "notification"					
					},
					requiredOnCreate: true,					
					linkType: "many",
					handler: true
				}
			}
		]
	}
}


disabled_notification

{
	"disabled_notification": {
		properties: {
			originTimestamp: {...}
		},
		storageResources: {
			myGraph: {
				storageType: "graph",
				graphServerTag: "graphHandler"			
			}
		},
		links: [
			{
				storageResourceTags: ["myGraph"],
				from: {
					objType: {
						serviceTag: "NotificationMgr",					
						objectType: "notificationGroup"
					},
					linkType: "one",
					handler: true
				},
				to: {
					objType: {
						serviceTag: "NotificationMgr",				
						objType: "notification"					
					},
					linkType: "many",
					handler: true
				}
			}
		]
	}
}


has_notificationTrigger

{
	"has_notificationTrigger": {
		properties: {
			originTimestamp: {...}
		},
		storageResources: {
			myGraph: {
				storageType: "graph",
				graphServerTag: "graphHandler"			
			}
		},
		links: [
			{
				storageResourceTags: ["myGraph"],
				from: {
					objType: {
						serviceTag: "NotificationMgr",					
						objectType: "notification"
					},
					linkType: "one",
					handler: true
				},
				to: {
					objType: {
						serviceTag: "NotificationMgr",				
						objType: "notificationTrigger"					
					},
					requiredOnCreate: true,	
					linkType: "many",
					handler: true
				}
			}
		]
	}
}


Triggers structure

[
	{
		"propertyName": {can be a nested property, use dot notation}
		"valueType": property|attribute|serviceName|topicName
		"value": {string or number}
		"values": {array/list of values}
	},
	..
]

value or values array

  • Either 'value' or 'values' should be set, not both, if 'values' is used it means any of the elements in the 'values' array can match.
  • To achieve this on Activity Switchboard a new trigger group is created for each element, each activity group has the full list of other triggers, and one option from this trigger's values array. If a notification has multiple values type triggers than a new trigger group on Activity Switchboard is created for each combination.
  • "serviceName" and "topicName" valueTypes do not have propertyName

serviceName and topicName triggers

  • Notifications do not have to set their serviceName and/or topicName, if not set then any message that matches the properties will pass
  • Can set only the serviceName, then any message that passess the properties and is from that serviceName passes
  • Can set serviceName+topicName, then only messages in that topic will pass
  • serviceName and topicName can both be submitted as "values" array, creating multiple trigger groups for each combination

Consolidated notifications

How to trigger processing for time based consolidations

  • ....
  • maybe can use some sort of queue to store a list of NotificationGroup’s that are due to be sent (either because consolidatedSendIfEmpty == true or there are some activities waiting to be processed)

Formating the notification body

  • Initially the format will be hardwired and simple, but in the future we could create templates for formating the notification body
  • The notificationBody is currently sent to receiver as a JSON stringified object containing all activityMsgs

Ideas

  • overview notifications currently count per notification, but could be extended to do aggregates on a per notification, per field level
  • If set to overview maybe can store just aggregate/s needed for the consolidated notification, at the moment store entire messages, create the overview once when sending notification

Working documents

Working documents - Notification Manager