234 lines
8.7 KiB
Markdown
234 lines
8.7 KiB
Markdown
# Chat Switchboard
|
|
|
|
A self-hosted AI chat application for enterprise and government environments. Unified interface for multiple AI providers with admin controls, team management, and security features.
|
|
|
|
## Quick Start
|
|
|
|
```bash
|
|
# Clone and start
|
|
git clone <repo-url> && cd chat-switchboard
|
|
docker compose up -d
|
|
|
|
# Access at http://localhost:3000
|
|
# Default admin: admin / admin
|
|
```
|
|
|
|
## Features
|
|
|
|
- **Multi-Provider**: Anthropic, OpenAI, OpenRouter, Venice AI — with BYOK support
|
|
- **Team Management**: Roles (admin/user) for vertical permissions, Teams for horizontal visibility
|
|
- **Personas**: Preset configurations (model + system prompt + parameters) at global, team, or personal scope
|
|
- **Model Catalog**: Three-state visibility (enabled/disabled/team-only) with admin controls
|
|
- **Message Trees**: Edit and regenerate with full conversation forking — navigate sibling branches
|
|
- **Notes**: Markdown notes with full-text search, folders, and tags
|
|
- **Audit Log**: All admin operations logged with actor, action, and resource details
|
|
- **Security**: JWT + refresh tokens, optional mTLS, optional OIDC/Keycloak, environment classification banners
|
|
- **Airgapped**: Local vendor files (marked.js, DOMPurify), no CDN required
|
|
- **Mobile**: Responsive design, PWA manifest
|
|
|
|
## Architecture
|
|
|
|
```
|
|
┌─────────────┐ ┌──────────────────────────────┐
|
|
│ Browser │────▶│ nginx (port 80) │
|
|
│ (vanilla JS)│◀────│ ├─ /api/* → Go backend:8080 │
|
|
└─────────────┘ │ ├─ /ws → WebSocket proxy │
|
|
│ └─ /* → static files │
|
|
└──────────────────────────────┘
|
|
│
|
|
┌─────────▼─────────┐
|
|
│ Go Backend │
|
|
│ ├─ handlers/ │
|
|
│ ├─ store/postgres/ │
|
|
│ ├─ providers/ │
|
|
│ └─ capabilities/ │
|
|
└─────────┬─────────┘
|
|
│
|
|
┌─────────▼─────────┐
|
|
│ PostgreSQL 16 │
|
|
└───────────────────┘
|
|
```
|
|
|
|
**Go backend** (vanilla, no framework beyond Gin) with a store layer abstracting all database access. Providers package handles LLM API calls. Capabilities package resolves model features from catalog data, known model tables, and heuristic inference.
|
|
|
|
**Frontend** is vanilla JavaScript — no build step, no bundler. Five files: `api.js` (HTTP client), `app.js` (state + logic), `ui.js` (DOM rendering), `events.js` (event bus + WebSocket), `debug.js` (admin debug panel).
|
|
|
|
## Configuration
|
|
|
|
All configuration via environment variables. See `server/.env.example` for the full list.
|
|
|
|
| Variable | Default | Description |
|
|
|----------|---------|-------------|
|
|
| `PORT` | `8080` | Backend listen port |
|
|
| `BASE_PATH` | ` ` | URL prefix (e.g. `/chat`) |
|
|
| `DB_HOST` | `localhost` | PostgreSQL host |
|
|
| `DB_NAME` | `chat_switchboard` | Database name |
|
|
| `JWT_SECRET` | (required) | Token signing key |
|
|
| `SWITCHBOARD_ADMIN_USERNAME` | ` ` | Bootstrap admin username |
|
|
| `SWITCHBOARD_ADMIN_PASSWORD` | ` ` | Bootstrap admin password |
|
|
|
|
## Deployment
|
|
|
|
Three Docker images support different scenarios:
|
|
|
|
| Image | Dockerfile | Use Case |
|
|
|-------|-----------|----------|
|
|
| **Unified** | `Dockerfile` | Dev, docker-compose, single-node |
|
|
| **Backend** | `server/Dockerfile` | K8s — scale API pods independently |
|
|
| **Frontend** | `Dockerfile.frontend` | K8s — scale FE pods independently |
|
|
|
|
### Docker Compose (development — unified image)
|
|
|
|
```bash
|
|
docker compose up -d # start all services
|
|
docker compose up -d --build # rebuild after code changes
|
|
docker compose --profile dev up # include Adminer DB UI
|
|
```
|
|
|
|
### Kubernetes (split images)
|
|
|
|
Build and push both images:
|
|
|
|
```bash
|
|
docker build -f server/Dockerfile -t your-registry/switchboard-api:0.9.1 server/
|
|
docker build -f Dockerfile.frontend -t your-registry/switchboard-fe:0.9.1 .
|
|
```
|
|
|
|
**Backend deployment:**
|
|
|
|
```yaml
|
|
containers:
|
|
- name: api
|
|
image: your-registry/switchboard-api:0.9.1
|
|
ports:
|
|
- containerPort: 8080
|
|
env:
|
|
- name: DB_HOST
|
|
value: "postgres-service"
|
|
- name: BASE_PATH
|
|
value: "/chat" # must match ingress path
|
|
- name: JWT_SECRET
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: switchboard-secrets
|
|
key: jwt-secret
|
|
```
|
|
|
|
**Frontend deployment:**
|
|
|
|
```yaml
|
|
containers:
|
|
- name: frontend
|
|
image: your-registry/switchboard-fe:0.9.1
|
|
ports:
|
|
- containerPort: 80
|
|
env:
|
|
- name: BASE_PATH
|
|
value: "/chat" # injected into index.html at startup
|
|
volumeMounts:
|
|
- name: branding
|
|
mountPath: /branding
|
|
readOnly: true # optional: custom logo, colors
|
|
```
|
|
|
|
**Ingress** routes `/api/*` and `/ws` to the backend Service, everything else to the frontend Service. The frontend entrypoint generates the nginx config dynamically based on `BASE_PATH`.
|
|
|
|
### Path-Based Routing
|
|
|
|
Set `BASE_PATH=/chat` to serve the application under a subpath. The frontend reads `window.__BASE__` injected at container startup, and all API calls are prefixed automatically.
|
|
|
|
### Airgapped / Disconnected
|
|
|
|
The Docker build bakes in `marked.js` and `DOMPurify` from npm during the vendor stage. No CDN calls at runtime. The `src/vendor/` directory contains local copies as fallback for development without Docker.
|
|
|
|
## Database
|
|
|
|
PostgreSQL 16+ required. The `pgcrypto` extension is used for `gen_random_uuid()`.
|
|
|
|
### Schema Management
|
|
|
|
The Go backend auto-migrates on startup using files in `server/database/migrations/`. For manual operations:
|
|
|
|
```bash
|
|
# Bootstrap database (superuser, creates role + DB)
|
|
scripts/db-bootstrap.sh
|
|
|
|
# Manual migration (usually not needed)
|
|
scripts/db-migrate.sh
|
|
|
|
# Validate schema
|
|
scripts/db-validate.sh
|
|
```
|
|
|
|
### Key Tables (v0.9)
|
|
|
|
| Table | Purpose |
|
|
|-------|---------|
|
|
| `users` | Accounts with role, avatar, settings |
|
|
| `provider_configs` | API provider configurations (scope: global/team/personal) |
|
|
| `model_catalog` | Synced model list with capabilities and visibility |
|
|
| `personas` | Model presets (scope: global/team/personal) |
|
|
| `channels` | Conversations with type (direct/group/channel) |
|
|
| `messages` | Message tree with parent_id for forking |
|
|
| `teams` / `team_members` | Organizational units |
|
|
| `notes` | Markdown notes with full-text search |
|
|
| `audit_log` | Admin action audit trail |
|
|
| `user_model_settings` | Per-user model visibility and sort preferences |
|
|
|
|
## API
|
|
|
|
All endpoints under `/api/v1/`. Authentication via `Authorization: Bearer <token>` header.
|
|
|
|
### Auth
|
|
- `POST /auth/register` — Register (if `allow_registration` policy is true)
|
|
- `POST /auth/login` — Login, returns access + refresh tokens
|
|
- `POST /auth/refresh` — Refresh access token
|
|
- `POST /auth/logout` — Revoke refresh token
|
|
|
|
### Channels & Messages
|
|
- `GET/POST /channels` — List/create conversations
|
|
- `GET/PUT/DELETE /channels/:id` — Channel CRUD
|
|
- `GET/POST /channels/:id/messages` — Message list/create
|
|
- `POST /chat/completions` — Stream AI completions (SSE)
|
|
- `POST /channels/:id/messages/:msgId/edit` — Edit and fork
|
|
- `POST /channels/:id/messages/:msgId/regenerate` — Regenerate response
|
|
|
|
### Models
|
|
- `GET /models/enabled` — Models available to the user (global + team + personal)
|
|
- `GET/PUT /models/preferences` — User model visibility settings
|
|
|
|
### Personal Providers (BYOK)
|
|
- `GET/POST /api-configs` — User's personal provider configs
|
|
- `GET/PUT/DELETE /api-configs/:id` — Provider CRUD
|
|
- `POST /api-configs/:id/models/fetch` — Refresh models from provider API
|
|
- `GET /api-configs/:id/models` — List models for a personal provider
|
|
|
|
### Teams
|
|
- `GET /teams` — Teams the user belongs to
|
|
- `GET/POST /teams/:id/providers` — Team provider management (team admins)
|
|
- `GET/POST /teams/:id/presets` — Team preset management (team admins)
|
|
|
|
### Admin
|
|
- `GET/POST /admin/users` — User management
|
|
- `GET/PUT /admin/settings/:key` — Global settings and policies
|
|
- `GET/POST /admin/configs` — Global provider configs
|
|
- `GET/POST /admin/models/fetch` — Model catalog sync
|
|
- `GET /admin/audit` — Audit log
|
|
|
|
## Development
|
|
|
|
```bash
|
|
# Backend (requires Go 1.22+)
|
|
cd server
|
|
cp .env.example .env # edit with your DB credentials
|
|
go run .
|
|
|
|
# Frontend (just serve static files)
|
|
# Use any HTTP server pointed at src/
|
|
python3 -m http.server 3000 --directory src
|
|
```
|
|
|
|
## License
|
|
|
|
Proprietary. All rights reserved.
|