feat(notifications): replace 30s short-polling with SSE stream and realtime toast alerts
Feature: Realtime Notifications via Server-Sent Events (SSE)
Overview
Replaced the legacy 30-second short-polling mechanism (refetchInterval: 30000) for notifications and unread counts with a persistent, low-overhead Server-Sent Events (SSE) connection. The app now receives instant updates for incoming notifications and badge counts without redundant network polling.
Key Changes
-
useNotificationSSEHook (src/hooks/use-notification-sse.ts):- Automatically manages the lifecycle of an
EventSourceconnection to/api/v1/notifications/stream. - Supports authentication via cookies and
?token=<access_token>query parameters for mobile webview compatibility. - Listens to
unread_countevents to dynamically update React Query cache (notificationKeys.unread()). - Listens to
notificationevents to invalidate notifications list cache and trigger realtime toasts. - Handles automatic reconnection and graceful connection termination upon logout or component unmount.
- Automatically manages the lifecycle of an
-
NotificationRealtimeListener(src/components/shared/NotificationRealtimeListener.tsx):- Headless listener component mounted in
Layout.tsxwithinSnackbarProviderandAuthInitializer. - Dispatches immediate snackbar notifications when alerts (e.g., budget warnings, saving goals, anomalies) are received.
- Headless listener component mounted in
-
Eliminated 30s Polling (
src/hooks/use-notifications.ts):- Disabled
refetchInterval(false) in bothuseUnreadNotificationCountanduseNotifications. - Increased
staleTimeto60_000ms, retainingrefetchOnWindowFocus: trueas a graceful fallback on device wake-up.
- Disabled
-
API Client Update (
src/lib/api-client.ts):- Exported
API_BASE_URLto ensure consistent endpoint resolution across all services and streams.
- Exported
-
Memory Documentation (
.agents/memory.md):- Documented the architectural transition from polling to SSE.
Performance & Efficiency Impact
- Network Traffic: Eliminated continuous HTTP requests every 30 seconds per active client tab, saving battery and bandwidth on mobile devices.
- Latency: Notification and unread badge updates are delivered with sub-second latency instead of up to a 30-second delay.