# Chattz

A simple single-instance Discord-style monolith in Rust using:
- `axum` HTTP server
- `SeaORM` + PostgreSQL for persistence
- Authentik OIDC for login

## What this includes

- OIDC login flow (`/auth/login`, `/auth/callback`, `/auth/logout`)
- Signed 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

1. Create DB and apply schema:
1. Create DB:

```sql
CREATE DATABASE chattz;
```

2. Configure env:

```bash
cp .env.example .env
# edit .env values
```

For voice reliability on restrictive networks, configure TURN in `.env`:
- `TURN_URLS`
- `TURN_USERNAME`
- `TURN_PASSWORD`

3. Run app:

```bash
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: `http://localhost:3000/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_URL`
- `OIDC_TOKEN_URL`
- `OIDC_USERINFO_URL`

For Authentik these are commonly under `/application/o/...` for the app slug.

## API summary

- `GET /health`
- `GET /auth/login`
- `GET /auth/callback?code=...&state=...`
- `POST /auth/logout`
- `GET /me`
- `GET /dms`
- `GET /dms/:other_user_id/messages?limit=50`
- `POST /dms/:other_user_id/messages` body: `{ "body": "hello" }`
- `GET /rtc-config`
- `GET /guilds`
- `POST /guilds` body: `{ "name": "My Guild" }`
- `GET /guilds/:guild_id/members`
- `GET /guilds/:guild_id/voice-presence`
- `POST /guilds/:guild_id/invites` body: `{ "max_uses": 50, "expires_in_hours": 24 }`
- `POST /invites/:code/join`
- `GET /guilds/:guild_id/channels`
- `POST /channels` body: `{ "guild_id": "...", "name": "general", "kind": "text|voice" }`
- `GET /channels/:channel_id/messages?limit=50`
- `POST /channels/:channel_id/messages` body: `{ "body": "hello" }`
- `GET /channels/:channel_id/voice/ws` (WebSocket signaling)

All endpoints except health and auth flow require the session cookie from successful login.

## 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.

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).
