Back to projects
notif_service

Real-Time Notifications

Users find out the moment it happens, without reloading.

GoWebSocketHMACMySQLDocker
Real-Time Notifications

The problem

The ERP announced nothing in the moment. If someone registered a payment or a sale, the rest of the team only found out when they reloaded the page, and many didn't even know they had to reload. That meant people working with stale data: asking "has this been paid yet?" when it already had, repeating actions someone else had already done, or assuming the system had frozen. The classic was users hitting F5 every couple of minutes just in case. A system that feels dead breeds distrust, and that distrust is hard to reverse.

The solution

The starting point was clear: I didn't want the user to reload to find out. I ruled out pure browser polling —costly and laggy— and went with WebSocket, which keeps the connection open and pushes the event the moment it happens. The real doubt came next: what if the pushing service is down exactly when something important happens? So I decided not to trust everything to the push, and added a poller that every few seconds checks for anything that might have been missed. That way the push gives the speed and the polling gives the guarantee. To avoid coupling it to Laravel, instead of sharing the session I had the backend sign an HMAC token that the Go service validates on its own: two independent services that still trust each other. And per-company isolation lives in the hub, not in each message, so a user never receives what isn't theirs.

Technical decisions

WebSocket + polling, not just push

Push gives low latency; the polling fallback guarantees delivery if the push fails. Robustness without giving up speed.

HMAC token instead of a shared session

Go validates the client with no access to Laravel's session: two decoupled services that still trust each other.

One channel per company

Each user only receives its own events; isolation lives in the hub, not in every message.

Live

Realtime in action: per-company connections, a test push and a real case.

A client connects as Company A, disconnects and reconnects as Company B — the logs show the different connections opening.
A live test notification sent, with the service logs showing the push.
Real case: creating a sale delivers the notification to the user instantly.