# 🔀 Chat Switchboard **Multi-Model AI Chat Platform — Self-Hosted, Extensible, Fast** A self-hosted AI chat interface that routes conversations across multiple LLM providers. Built with a Go backend for performance and a clean vanilla JS frontend inspired by Open WebUI. [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Go Version](https://img.shields.io/badge/Go-1.22+-00ADD8?logo=go)](https://go.dev/) --- ## What It Does - **Multi-provider routing** — Connect OpenAI, Anthropic, Venice.ai, Ollama, or any OpenAI-compatible API. Switch models per-conversation. - **Streaming responses** — SSE-based streaming with stop button, thinking block display, and full markdown rendering. - **Per-user API keys** — Each user manages their own provider keys. Admins can set global keys shared across the instance. - **Admin panel** — User management, global provider config, model visibility, registration toggle, usage stats. - **Self-hosted** — Single Docker image, PostgreSQL backend. No external dependencies at runtime. --- ## Quick Start ### Docker (Recommended) ```bash git clone https://git.gobha.me/xcaliber/chat-switchboard.git cd chat-switchboard cp server/.env.example server/.env # Edit .env: set DATABASE_URL, JWT_SECRET, etc. docker-compose up -d ``` Access at `http://localhost:3000`. First registered user becomes admin. ### Manual ```bash # Backend cd server cp .env.example .env go build -o switchboard . ./switchboard # Frontend — serve src/ with any HTTP server cd ../src python3 -m http.server 8080 ``` Point the frontend at the backend by setting the API base URL (defaults to same-origin). --- ## Architecture ``` ┌──────────────────────────┐ │ Frontend (Vanilla JS) │ │ 4 files + vendor libs │ │ No build step required │ └───────────┬──────────────┘ │ REST + SSE ▼ ┌──────────────────────────┐ │ Go Backend │ │ ├── Auth (JWT + refresh)│ │ ├── Chat CRUD │ │ ├── Completion proxy │ │ ├── Provider management │ │ ├── Admin endpoints │ │ └── Static file server │ └───────────┬──────────────┘ │ PostgreSQL ``` ### Frontend (src/) | File | Size | Purpose | |------|------|---------| | `api.js` | 240 lines | HTTP client, token management, auto-refresh on 401 | | `app.js` | 490 lines | State, init flow, auth, chat CRUD, event wiring | | `ui.js` | 510 lines | DOM rendering, streaming, modals, formatting | | `debug.js` | 550 lines | Console/network intercept, state inspector (Ctrl+Shift+L) | | `vendor/` | 62KB | marked.js + DOMPurify (local, CDN fallback) | No framework. No build step. No node_modules. Works in disconnected (SCIF) environments with vendor libs baked in. ### Backend (server/) Go 1.22, ~26 source files. Key packages: - `handlers/` — Auth, chats, messages, completions, API configs, admin - `middleware/` — JWT auth, admin role check, rate limiting, error handling, logging - `providers/` — OpenAI and Anthropic adapters with streaming support - `models/` — Database models - `database/` — PostgreSQL connection + migration runner - `config/` — Environment-based configuration ### API Surface | Route | Method | Auth | Description | |-------|--------|------|-------------| | `/health` | GET | — | Health check + version | | `/api/v1/auth/register` | POST | — | Create account | | `/api/v1/auth/login` | POST | — | Get JWT tokens | | `/api/v1/auth/refresh` | POST | — | Rotate access token | | `/api/v1/chats` | GET/POST | ✓ | List / create chats | | `/api/v1/chats/:id` | GET/PUT/DELETE | ✓ | Chat CRUD | | `/api/v1/chats/:id/messages` | GET | ✓ | Message history | | `/api/v1/chat/completions` | POST | ✓ | Streaming SSE or sync JSON | | `/api/v1/models/enabled` | GET | ✓ | Available models | | `/api/v1/api-configs` | GET/POST/DELETE | ✓ | User provider management | | `/api/v1/profile` | GET/PUT | ✓ | User profile | | `/api/v1/settings` | GET/PUT | ✓ | User settings (persisted) | | `/api/v1/admin/*` | various | admin | User/provider/model/settings management | --- ## Configuration All via environment variables (see `server/.env.example`): | Variable | Default | Description | |----------|---------|-------------| | `PORT` | `8080` | Backend listen port | | `DATABASE_URL` | — | PostgreSQL connection string | | `JWT_SECRET` | — | Token signing key | | `JWT_EXPIRY` | `15m` | Access token TTL | | `REFRESH_EXPIRY` | `7d` | Refresh token TTL | | `CORS_ORIGINS` | `*` | Allowed origins | | `REGISTRATION_ENABLED` | `true` | Allow new signups | --- ## Deployment ### Docker Compose (unified) The provided `Dockerfile` is a 3-stage build: 1. `golang:1.22-bookworm` — compiles Go backend 2. `node:20-alpine` — downloads vendor JS libs via `npm pack` 3. `nginx:1-alpine` — serves frontend, proxies `/api/` to Go backend Vendor libs are baked into the image at build time — no CDN access needed at runtime (SCIF-safe). ### Reverse Proxy If running behind nginx/Caddy, proxy `/api/` and `/health` to the Go backend. Serve `src/` as static files. --- ## Development ```bash # Backend (hot reload with air) cd server go install github.com/air-verse/air@latest air # Frontend — just edit files, hard-refresh browser # Debug: Ctrl+Shift+L opens debug modal ``` ### Database Migrations Migrations in `migrations/` run automatically on startup. Current schema: - `001_full_schema.sql` — users, chats, messages, api_configs - `002_refresh_tokens.sql` — token rotation - `003_global_settings.sql` — admin settings table - `004_model_configs.sql` — per-model enable/disable --- ## Roadmap See [ROADMAP.md](ROADMAP.md) for the full plan. Next up: 1. **WebSocket hub** — real-time message delivery, typing indicators 2. **Channels** — multi-user + AI chat rooms with @mentions 3. **Plugin system** — Go-native extensions, installable via admin UI 4. **Notes & Knowledge Base** — markdown notes, document upload, RAG via pgvector --- ## License MIT — build anything, including commercial products. --- **Repository:** https://git.gobha.me/xcaliber/chat-switchboard