Chat Socket.IO Playground
Connect as a test user, join a conversation, emit chat events, and inspect every live server response from one focused workspace.
Shared connection settings
Both actors use the same host on the fixed Socket.IO port 30123.
clientproviderRoom lifecycle
Client and Provider enter the same existing chat using chatId only.
Waiting for chatId
02 · Client starts the conversation
Enter the existing chatId. The tester copies it to the Provider side automatically.
03 · Provider joins the resolved room
The Provider chatId is synchronized from the Client field and confirmed by chat:participant-joined.
Message exchange
Outgoing messages appear immediately as pending, then show the measured latency when the server broadcasts them.
Event payloads and server behavior
Use this section when you need exact fields, validation rules, or broadcast targets.
Connection
Connect to the API host on fixed port 30123 using Socket.IO path /socket.io/.
const socketOrigin = new URL(baseOrigin);
socketOrigin.port = "30123";
const socket = io(socketOrigin.origin, {
path: "/socket.io/",
query: {
userId: "665f1c2a9b4e1d0012ab34b2",
lang: "ar",
userType: "client",
deviceType: "web",
deviceId: "browser-session-id"
}
});
| Handshake field | Rules |
|---|---|
userId | Required Mongo ObjectId |
lang | ar or en |
userType | admin, client, store, haraj, or provider |
deviceType | ios, android, or web |
deviceId | Required non-empty identifier |
The server takes user identity from the validated connection query and checks chat membership. Do not send identity fields as authority inside event payloads.
Success event:
connected
{ "userId": "...", "deviceId": "...", "deviceType": "web" }
An invalid handshake currently emits auction:error with { "message": "..." } and registers no chat handlers.
Client → server
chat:enter
{ "chatId": "665f1c2a9b4e1d0012ab34c1" }
// Or find/create a direct chat:
{ "receiverId": "665f1c2a9b4e1d0012ab34b1" }
- Send
chatIdorreceiverId;chatIdwins when both exist. - The selected value must be a Mongo ObjectId. When both fields are sent,
receiverIdis ignored and onlychatIdis validated. - Existing chat access is member-checked. Direct receiver mode finds or creates a 1:1 chat.
- Success broadcasts
chat:participant-joinedto the room, including the joining socket.
{
"chatId": "...",
"targetId": null,
"type": null,
"totalParticipants": 1,
"user": { "id": "...", "name": "Example user", "userType": "client" }
}
chat:message
{ "chatId": "665f1c2a9b4e1d0012ab34c1", "message": "Hello" }
- The socket must enter the room first.
- The message is trimmed, required, text-only, and limited to 4000 characters.
- The Socket server rejects Western, Arabic-Indic, or Persian digits through
chat:errorbefore persistence. - Success broadcasts
chat:message-receivedin the standard response envelope.
{
"key": "success",
"message": "Success",
"status": 200,
"data": {
"id": "...",
"type": "text",
"message": "Hello",
"senderPath": "client",
"senderId": "...",
"senderName": "Example user",
"senderAvatar": "https://example.test/avatar.png",
"date": "a few seconds ago",
"chatId": "...",
"direction": "left"
}
}
chat:exit
{ "chatId": "665f1c2a9b4e1d0012ab34c1" }
The user must be a member and the socket must be inside the room. Success broadcasts chat:participant-left to the other room sockets and then leaves the room.
Server → client
| Event | Recipient and payload |
|---|---|
connected | Connecting socket: userId, deviceId, deviceType |
chat:participant-joined | Room: chatId, targetId, type, totalParticipants, user |
chat:message-received | Room: ApiResponse envelope with the message DTO |
chat:notification-status | Sender: server-side FCM acceptance summary; accepted is not a device delivery receipt |
chat:participant-left | Other room sockets after explicit exit |
chat:participants-updated | Remaining sockets after disconnect: chatId, totalParticipants |
chat:error | Emitting socket: localized message only |
auction:error | Connecting socket when the shared handshake is invalid |
Error and acknowledgement behavior
Chat events currently have no acknowledgement callbacks. chat:error has no stable code or status:
{ "message": "Join the chat room before sending messages." }
HTTP boundary
GET /api/chats— list chats.GET /api/chat/messages— paginated history.POST /api/chat/upload— image upload.
The image upload endpoint returns a URL, but the current Socket.IO message handler accepts text only. There is no implemented chat:image event.
Client flow
- Connect and wait for
connected. - Register all server listeners.
- Emit
chat:enterand read the resolved chatId fromchat:participant-joined. - Emit
chat:messageonly after entering. - Use the HTTP messages endpoint for history.
- Emit
chat:exitwhen leaving the screen. - After reconnect, enter the room again before sending.
Repository source: docs/CHAT_SOCKET_EVENTS.md.