Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/khushboodaryani/Chat-App/llms.txt

Use this file to discover all available pages before exploring further.

Chat App uses Socket.io on the same port as the REST API (default 4000). When the Express server starts, a Socket.io Server instance is mounted on the same underlying http.Server, so no extra port or proxy configuration is required. The server maintains an in-memory map of connected users (userSocketMap) that links each userId to its current socketId, enabling both real-time presence tracking and targeted message delivery.

Connection Setup

The client initiates a connection by passing the authenticated user’s ID as a query parameter. The server stores that mapping on the connection event and removes it on disconnect.
// frontend/src/context/SocketContext.jsx
const socket = io("https://chat-app-yt.onrender.com", {
  query: {
    userId: authUser._id,
  },
});

socket.on("getOnlineUsers", (users) => {
  setOnlineUsers(users);
});
On the server side, every new connection runs:
// backend/socket/socket.js
const userId = socket.handshake.query.userId;
if (userId != "undefined") userSocketMap[userId] = socket.id;

io.emit("getOnlineUsers", Object.keys(userSocketMap));
The socket connects automatically as soon as authUser is set in AuthContext (login or page refresh with a valid cookie) and disconnects when authUser is cleared (logout). This lifecycle is managed entirely inside SocketContextProvider — you do not need to call connect() or close() manually in your components.

Events Overview

EventDirectionTrigger
connectionClient → ServerUser loads the app while authenticated
disconnectClient → ServerUser closes the tab or logs out
getOnlineUsersServer → All ClientsAny user connects or disconnects
newMessageServer → One ClientA message is sent to this specific user

getOnlineUsers

Direction: Server → All Clients (broadcast via io.emit) Trigger: Fires on every connection and disconnect event so every connected client always has an up-to-date presence list. Payload: string[] — an array of user IDs that are currently online.
["64abc123def4567890abcdef", "64def456abc7890123defabc"]
Frontend usage: SocketContextProvider stores the payload in onlineUsers state and exposes it through useSocketContext(). The sidebar uses this list to render a green indicator dot next to each contact:
const { onlineUsers } = useSocketContext();

// Show green dot if user is online
const isOnline = onlineUsers.includes(user._id);
userSocketMap is an in-memory object — it is not persisted to MongoDB. Restarting the server resets all presence state, and every connected client will receive a fresh getOnlineUsers broadcast once they reconnect.

newMessage

Direction: Server → Target Client only (via io.to(socketId).emit) Trigger: Fires from the sendMessage controller immediately after a message document is saved to MongoDB, but only when the receiver currently has an active socket connection:
// backend/controllers/message.controller.js (simplified)
const receiverSocketId = getReceiverSocketId(receiverId);
if (receiverSocketId) {
  io.to(receiverSocketId).emit("newMessage", newMessage);
}
Payload fields:
_id
string
required
MongoDB ObjectId of the message document.
senderId
string
required
MongoDB ObjectId of the user who sent the message.
receiverId
string
required
MongoDB ObjectId of the user who received the message.
message
string
required
The plaintext content of the message.
createdAt
string
required
ISO 8601 timestamp set by MongoDB when the document was created.
updatedAt
string
required
ISO 8601 timestamp updated by MongoDB on every document change.
Example payload:
{
  "_id": "65f1a2b3c4d5e6f7a8b9c0d1",
  "senderId": "64abc123def4567890abcdef",
  "receiverId": "64def456abc7890123defabc",
  "message": "Hey, are you free tonight?",
  "createdAt": "2024-03-13T18:45:00.000Z",
  "updatedAt": "2024-03-13T18:45:00.000Z"
}
Frontend handling in useListenMessages: When the event arrives, the hook plays notification.mp3, sets a shouldShake: true flag on the message object (used by the message bubble animation), and appends the message to the active conversation state:
// frontend/src/hooks/useListenMessages.js
socket?.on("newMessage", (newMessage) => {
  newMessage.shouldShake = true;
  const sound = new Audio(notificationSound);
  sound.play();
  setMessages([...messages, newMessage]);
});
If the receiver is offline when the message is sent, getReceiverSocketId returns undefined and no socket event is emitted. The message is still persisted in MongoDB and will appear in full when the receiver opens the conversation — Chat App fetches the full message history via GET /api/messages/:id on conversation select.

Complete Client-Side Usage Example

The snippet below shows how to consume both socket events inside a React component or custom hook using the context and Zustand store that Chat App already provides:
import { useSocketContext } from "../context/SocketContext";
import useConversation from "../zustand/useConversation";

// Inside a React component or hook:
const { socket, onlineUsers } = useSocketContext();
const { messages, setMessages } = useConversation();

// Listen for incoming messages
socket.on("newMessage", (newMessage) => {
  setMessages([...messages, newMessage]);
});

// Check if a user is online
const isOnline = onlineUsers.includes(userId);

Build docs developers (and LLMs) love