Modelling a Notification System in PHP

Jan 19, 2015

Table of contents:

  1. What is a Notification System?
  2. Notifications should listen for Events
  3. Notifications are important to Identity
  4. The Notification Entity and the User Aggregate
  5. The importance of notification controls
  6. Conclusion

A really important aspect of modern consumer web applications is a notification system. Notifications promote user interaction, stimulates usage and encourages repeat visits, so having a notification system can be an important lever for growth.

Whilst notifications can be very important and useful for your users, they can also be really annoying too. I’m sure we’ve all been sick of getting bombarded with notifications from certain web applications.

So it’s important to not only have a notification system that provides utility service to our users, we also need to afford them the granular control of deciding what they want to be notified about.

In today’s article we will look at modelling a notification system for Cribbb.

What is a Notification System?

As I mentioned above, nearly all modern consumer web applications have a notification system in one form or another. The majority of these notification systems have basically all the same functionality and attributes.

However with that being said, here are the characteristics that I’m going to build as part of the Cribbb notification system:

A pipeline of messages to the user The Cribbb notification system will act as a pipeline of messages that notify the user of recent events. There will be a number of different “hooks” that can trigger notifications to be added to a user’s pipeline.

A message can be of many types There will be many different types of notifications for the different possible actions that have taken place in the application.

Should have read / unread status Notifications should have a status that will change once the user has shown interaction with it. This will be important as part of the User Interface design.

Send email and display as part of the UI By default a user will receive an email as well as a visual notification as part of the User Interface. The user should be able to turn off the email notifications.

An action can cause many notifications An action in Cribbb should cause many notifications to one or more users. This means that there should be a decoupled relationship between the action and the notification.

Notifications should be queued We should make use of a queue system to send notifications because we could be potentially sending many emails for a single action. Notifications do not need to be instant.

Notifications should listen for Events

A Notification is a message to a user to inform them that an event of interest occurred in the application. For example, perhaps another user followed them, or someone replied to one of their posts.

For the most part, these notifications will be triggered by the actions of other users.

As we’ve already looked at in this series, Domain Events make it really easy to notify other aspects of the application that an event has occurred.

When a Domain Event is emitted, registered listener classes are automatically triggered and so the action is decoupled from the event. This means we can add or remove event listeners without touching the actual trigger of the event.

We therefore already have the perfect infrastructure in place for triggering and sending notifications to our users!

If you would like to read more about Domain Events, take a look at Implementing Domain Events and Creating your own Domain Event Dispatcher.

Notifications are important to Identity

Over the last couple of weeks we’ve looked at the importance of separating an application into different Bounded Contexts.

A Bounded Context should act as a layer of protection around a certain aspect of an application to maintain a unified internal model.

This is particularly important for large applications that often have similar terms that have different meanings in different aspects of the application.

We’ve already got a Bounded Context for Identity that includes functionality for registering as a new user, following other users, and updating profile information.

Should the notifications functionality have it’s own Bounded Context or should it be part of the Identity Bounded Context?

In my opinion, the notification functionality should be part of the Identity Bounded Context. Whilst this means the Identity Bounded Context will grow in scope, I think there are a couple of important reasons to keep these two aspects of the application together.

Firstly, notifications are an important concept of identity that transcends the application. Any part of the application can trigger a notification, but the notification is only really important to a user with identity.

Secondly, there are no contradictions between the notification model and the identity model. If we had an important term that had different, contradicting meanings, we would probably have a case for two separate Bounded Contexts.

And thirdly, a notification doesn’t make sense without being tied to an identity. A user can only view their own notifications and not the notifications of any other user. If (or should I say when?) we build out the API for Cribbb, the endpoint for getting notifications would be me/notifications.

The Notification Entity and the User Aggregate

A Notification has a lifecycle and therefore we need to model it as an Entity. You should always attempt to default to modelling something as a Value Object, rather than an Entity for simplicity, but in this case we have no choice.

For a refresher on Entities verses Value Objects, have a read of What is the difference between Entities and Value Objects?

As I mentioned above, notifications don’t really make sense outside of the context of a User. We shouldn’t be able to arbitrarily retrieve notifications from the database. Instead we should only be able to get the notifications for a user from the User object.

This means notifications will sit neatly within the existing User Aggregate (What are Aggregates in Domain Driven Design?).

The Notification Entity itself can be fairly simple.

Firstly the notification will require a body that can hold a generic chunk of text.

Secondly, we need a read / unread status. We will also need to require the timestamp of when the notification was read, and so we can kill two birds with one stone by determining the read / unread status from this timestamp.

And thirdly we need to categorise notifications so we can filter them or treat them in different ways. I’m just going to use a standard keyword on the notification Entity to keep things simple.

The importance of notification controls

An important part of any good notification system is the controls that allow a user to filter what notifications they want to receive.

If you are going to offer application notifications, you can’t neglect to build the controls to filter or stop the notifications your users receive.

Neglecting to build this functionality will only annoy your users so that they mark your emails as spam.

We’re going to need a way for a user to specify which notification emails they do not want to receive.

We’re also going to need a service that can filter through notifications to decide whether the user should receive an email notification.

However, we’ll cross that bridge when we come to it.


Notifications are very important aspect of consumer web applications. Timely and expected notifications can significantly drive usage and growth for your application.

However, notifications can also be extremely annoying. You don’t want your notifications to get marked as spam, and so it’s very important to offer your users the control over what notifications they should receive.

Cribbb will be built around the idea of Domain Events. This means we already have the decoupled architecture in place to add or remove notification events without explicitly coupling ourselves to the triggers themselves.

Notifications are important to identity as a user should only ever be able to see their own notifications. This fits neatly on our existing User Aggregate. I think it’s important to attempt to fit functionality in the right logical place, rather than optimising for scope in terms of number of classes in a Bounded Context or number of methods on an object.

Today’s article was really just setting the groundwork for what we’re going to build next. As I’ve mentioned a few times in this series, I think the initial design phase is extremely important for not tripping up at some later point down the line.

This is a series of posts on building an entire Open Source application called Cribbb. All of the tutorials will be free to web, and all of the code is available on GitHub.

Philip Brown


© Yellow Flag Ltd 2024.