# GroupChat2 Server

The server is a Rust/Axum application that provides authentication, room and message APIs, WebSocket chat delivery, AI response orchestration, file uploads, and SQLite-backed persistence for GroupChat2.

## Stack

- Rust 2021
- Axum and Tokio
- SQLx with SQLite
- JWT auth and Argon2 password hashing
- OpenRouter for AI completions
- Tavily or Brave for web search tools

## Responsibilities

- Register and authenticate users
- Support Nostr challenge/verify login
- Manage rooms, members, invites, and profile updates
- Persist messages, hashes, room settings, and AI metadata
- Broadcast real-time events over WebSockets
- Stream AI responses and tool usage events to connected clients
- Store uploaded avatars and chat images
- Serve built frontend assets in production

## Requirements

- Rust toolchain with `cargo`
- A valid `OPENROUTER_API_KEY`
- A search provider configured through either Tavily or Brave

## Environment

Copy `.env.example` to `.env` and fill in the values you need.

```bash
cp .env.example .env
```

Important variables:

- `BIND_ADDR`: server bind address, default `0.0.0.0:3001`
- `RUST_LOG`: log level, default `info`
- `DATABASE_URL`: SQLite connection string, default `sqlite:chat.db?mode=rwc`
- `JWT_SECRET`: JWT signing secret
- `OPENROUTER_API_KEY`: required
- `SEARCH_PROVIDER`: `tavily` or `brave`
- `TAVILY_API_KEY`: required when `SEARCH_PROVIDER=tavily`
- `BRAVE_API_KEY`: required when `SEARCH_PROVIDER=brave`
- `STATIC_DIR`: optional path to built client assets for production serving

## Commands

Run the backend directly:

```bash
cargo run
```

Build a release binary:

```bash
cargo build --release
```

From the repo root, production build/run is also available through:

```bash
./prod.sh
```

## Startup Behavior

On startup the server:

- loads environment variables from `.env`
- validates required AI/search configuration
- creates a timestamped backup of the SQLite database if it already exists
- keeps the 10 most recent backups
- opens the SQLite database
- applies SQL migrations embedded in the binary

## API Surface

Main routes exposed by the server:

- `/api/auth/register`
- `/api/auth/login`
- `/api/auth/me`
- `/api/auth/profile`
- `/api/auth/avatar`
- `/api/auth/nostr/challenge`
- `/api/auth/nostr/verify`
- `/api/rooms`
- `/api/rooms/:room_id`
- `/api/rooms/:room_id/messages`
- `/api/rooms/:room_id/join`
- `/api/rooms/:room_id/clear`
- `/api/messages/hash/:hash`
- `/api/models`
- `/api/invites`
- `/api/invites/:token/accept`
- `/api/invites/nostr`
- `/api/upload`
- `/ws`
- `/uploads/*`

## Real-Time Flow

WebSocket clients connect to `/ws` with a JWT token in the query string.

Client messages include:

- `join_room`
- `typing`
- `send_message`

Server events include:

- new messages
- AI typing notifications
- AI stream chunks and stream end markers
- AI tool usage updates
- user typing notifications
- room deleted and room cleared events

## Storage Layout

```text
server/
|- migrations/   SQL schema and incremental changes
|- src/          handlers, middleware, models, services
|- uploads/      avatars and chat images
|- backups/      automatic database backups
|- chat.db       SQLite database
```

Uploaded file behavior:

- avatars are stored under `uploads/avatars/`
- chat images are stored under `uploads/chat-images/`
- avatar uploads are limited to 2 MB
- chat image uploads are limited to 5 MB

## AI Behavior

When a user mentions the assistant or the room is configured to always respond, the server:

- loads recent room history
- includes image context for human-uploaded images when available
- calls OpenRouter in streaming mode
- executes tool calls for search or page fetches
- broadcasts streaming output to the room
- stores the final AI response with usage metadata

For frontend behavior and local browser setup, see the [Client README](../client/README.md).
