Skip to content

Real-time Chat

Planner includes a built-in real-time messaging system powered by Socket.IO WebSockets.

Architecture

  • Socket.IO Namespace: /chat
  • Authentication: Token-based via handshake.auth.token
  • Events: join, leave, typing (client→server); chat:typing, chat:message, chat:created (server→client)

API Endpoints

MethodPathDescription
GET/api/chatsList user conversations
POST/api/chatsCreate conversation
POST/api/chats/direct/:userIdCreate or get direct conversation
POST/api/chats/task/:taskIdCreate or get task conversation
GET/api/chats/:id/messagesList messages (cursor pagination: ?before=&limit=)
POST/api/chats/:id/messagesSend message
POST/api/chats/:id/messages/attachmentsUpload attachments (up to 10 files)
POST/api/chats/:id/readMark conversation as read

Socket.IO Events

Client → Server

EventPayloadDescription
joinconversationId: stringJoin conversation room
leaveconversationId: stringLeave conversation room
typingconversationId: stringTyping indicator

Server → Client

EventPayloadDescription
chat:typing{ conversationId, userId }Another user is typing

Messages are sent via REST (POST /api/chats/:id/messages), real-time delivery is handled by sendToConversation() on the server.

Frontend

Chat Store

typescript
const store = useChatStore()
const { conversations, messages } = storeToRefs(store)

await store.fetchConversations()
await store.createConversation(userId)  // direct
await store.createTaskConversation(taskId)  // task chat
await store.fetchMessages(conversationId)
await store.sendMessage(conversationId, body)

UI Structure

The chat interface has a two-panel layout:

  • Left panel: Conversation list (filtered by type — task chats display inline on task detail pages)
  • Right panel: Message stream with real-time updates

Voice Messages

Chat supports voice message recording and playback:

  • VoiceRecorder.vue — records audio via the MediaRecorder API, uploads as a file attachment
  • AudioPlayer.vue — custom audio player for voice message playback with waveform display
  • Voice messages are uploaded via POST /api/chats/:id/messages/attachments with a voice flag
  • Duration metadata is stored alongside the audio file

Key Implementation Details

  • Task conversations are created via POST /api/chats/task/:taskId — a separate endpoint from direct conversations
  • The task path segment is static, avoiding route conflicts with /direct/:userId
  • Creating a task conversation automatically adds the requesting user as a participant
  • Message delivery is real-time via socket events — no polling
  • Typing indicators show when another user is typing
  • The main chat page filters out task-type conversations (they display inline on task detail pages)