How to Set Up Real-Time Letter Status Notifications and Tracking for Hospitals & Clinics
A guide to building real-time letter status notifications and tracking with Node.js, Redis, and WebSocket, complete with code samples and operational best practices.
Imagine a type-B hospital with 40 work units receiving 300–450 incoming letters per month. Without a tracking system, the secretariat records them in an agenda book, then staff call other units to confirm whether a letter has been received or not. As a result, disposition is delayed by an average of 2–4 days, and about 5–8% of letters are not tracked at all. In a clinic with 10–15 employees, the problem is simpler but remains the same: an operational license letter from the Health Office can be stuck for weeks simply because no one knows who last held the document. This article discusses how to build a lightweight real-time letter status notification and tracking system — a VPS with 2 vCPU/4 GB RAM is enough — that can still connect to an existing e-office.
Event-Driven Architecture: Don't Rely on Polling
The first approach usually chosen is polling: the dashboard calls the API every 30 seconds to check status. The calculation quickly balloons. With 50 active users and a 30-second interval, the server receives 50 × 120 = 6,000 requests per hour, or 144,000 requests per day just to ask ‘is there a change or not’. Most of those requests return empty results. This load is indeed still manageable on modern servers, but bandwidth costs, database load, and mobile device battery consumption become unreasonable.
The solution is event-driven with publish-subscribe. Every action — letter received, assigned a disposition, processed, completed, or rejected — is written to the letter_events table and simultaneously published to a Redis channel. The client no longer asks; the server notifies. The most practical combination for e-office needs is Laravel 11 for the API and admin panel, Redis 7.2 as the message broker, and Socket.IO 4.7.1 on the web client side if you want automatic fallback to long-polling when WebSocket is blocked by the office proxy.
The minimal schema requires only three tables: letters (id, nomor, perihal, pengirim, status, unit_id, deadline), letter_events (id, letter_id, status_lama, status_baru, actor_id, created_at, ip, user_agent), and subscriptions (user_id, channel). With this schema you already get a complete audit trail without additional tables, and can derive SLA reports from the same data.
One important note: publish the event after the database transaction commits, not inside it. Use Laravel event listeners with ShouldQueueAfterCommit or the afterCommit() hook on the connection. Otherwise, the worker may send a WhatsApp notification for a letter whose transaction turns out to be rolled back — a classic mistake that is hard to trace in production.
Multi-Channel Notification Worker Implementation
Do not send notifications inside the HTTP request. The HTTP process must finish under 300 ms, while calls to WhatsApp Business API or SMTP can take 1–3 seconds and occasionally fail. Separate it into a dedicated worker that subscribes to Redis and sends notifications asynchronously. Here is a minimal worker example with Node.js 20 LTS and ioredis 5.4.1 that sends WhatsApp messages via Fonnte (can be replaced with Wablas or the official WhatsApp Cloud API).
// worker-notif.js — Node.js 20 LTS, ioredis 5.4.1
import Redis from 'ioredis';
import axios from 'axios';
const sub = new Redis(process.env.REDIS_URL);
await sub.subscribe('letter:events');
sub.on('message', async (_, raw) => {
const evt = JSON.parse(raw); // {id, status, unit, phone, actor}
await axios.post('https://api.fonnte.com/send', {
target: evt.phone,
message: `Surat ${evt.id} berstatus '${evt.status}' oleh ${evt.actor}.`
}, { headers: { Authorization: process.env.FONNTE_TOKEN } });
});
Run this worker with pm2 or systemd, not nodemon. A systemd unit with Restart=always and RestartSec=5 makes the worker automatically come back to life after a crash or deploy. For a volume of 500–1,000 notifications per day, one worker with 256 MB of memory is enough; increase to two replicas if queue latency exceeds 30 seconds.
Multi-channel is not just about adding integrations. Apply routing rules: WhatsApp for disposition and approval (read within minutes), email for daily reports and archives (needs a formal trail), and web push for SLA reminders. Store delivery status in the notification_logs table (channel, status, error, sent_at) so that when users complain ‘I didn't get a notification’, you have concrete evidence — not speculation.
For hospital and clinic environments, also pay attention to the PDP Law. Phone numbers and letter subjects are personal data. Do not send the full subject on WhatsApp; just the letter number, status, and a link to the system with authentication. This reduces the risk of leaks if a device is lost or a number changes hands.
Tracking Timeline and Automatic SLA Escalation
Useful tracking is not just a status column, but a chronology. Display a vertical timeline: who received it, when it was dispositioned, to which unit, disposition notes, and how long the letter stayed in each unit. This data comes from letter_events, which you already wrote in the previous section — no new table is needed.
SLA escalation runs as a cron job every 15 minutes. Example rules: a letter with processed status for more than 3 working days → send a reminder to the holder; more than 5 days → escalate to the unit supervisor; more than 7 days → add it to the daily list for the Head of the General Affairs Section. The query requires only one SELECT with an index on (status, updated_at). In MySQL 8, this composite index makes scanning 200,000 rows finish under 50 ms.
On the UI side, use lightweight components. Alpine.js 3.14 or Livewire 3 is enough to render a reactive timeline without building a full SPA. If your team uses React, use TanStack Query 5 for caching and refetch on focus; this eliminates 80% of manual state management needs.
For field officers who collect physical letters in the archive room, provide a QR scan button on the mobile page. Each QR contains the letter UUID; once scanned, the ‘received’ event is recorded along with a timestamp and optional GPS. Recording time drops from 30–45 seconds to under 5 seconds per letter.
Best Practices
- Commit first, publish later. Use
afterCommitso events are not sent for transactions that roll back. - Idempotent. Store
event_idinnotification_logswith a unique index; a worker that receives duplicate messages does not send notifications twice. - Limit the payload. Maximum 4 KB per event — send the ID and link, not the document content or full subject.
- Measured retention.
letter_eventsis stored for 24 months, partitioned by month soDELETEis fast and indexes remain lean. - Test failures, not just the happy path. Simulate Redis down, a 30-second gateway timeout, and an expired token at least once before go-live.
FAQ
Is WebSocket mandatory? Can we use Server-Sent Events?
Not mandatory. SSE (EventSource) is sufficient for one-way notifications and is simpler behind an Nginx reverse proxy. WebSocket is superior when you need a two-way channel, for example collaboration on dispositions between units. For e-office, SSE with a 25-second heartbeat is already adequate and saves server memory.
What is the estimated monthly infrastructure cost?
A VPS with 2 vCPU/4 GB RAM from a local provider is around Rp 150–250 thousand/month, self-hosted Redis is free, and a WhatsApp gateway is Rp 150–400 thousand/month depending on volume. Total is under Rp 700 thousand/month for 50–100 active users — far cheaper than one disposition error delayed for days.
Can it be integrated with an existing e-office?
Yes. Generally, it is enough to add a webhook on the e-office side that calls the /api/events endpoint whenever the status changes. If the vendor does not provide a webhook, the second option is CDC (change data capture) with Debezium 2.6 reading the MySQL binlog, or scheduled polling every 5 minutes specifically for the status table.
What if the office internet connection goes down?
WhatsApp notifications are still sent because the worker runs on the VPS, not on the office network. Only dashboard access is disrupted. Provide a degradation mode: the last status page remains open via PWA cache (service worker) so officers can still see the latest snapshot.
Building real-time letter tracking does not require an expensive stack. Three core components — event log, message broker, and notification worker — are enough to cut disposition time from days to minutes. The key to success is not technology, but the discipline of recording every status change and testing failure paths before go-live. If you manage a hospital, clinic, or operational office in Yogyakarta (DIY) and Magelang that wants to integrate letter tracking with an existing SIMRS, SIM Klinik, ERP, POS, or e-office, our team provides IT consulting and custom application development services tailored to your workflow.
This article is part of the knowledge base of Nugroho Setiawan, an IT consultant in Jogja (Yogyakarta). Related solutions: SIMRS (Hospital Information System) Clinic Management System E-Office. Need a free consultation?
Komentar
Belum ada komentar. Jadilah yang pertama!
Saya membantu konsultasi IT & pengembangan aplikasi untuk rumah sakit, klinik, dan bisnis di Yogyakarta (DIY), Magelang, dan sekitarnya.