Real-Time Notifications
Users find out the moment it happens, without reloading.
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.