I'm trying to implement notifications system with GS
Basically, related models are:
Organizations
(orgs);User
, the member of org. Users can have administrative privilege in org;Entity
that admin users can create and regular users can purchase and entities also belong to orgs.In GS there are following feeds:
notification:$userId-$orgId
---- re-used default feed, personal notification feed for user in certain organizationOrg:$orgId
---- shared feed for all organization membersAdminEntity:$entityId
---- notifications about users actions on entity for admin usersUserEntity:$entityId
---- notifications about admin/system actions on entity for regular usersLet me briefly explain basic relationships between feeds:
1) Admin
creates Entity
:
push activity to Org:$orgId
about this event. Activity will have user:$userId
as Actor
and entity:$entityId
as Object
.
subscribe his notification:$userId-$orgId
to AdminEntity:$entityId
2) User
joins Organization
:
push activity to Org:$orgId
about this event
subscribe his notification:$userId-$orgId
to Org:$orgId
.
3) User
purchases Entity
:
push activity to AdminEntity:$entityId
about this event.
subscribe his notification:$userId-$orgId
to UserEntity:$entityId
And so on.
The problem with described model is that in first case User
that is creator of Entity
will also receive notification via Org:$orgId
that he has created Entity
along with other Organization
members. Same thing with second case.
And this is unwanted behaviour of notifications system.
Ideally, we should not notify User
about his own activities in "shared" feeds, like Org:$orgId
. And the question is - how to achieve this? Maybe GS feeds should be organized in different way or it can be done via Aggregation Format
syntax?
Edited: as I can see, the possible solution can be:
get rid of all shared feeds like Org
, AdminEntity
, UserEntity
;
push activities directly to notification:$userId-org$id
feed regarding users roles in organization, relationships with entities etc via add_to_many
call.
I am not sure if this is idiomatic solution to use with GS.
I think your structure could be simpler than you initially designed, and be closer to what you mention at the bottom of your post. I'd also recommend you have a read through http://blog.getstream.io/best-practices-for-instagram-style-feeds/ which sounds similar to what you're wanting to do here.
For a simplified breakdown of our feed types:
Any feed type can follow a Flat feed, but we generally recommend that only flat feeds and aggregated feeds follow other flat feeds. Notification feeds generally stand alone, which I'll describe below.
Let's make the following assumptions:
12
56
is "Acme Inc"74
63
Let's create a flat feed called org
where entity activities will be made, and aggregated feed called org_aggregated
for aggregated data, a notification feed called notifications
, a flat feed for users called timeline
. If your users could see a feed of everything authored by another user (not by organization) then I'd recommend another flat feed called usercontent
.
For Silverthorne to post this activity to GetStream, the activity actor would be "user:12"
, the verb could be "post"
, the object would be "entity:63"
To pseduocode this, since I don't know which SDK you're using, would be something like:
# acme inc gets created as an organization, and so its aggregated feed
# should follow the org's flat feed
acme_org_feed = getstreamClient->feed('org', '56')
acme_org_agg_feed = getstreamClient->feed('org_aggregated', '56')
acme_org_agg_feed->follow(acme_org_feed)
At this point, every entity that gets added to Acme's org
flat feed will also get aggregated. You can set how these get rolled up on your GetStream dashboard.
Now, let's have Ian follow Acme:
# ian is a member of Acme Inc, so follow their entity feed
ian_feed = getstreamClient->feed('timeline', '74')
ian_feed->follow(acme_org_feed)
If Ian is a new registration, you could send an activity to Acme's notification feed like this:
acme_notif_feed = getstreamClient->feed('org_notification', '56')
acme_notif_feed->addActivity({
'actor': 'user:74',
'verb': 'registration',
'object': 'user:74'
})
When you retrieve this notification feed later, it will group all verbs together, and then break down the notification activities, so your UI could report those differently if you choose.
Now let's have Silverthorne add that Entity to GetStream: # Silverthorne adds an activity to Acme Inc's entity feed # we'll "cc" the activity to the aggregated feed acme_org_feed->addActivity({ 'actor': 'user:12', 'verb': 'post', 'object': 'entity:63', 'to': ['usercontent:12'], ... any other metadata you want to track })
When this is saved, here's what GetStream would do:
org
flat feed for Acme (org:56
)user:74
follows the flat feed for org:56
usercontent:12
) from the 'To' field; this is entirely optionalorg_aggregated:56
) since the aggregated feed follows the flat feedWhen Ian logs in, your app now has several possible feeds and options to show, and this is entirely up to your app:
timeline:74
feed, which will have a copy of Entity #63ian_feed->followed()
to get a list of every feed that Ian followsorg_aggregated:56
and Ian could see one new entity added in the past day
if that's how you aggregate your content)The key here is that Ian doesn't have to follow a feed in order to see the content, your app can pull any feed to display to any user.
If Ian were to 'share' or 'like' that entity that Silverthorne posted, you'd add a new activity to the 'org_notification:56' feed with 'user:74' as the Actor, 'entity:63' is the object, and verb is whatever string you want (up to 20 characters). If you want your app to see how other users interact with the org's posts, you could fetch org_notification:56
and all users could see "Ian liked entity 63", or however your UI needs to present that.
Hope that helps to clarify things and give you some additional details. Contact our support team via email if you want further help or ideas.
As a final note, I don't think I'd do $userId-$orgId
... some of our SDKs (ie, Rails and Django) will automatically try to 'enrich' those values in your database, so you'd need additional logic to attempt to split apart those values later. We recommend using a UUID for a collision-free identifier, but that's entirely up to you to control. If a user can really be part of multiple organizations, you can just have that user 'follow' the organization's feed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With