Skip to content

Latest commit

 

History

12 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 

Repository files navigation

Real-time chat app

WebSocket-based chat with typing indicators, read receipts, and online presence, built with a Node.js/Socket.io backend and a Flutter mobile frontend.

The core engineering problem this solves

A single chat server is easy. The interesting problem is: what happens when you run more than one server instance (which any real app needs, for reliability and scale)? A message sent by a user connected to Server A needs to reach a user connected to Server B. A plain WebSocket server can't do this on its own — the two instances don't know about each other.

Redis pub/sub solves this. Every server instance subscribes to the same Redis channels. When a message is sent, it's published to Redis, and every server instance (including ones the sender isn't connected to) receives it and forwards it to its own connected clients. This is what makes the system horizontally scalable instead of a single point of failure.

Architecture

Flutter App A ──WebSocket──┐
                            ├──> Server Instance 1 ──┐
Flutter App B ──WebSocket──┘                         │
                                                       ├──> Redis (pub/sub)
Flutter App C ──WebSocket──┐                         │
                            ├──> Server Instance 2 ──┘
Flutter App D ──WebSocket──┘
                                                  JSON file (message history)

Locally, running one server instance, Redis has no visible effect on behavior — it only matters (and becomes necessary) once you run multiple instances behind a load balancer. That's intentional: the architecture is built to scale even though the demo runs on one instance.

Tech stack

  • Backend: Node.js, Express, Socket.io, Redis (via ioredis + @socket.io/redis-adapter)
  • Auth: JWT + bcrypt password hashing
  • Persistence: lowdb (JSON file) — deliberately avoids native-compiled packages to skip Windows build-toolchain issues; swap for Postgres/MongoDB in production
  • Frontend: Flutter (Dart), socket_io_client package

Running the backend locally

Requires Node.js and Redis running locally (or a Redis Cloud free instance).

cd server
npm install
cp .env.example .env
# edit .env if needed — defaults work for local Redis on default port
npm start

Server runs on http://localhost:4000. Health check: GET /health.

Auth endpoints

  • POST /auth/signup{ "username": "...", "password": "..." }
  • POST /auth/login — same body shape

WebSocket events (after connecting with a JWT in auth.token)

  • room:join{ roomId }
  • message:send{ roomId, text }
  • message:read{ roomId, messageId }
  • typing:start / typing:stop{ roomId }

Server emits: room:history, message:new, message:readReceipt, typing:update, presence:update

Running the Flutter client

Requires Flutter SDK + Android Studio with an emulator set up.

cd client_flutter
flutter pub get
flutter run

Important: lib/config.dart points to http://10.0.2.2:4000 — this is the special Android emulator alias for your host machine's localhost. If you're testing on a physical device instead of an emulator, replace this with your PC's actual LAN IP address.

Demo

Login screen

Two users chatting in real-time across separate devices: Two-device chat Password_reset Password_reset

What I'd change to scale

  • Move online-presence tracking into Redis too (currently in-memory per instance, which means presence data doesn't sync across instances — only message delivery does, via the pub/sub adapter)
  • Swap lowdb for Postgres/MongoDB for real persistence guarantees
  • Add rate limiting on message sends to prevent spam/abuse
  • Add pagination for message history instead of a flat "last 50" slice

About

Real-time chat app with WebSocket messaging, Redis pub/sub for horizontal scaling, JWT auth, and Flutter mobile client

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages