Skip to content

Chat Service ​

Port: 8085 (HTTP + WebSocket)
Database: omninet_chat (PostgreSQL)
Language: Go 1.22
Framework: go-chi/chi v5

The chat service is OmniNet's real-time messaging backbone, built in Go for maximum concurrency and low-latency WebSocket handling.

Features ​

  • Real-Time Messaging — Bidirectional WebSocket communication via gorilla/websocket.
  • DM & Group Conversations — Create 1-to-1 direct messages or multi-member group chats.
  • Multi-Tab Support — A single user can connect from multiple browser tabs simultaneously; all receive messages.
  • Redis Pub/Sub Fan-Out — Messages delivered to one instance are published to Redis and consumed by all other instances — enabling horizontal scaling with zero shared in-process state.
  • Typing Indicators — Broadcast real-time typing events to all conversation members (excluding the sender). Stored temporarily in Redis.
  • Delivery & Read Receipts — DELIVERED status set on message delivery; READ status pushed when a member calls mark_read.
  • Emoji Reactions — Add/remove reactions on any message; updated reactions map broadcast to all members.
  • User Presence — Online/offline status tracked in Redis + PostgreSQL. New connections receive the current online list immediately.
  • Message Edit & Delete — REST API for editing message content or soft-deleting (unsend); changes broadcast via WebSocket.
  • Member Management — Add/remove members from group conversations via REST API.
  • Graceful Shutdown — 10-second drain using signal.NotifyContext + http.Server.Shutdown.
  • Structured Logging — go.uber.org/zap with production-mode JSON logging.

Stack ​

ComponentLibrary
HTTP Routergo-chi/chi v5
WebSocketgorilla/websocket v1.5
PostgreSQLjackc/pgx v5 (connection pool)
Redisredis/go-redis v9
JWTgolang-jwt/jwt v5
Loggergo.uber.org/zap

WebSocket Events ​

Client → Server ​

EventDescription
send_messageSend a text message to a conversation
typingNotify members that user is typing
mark_readMark all messages up to last_message_id as read
add_reactionAdd emoji reaction to a message
remove_reactionRemove emoji reaction
pingKeepalive ping

Server → Client ​

EventDescription
connectedSent immediately after WS handshake with user info
new_messageNew message received in a conversation
message_editedA message's content was updated
message_deletedA message was unsent/deleted
message_statusDelivery or read receipt update (DELIVERED / READ)
typingAnother user is typing
presenceUser came online or went offline
reaction_updateEmoji reactions on a message changed
pongResponse to ping
errorOperation failed with code + message

WebSocket Connection ​

Connect with a JWT as a query parameter (since browsers can't set Authorization headers on WebSocket):

ws://localhost:8085/ws?token=<jwt>

On connection the server immediately sends:

json
{ "type": "connected", "payload": { "user_id": "...", "email": "..." } }

REST API ​

Conversations ​

MethodPathDescription
GET/api/chat/conversationsList user's conversations
POST/api/chat/conversationsCreate DM or group conversation
GET/api/chat/conversations/{id}Get conversation details
PUT/api/chat/conversations/{id}Update name/avatar
POST/api/chat/conversations/{id}/membersAdd member to group
DELETE/api/chat/conversations/{id}/members/{userId}Leave / remove from group

Messages ​

MethodPathDescription
GET/api/chat/conversations/{id}/messagesPaginated message history
POST/api/chat/conversations/{id}/readMark conversation as read
PUT/messages/{id}Edit a message
DELETE/messages/{id}Delete (unsend) a message
POST/messages/{id}/reactionsAdd emoji reaction
DELETE/messages/{id}/reactions/{emoji}Remove emoji reaction

Presence ​

MethodPathDescription
GET/api/chat/presence?user_ids=a,b,cBatch query online status

Hub Architecture ​

Message Flow ​

Horizontal Scaling ​

Each hub instance registers a Redis Pub/Sub subscriber on chat:presence and per-conversation channels (chat:conv:{id}). When a message target is not connected locally, deliverToUser publishes to Redis, and the instance where the target user is connected picks it up and delivers it.

NOTE

The chat service runs independently on port 8085. It does not go through the Java API Gateway — it validates JWTs directly using the same JWT_SECRET.

Released under the MIT License.