Throwaway, kept as a primary source rather than on main. Single self-contained HTML file: free-play buttons plus six guided walkthroughs over a pure reducer. It settled two things the spec had wrong or missing: - The client must supply the message id. With a server-generated id there is nothing to reconcile the optimistically rendered message against when it comes back over the realtime channel, and it renders twice. Both cases are reproducible via the toggle at the top. - An unread *count* cannot be derived without fetching, because seq counts events and not messages. Hence: fetch for DMs, a plain dot for channels.
rustification-client
Desktop chat client for Rustification. Built with Tauri v2 (Rust backend) and React + TypeScript (frontend).
Tech stack
| Layer | Technology |
|---|---|
| Desktop shell | Tauri v2 |
| Frontend | React 18 + TypeScript, Vite |
| HTTP | reqwest (Rust) via Tauri commands |
| Persistence | tauri-plugin-store (JWT token, user ID) |
| Build (Linux) | nix-shell |
Features
- Login / Register — authenticates against the rustification-server, stores JWT via tauri-plugin-store
- Workspace list — browse workspaces the current user belongs to
- Chat page — conversation list, message history, and real-time polling for new messages
- Message input — send messages to any conversation
- Member panel — view conversation members
- Settings page — user preferences
Prerequisites
- Rust + Cargo
- Node.js 18+ and npm
- Tauri v2 system dependencies (see below)
- A running rustification-server
System dependencies (Linux)
The project ships a shell.nix. If you use Nix, enter the dev shell first:
nix-shell
This provides: cargo, rustc, pkg-config, glib, gtk3, webkitgtk_4_1, libsoup_3, openssl, librsvg.
Without Nix, install the equivalent packages via your system package manager. On Debian/Ubuntu:
sudo apt install libgtk-3-dev libwebkit2gtk-4.1-dev libsoup-3.0-dev \
libayatana-appindicator3-dev librsvg2-dev
Getting started
# Install frontend dependencies
npm install
# Start in development mode (hot-reload frontend + Tauri window)
# Must be run inside nix-shell on NixOS / Nix systems
npm run tauri dev
The client defaults to http://localhost:3000/api/v1 as the server base URL (configurable at runtime via Settings).
Build
# Must be run inside nix-shell on NixOS / Nix systems
npm run tauri build
Output bundles (.deb, .AppImage, etc.) are written to src-tauri/target/release/bundle/.
Project structure
src/ # React frontend
├── main.tsx # Entry point
├── App.tsx # Router + AuthContext provider
├── theme.ts # MUI / global theme
├── styles.css
├── contexts/
│ └── AuthContext.tsx # Auth state (token, user ID, login/logout)
├── pages/
│ ├── LoginPage.tsx
│ ├── WorkspacePage.tsx
│ ├── ChatPage.tsx
│ └── SettingsPage.tsx
└── components/
├── ConversationList.tsx
├── MessageList.tsx
├── MessageInput.tsx
├── MemberPanel.tsx
└── Toast.tsx
src-tauri/ # Tauri Rust backend
├── Cargo.toml
└── src/
├── lib.rs # Tauri builder, plugin + command registration
├── main.rs
├── state.rs # AppState: reqwest client, token, base URL
├── models.rs # Shared response types
└── commands/
├── user.rs # login, register, refresh_session, logout
├── workspace.rs # list_workspaces
├── conversation.rs # list_conversations
└── message.rs # list_messages, send_message
Tauri commands
The frontend calls these via invoke():
| Command | Description |
|---|---|
login |
Authenticates and stores JWT + user ID |
register |
Registers a new account |
refresh_session |
Refreshes the JWT using the stored refresh token |
logout |
Clears stored credentials |
list_workspaces |
Returns workspaces for the current user |
list_conversations |
Returns conversations for a workspace |
list_messages |
Returns messages for a conversation |
send_message |
Posts a new message |
Server connection
The default base URL is http://localhost:3000/api/v1. To point the client at a different server, update the URL in Settings — it is persisted in the Tauri store across sessions.