Realtime
Канал для push-данных: WebSocket, SSE, событийные шины и любой другой источник, инициирующий передачу со стороны сервера. Транспорт не зашит в правила — важна абстракция «подписка».
Получение REST-данных — REST.
Принципы
- Клиент realtime — в
infrastructure/отдельным модулем по имени канала. То же правило, что и для REST: никаких прямых соединений в коде приложения. - Подписка — единица потребления. Клиент даёт функцию
subscribe(topic, handler) → unsubscribe. Внутри — конкретный транспорт. - Использование на клиенте — два сценария:
useSWRSubscription— для данных, которые показываются в UI и должны кешироваться/синхронизироваться с REST.- Прямая подписка — для побочных эффектов (тосты, нотификации, аналитика), не привязанных к рендеру.
Размещение клиента
text
src/infrastructure/
└── {channel-name}/
├── connection.ts # установление соединения, реконнект
├── subscribe.ts # subscribe(topic, handler) → unsubscribe
├── types.ts
└── index.tsИспользование через SWR
tsx
'use client'
import useSWRSubscription from 'swr/subscription'
import { subscribe } from 'infrastructure/notifications'
export function NotificationCounter() {
const { data: count } = useSWRSubscription(
['notifications', 'count'],
(key, { next }) =>
subscribe('notifications.count', (value: number) => next(null, value)),
)
return <span>{count ?? 0}</span>
}Плюсы: кеш и дедупликация подписки между несколькими местами рендера; единая модель данных с REST.
Прямая подписка
Для побочных эффектов, которые не влияют на состояние UI напрямую:
tsx
'use client'
import { useEffect } from 'react'
import { subscribe } from 'infrastructure/notifications'
import { showToast } from 'ui/toast'
export function NotificationsToaster() {
useEffect(() => {
return subscribe('notifications.new', (notification) => {
showToast(notification.message)
})
}, [])
return null
}Возврат unsubscribe из useEffect обязателен — иначе утечка подписки.
Запрет прямых соединений
Создавать new WebSocket(...), new EventSource(...) или подписываться на событийные шины напрямую в коде приложения — запрещено. Все соединения проходят через клиент в infrastructure/.
Исключения — точечные и обоснованные (например, диагностический скрипт), помечаются комментарием.