Skip to content

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/.

Исключения — точечные и обоснованные (например, диагностический скрипт), помечаются комментарием.