- Rust 57%
- JavaScript 24.2%
- CSS 9.9%
- HTML 8.9%
| .forgejo/workflows | ||
| build | ||
| desktop | ||
| migrations | ||
| scripts | ||
| shared-html | ||
| src | ||
| static | ||
| .env.example | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| main.js | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| test.html | ||
| test_output.txt | ||
Chattz
A simple single-instance Discord-style monolith in Rust using:
axumHTTP serverSeaORM+ PostgreSQL for persistence- Authentik OIDC for login
What this includes
- OIDC login flow (
/auth/login,/auth/callback,/auth/logout) - HttpOnly session cookie auth
- Channel voice chat over WebRTC (P2P mesh) with server WebSocket signaling
- Guild invite codes (create + join)
- Direct messages (DM) between users
- Core resources:
- users
- guilds + guild membership
- channels
- messages
- direct_messages
- Basic JSON APIs for creating guilds/channels and posting/listing messages
Quick start
- Create DB and apply schema:
- Create DB:
CREATE DATABASE chattz;
- Configure env:
cp .env.example .env
# edit .env values
For voice reliability on restrictive networks, configure TURN in .env:
TURN_URLSTURN_USERNAMETURN_PASSWORD
For production deployments:
APP_BASE_URLmust be your public app origin and should usehttpsMEDIA_BASE_URLshould be a separate media origin for user uploads- uploads and soundboard require R2/object storage to be configured
- Run app:
cargo run
Migrations are applied automatically during startup.
Server binds to 0.0.0.0:${PORT} (defaults to 3000).
Web UI is available at http://localhost:${PORT}/.
Authentik setup notes
Create an Authentik OAuth2/OIDC provider + application and set:
- Redirect URI:
${APP_BASE_URL}/auth/callback - Scopes including at least:
openid profile email
If you change PORT, update OIDC_REDIRECT_URL and this redirect URI to match.
Then copy provider endpoints into env:
OIDC_AUTHORIZE_URLOIDC_TOKEN_URLOIDC_USERINFO_URL
For Authentik these are commonly under /application/o/... for the app slug.
API summary
GET /healthGET /auth/loginGET /auth/callback?code=...&state=...POST /auth/logoutGET /meGET /dmsGET /dms/:other_user_id/messages?limit=50POST /dms/:other_user_id/messagesbody:{ "body": "hello" }GET /rtc-configGET /guildsPOST /guildsbody:{ "name": "My Guild" }GET /guilds/:guild_id/membersGET /guilds/:guild_id/voice-presencePOST /guilds/:guild_id/invitesbody:{ "max_uses": 50, "expires_in_hours": 24 }POST /invites/:code/joinGET /guilds/:guild_id/channelsPOST /channelsbody:{ "guild_id": "...", "name": "general", "kind": "text|voice" }GET /channels/:channel_id/messages?limit=50POST /channels/:channel_id/messagesbody:{ "body": "hello" }GET /channels/:channel_id/voice/ws(WebSocket signaling)
All endpoints except health and auth flow require the session cookie from successful login.
Authenticated WebSocket connections (/ws, /channels/:channel_id/voice/ws) also use the same cookie session.
Notes
This is intentionally minimal and monolithic (single process, single Postgres instance).
Voice is implemented as browser-to-browser WebRTC audio with signaling in this server.
For two users behind strict NAT/firewall, you may need TURN for reliable connectivity.
The web UI remembers the last selected guild in browser local storage and auto-selects it on reload.
User uploads are served from the configured media origin, not from /static.
Mic filter modes in the UI:
NSNet2 (Compat): always-on denoising mode (implemented using DeepFilterNet3 with lighter suppression preset)
Noise processing requires browsers with AudioWorklet support (modern Chrome/Edge/Firefox).