Архитектура WebSocket
Planner использует Socket.IO для двунаправленной связи в реальном времени. Существует три отдельных пространства имён (namespace), каждое из которых обслуживает свою область.
Обзор
| Namespace | Назначение | Аутентификация | Направление |
|---|---|---|---|
/notifications | push-уведомления | JWT | Сервер → Клиент |
/chat | обмен сообщениями | JWT | Двунаправленный |
/video | сигналинг видеокомнат | JWT | Двунаправленный |
Аутентификация
Все WebSocket-соединения аутентифицируются через handshake.auth.token — JWT-токен доступа, передаваемый при рукопожатии Socket.IO. Сервер проверяет токен с помощью JwtService и извлекает ID пользователя.
// Подключение клиента
const socket = io('/notifications', {
auth: { token: accessToken }
})Пространства имён
/notifications
Только серверная отправка — клиенты слушают события, без сообщений от клиента.
| Направление | Событие | Payload | Описание |
|---|---|---|---|
| Сервер → Клиент | notification:new | Объект Notification | Новое уведомление для пользователя |
Пользователи автоматически присоединяются к комнате user:<id> при подключении.
/chat
Двунаправленный обмен сообщениями для разговоров в реальном времени.
| Направление | Событие | Payload | Описание |
|---|---|---|---|
| Клиент → Сервер | join | conversationId | Присоединиться к комнате разговора |
| Клиент → Сервер | leave | conversationId | Покинуть комнату разговора |
| Клиент → Сервер | typing | conversationId | Индикатор набора текста |
| Сервер → Клиент | chat:typing | { conversationId, userId } | Другой пользователь печатает |
Сообщения отправляются через REST (POST /api/chats/:id/messages), доставка в реальном времени обрабатывается sendToConversation() на сервере. Пользователи присоединяются к комнатам user:<id> и conv:<id>.
/video
Сигналинг и события комнат для видеоконференций.
| Направление | Событие | Payload | Описание |
|---|---|---|---|
| Клиент → Сервер | join | roomId | Присоединиться к комнате (room:<id>) |
| Клиент → Сервер | leave | roomId | Покинуть комнату |
| Клиент → Сервер | signal | WebRTC-сигнал | Ретрансляция сигналинга |
| Сервер → Клиент | video:participant_joined | Данные участника | Пользователь присоединился |
| Сервер → Клиент | video:participant_left | Данные участника | Пользователь покинул |
| Сервер → Клиент | video:room_updated | Данные комнаты | Состояние комнаты изменилось |
| Сервер → Клиент | video:call_started | Данные комнаты | Мгновенный вызов начат |
Структура комнат
Notifications: user:<userId>
Chat: user:<userId>, conv:<conversationId>
Video: room:<roomId>Интеграция с фронтендом
Слушатель уведомлений (в App.vue)
const socket = io('/notifications', { auth: { token } })
socket.on('notification:new', (notification) => {
notificationsStore.addNotification(notification)
})Store чата
const socket = io('/chat', { auth: { token } })
socket.on('chat:typing', ({ conversationId, userId }) => { /* ... */ })
socket.emit('join', conversationId)
socket.emit('typing', conversationId)Store видео
const socket = io('/video', { auth: { token } })
socket.on('video:participant_joined', (data) => { /* ... */ })
socket.on('video:participant_left', (data) => { /* ... */ })
socket.emit('join', roomId)Ключевые детали
NotificationsGateway.sendToUser()проверяетthis.server?(сервер не определён во время тестирования)- Уведомления доставляются без ожидания —
NotificationsService.create()не ожидается (fire-and-forget) - Сообщения чата сохраняются через REST, доставка в реальном времени — через WebSocket
- Видеосигналинг ретранслирует WebRTC-оферы/ответы/ICE-кандидаты через namespace
/video