Чат в реальном времени
Planner включает встроенную систему обмена сообщениями в реальном времени на базе Socket.IO WebSockets.
Архитектура
- Пространство имён Socket.IO:
/chat - Аутентификация: На основе токена через
handshake.auth.token - События:
join,leave,typing(клиент→сервер);chat:typing,chat:message,chat:created(сервер→клиент)
API Endpoints
| Метод | Путь | Описание |
|---|---|---|
GET | /api/chats | Список бесед пользователя |
POST | /api/chats | Создать беседу |
POST | /api/chats/direct/:userId | Создать или получить личную беседу |
POST | /api/chats/task/:taskId | Создать или получить беседу задачи |
GET | /api/chats/:id/messages | Список сообщений (курсорная пагинация: ?before=&limit=) |
POST | /api/chats/:id/messages | Отправить сообщение |
POST | /api/chats/:id/messages/attachments | Загрузить вложения (до 10 файлов) |
POST | /api/chats/:id/read | Отметить беседу как прочитанную |
Socket.IO события
Клиент → Сервер
| Событие | Payload | Описание |
|---|---|---|
join | conversationId: string | Присоединиться к комнате беседы |
leave | conversationId: string | Покинуть комнату беседы |
typing | conversationId: string | Индикатор печатания |
Сервер → Клиент
| Событие | Payload | Описание |
|---|---|---|
chat:typing | { conversationId, userId } | Другой участник печатает |
Сообщения отправляются через REST (POST /api/chats/:id/messages), доставка в реальном времени — через sendToConversation() на сервере.
Фронтенд
Store чата
typescript
const store = useChatStore()
const { conversations, messages } = storeToRefs(store)
await store.fetchConversations()
await store.createConversation(userId) // личная
await store.createTaskConversation(taskId) // чат задачи
await store.fetchMessages(conversationId)
await store.sendMessage(conversationId, body)Структура UI
Интерфейс чата имеет двухпанельный макет:
- Левая панель: Список бесед (фильтруется по типу — чаты задач отображаются отдельно на страницах задач)
- Правая панель: Поток сообщений с обновлениями в реальном времени
Ключевые детали реализации
- Беседы задач создаются через
POST /api/chats/task/:taskId— это отдельный эндпоинт от личных бесед - Сегмент пути
taskстатический, что позволяет избежать конфликтов маршрутов с/direct/:userId - Создание беседы задачи автоматически добавляет запрашивающего пользователя как участника
- Доставка сообщений происходит в реальном времени через socket-события — без polling
- Индикаторы печатания показывают, когда другой участник набирает текст
- Основная страница чата фильтрует беседы типа task (они отображаются встроенно на странице деталей задачи)
Голосовые сообщения
Чат поддерживает запись и воспроизведение голосовых сообщений:
VoiceRecorder.vue— запись аудио через MediaRecorder API, загрузка как файловое вложениеAudioPlayer.vue— пользовательский аудиоплеер для воспроизведения голосовых сообщений с отображением волновой формы- Голосовые сообщения загружаются через
POST /api/chats/:id/messages/attachmentsс флагомvoice - Метаданные продолжительности хранятся вместе с аудиофайлом