A modern, headless WebSocket API for building real-time chat applications. Rufer provides a robust backend infrastructure with built-in support for message delivery status, typing indicators, user presence, and more.
Includes a complete reference implementation built with Vue.js to demonstrate integration patterns and best practices.
- π WebSocket-based real-time messaging API
- π₯ Built-in user presence detection
- βοΈ Typing indicators
- β Message delivery status (delivered/read)
- π Last seen timestamps
- πΎ Message persistence with MongoDB
- π‘ MongoDB Change Streams for real-time updates
- π Automatic reconnection handling with exponential backoff
- π Session-based authentication with auto-expiring tokens
- π Debug mode for development
- π Automatic message delivery on reconnection
- π Unread message counter per chat
- π Optimistic message updates
- π Automatic session refresh on disconnection
- π― Complete reference implementation included
- π Separate backend service for token management
-
Frontend:
- Vue 3 with Composition API
- Pinia for state management
- Socket.IO client
- TypeScript
-
Backend:
- Express.js
- Socket.IO server
- MongoDB with Change Streams
- Mongoose
- TypeScript
- Docker and Docker Compose
-
Clone the repository:
git clone https://github.com/dashersw/rufer.git cd rufer
-
Create environment files:
# Main backend cp .env.example .env # Reference implementation backend cd reference-implementation/backend cp .env.example .env # Reference implementation frontend cd ../frontend cp .env.example .env cd ../..
Edit the
.env
files:- Main backend
.env
: Set yourRUFER_SECRET_KEY
and other variables - Reference backend
.env
: Set the sameRUFER_SECRET_KEY
and optionally adjustRUFER_URL
- Reference frontend
.env
: AdjustVITE_RUFER_URL
andVITE_BACKEND_URL
if needed
- Main backend
-
Start the application:
docker compose up
The reference backend will automatically register two test users:
alice
(Alice Smith)bob
(Bob Johnson)
-
Open two browser windows to test the chat:
Window 1: http://localhost:5173?userId=alice Window 2: http://localhost:5173?userId=bob
For debug mode, add
&debug=true
to see system messages and detailed message status:http://localhost:5173?userId=alice&debug=true
The debug mode is particularly useful to see:
- Message delivery status
- Typing indicators
- Connection events
- Online/offline status changes
The application uses Docker volumes for development, which means:
- Source code changes are reflected immediately
- No need to rebuild containers for code changes
- Frontend hot module replacement (HMR) works out of the box
- Backend automatically restarts on changes
api
: Backend service running on port 3000frontend
: Frontend service running on port 5173- MongoDB: Cloud-hosted database (no local setup required)
If you prefer to run the services without Docker:
-
Install dependencies:
# Install backend dependencies npm install # Install frontend dependencies cd frontend npm install
-
Create a
.env
file in the root directory:PORT=3000 DATABASE_URL=mongodb://localhost:27017/chat-app
-
Start the development servers:
# Start backend (from root directory) npm run dev # Start frontend (from frontend directory) cd frontend npm run dev
βββ src/ # Backend source code
β βββ models/ # Mongoose models
β βββ routes/ # Express routes
β βββ services/ # Business logic
β βββ types.ts # TypeScript types
βββ frontend/ # Frontend source code
β βββ src/
β β βββ components/ # Vue components
β β βββ stores/ # Pinia stores
β β βββ views/ # Vue views
β βββ public/ # Static assets
βββ docker-compose.yml # Docker Compose configuration
βββ Dockerfile # Backend Dockerfile
βββ package.json # Project configuration
- Messages are delivered instantly using Socket.IO
- Persistent storage in MongoDB
- Message status tracking (delivered/read)
- Change Streams for reliable real-time updates
- Real-time online/offline status
- Last seen timestamps
- Automatic status updates
- Real-time typing status
- Debounced typing events
- Automatic timeout after 3 seconds
- Delivered status when recipient receives message
- Read status when recipient opens the chat
- Visual indicators for message status
- Enable with
?debug=true
in URL - Shows detailed message information
- System messages for events
- Connection status updates
- MongoDB Change Streams for real-time data synchronization
- Separate collections for messages, users, and change events
- Change events track message delivery and read status
- Reliable event ordering and delivery through Change Streams
- No polling required - pure event-driven architecture
- Session tokens expire after 15 minutes
- Automatic token refresh on reconnection
- Secure session validation middleware
- Single-use tokens for enhanced security
- Instant message display before server confirmation
- Temporary message IDs for tracking
- Automatic update with server-assigned IDs
- Graceful error handling for failed messages
- Complete reference frontend implementation
- Separate token management backend service
- Example of secure token handling
- Production-ready authentication flow
- Detailed connection status updates
- Socket lifecycle events
- Message delivery confirmations
- Typing indicator events
- User presence updates
- Exponential backoff strategy
- Random jitter for distributed load
- Automatic session refresh
- State recovery after reconnection
- Maximum retry limit with configurable attempts
- Unread message counter per conversation
- Automatic counter reset on chat focus
- Last message preview in chat list
- Real-time chat list updates
- Optimistic chat list sorting
- User registration requires a secret key (
RUFER_SECRET_KEY
) - Each user gets a unique session token for Socket.IO connections
- The reference backend service manages token generation and validation
- The main backend service uses single-use session tokens for Socket.IO connections
- Environment variables control security settings
- MongoDB connection string and secret key must be kept secure
-
User Registration:
npm run register-user alice "Alice Smith"
This will:
- Register/update the user in the main backend using the
RUFER_SECRET_KEY
- The user is stored in MongoDB with their ID and display name
- Register/update the user in the main backend using the
-
Socket.IO Connection Flow:
The reference implementation demonstrates a secure connection flow:
- Frontend requests a temporary session token from reference backend
- Reference backend uses
RUFER_SECRET_KEY
to request session token from main backend - Main backend generates a single-use session token (15-minute expiry)
- Frontend uses session token to establish Socket.IO connection
// Request session token from reference backend const response = await referenceApi.post('/session-token', { userId }) const sessionToken = response.data.token // Use session token for Socket.IO connection const socket = io('http://localhost:3000', { auth: { token: sessionToken } })
-
Token Security Features:
- Session tokens:
- Single-use: Invalidated after first Socket.IO connection
- Short-lived: Expire after 15 minutes
- Automatically refreshed on reconnection
- Tied to specific user and socket connection
- Session tokens:
-
Production Considerations:
- Implement secure token storage
- Use environment-specific token generation
- Consider implementing token rotation
- Add rate limiting for token requests
- Monitor token usage for security anomalies
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add some amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.