A real-time chat application with a Go server, Rust TUI client, and Android client.
GoChat is a multi-platform messaging app built around a WebSocket-based protocol. Users can register accounts, create rooms, and exchange messages in real time. The server handles authentication via JWT, persists data in PostgreSQL, and broadcasts messages through WebSocket connections.
┌──────────────┐ WebSocket ┌──────────────┐
│ Rust Client │◄──────────────────►│ │
│ (ratatui) │ │ Go Server │
└──────────────┘ │ (port 1919) │
│ │
┌──────────────┐ WebSocket │ PostgreSQL │
│Android Client│◄──────────────────►│ │
│ (Compose) │ └──────────────┘
└──────────────┘
- Go with
nhooyr.io/websocket - JWT authentication (register/login via REST, connect via WebSocket)
- PostgreSQL for users, rooms, messages, and membership
- Real-time message broadcasting, typing indicators, and presence tracking
- Rate limiting (100ms between messages)
- Terminal UI built with
ratatuiandcrossterm - Async networking with
tokioandtokio-tungstenite - Keyboard-driven interface with room switching, message history, and member lists
- Kotlin with Jetpack Compose and Material 3
- MVVM architecture with ViewModels and StateFlow
- OkHttp WebSocket with automatic reconnection (exponential backoff)
- Retrofit for REST authentication, DataStore for token persistence
- Navigation drawer for room management, bottom sheet for members
- Go 1.22+
- Rust (stable toolchain)
- Docker (for PostgreSQL)
- Android Studio Ladybug+ (for the Android client)
make dbmake serverThe server starts on port 1919 by default.
Rust TUI:
make clientAndroid:
Open the android/ directory in Android Studio and run on an emulator. The app connects to 10.0.2.2:1919 (emulator loopback to host).
All real-time communication uses a JSON envelope format over WebSocket:
{
"type": "chat.message",
"payload": { ... },
"timestamp": "2025-01-01T00:00:00Z"
}| Type | Direction | Description |
|---|---|---|
chat.send |
client → server | Send a message to a room |
chat.message |
server → client | Broadcasted message |
chat.edit |
client → server | Edit own message |
chat.edited |
server → client | Broadcasted edit |
chat.history |
client → server | Request message history |
chat.history.response |
server → client | History response with pagination |
room.create |
client → server | Create a new room |
room.created |
server → client | Room creation confirmation |
room.join |
client → server | Join a room |
room.joined |
server → client | Join confirmation |
room.leave |
client → server | Leave a room |
room.left |
server → client | Leave confirmation |
room.list |
client → server | Request all rooms |
room.list.response |
server → client | List of available rooms |
room.members |
client → server | Request room members |
room.members.response |
server → client | Member list with online status |
presence.online |
server → client | User came online |
presence.offline |
server → client | User went offline |
presence.typing |
bidirectional | Typing indicator |
system.ping |
server → client | Keep-alive ping |
system.pong |
client → server | Keep-alive response |
system.error |
server → client | Error with code and message |
| Method | Path | Description |
|---|---|---|
POST |
/api/auth/register |
Register a new account |
POST |
/api/auth/login |
Login and receive JWT |
GET |
/ws?token=<jwt> |
WebSocket connection |
Copy .env.example to .env and adjust as needed:
PORT=1919
DATABASE_URL=postgres://gochat:gochat@localhost:5432/gochat?sslmode=disable
JWT_SECRET=change-me-in-production
JWT_EXPIRY_HOURS=72
make build # builds both server and client
make build-server # server only → bin/gochat
make build-client # client only → bin/gochat-clientMIT