* Add user identity, JWT auth, and admin console UI (#23) JWT-based authentication with three token types: config-file (hmac, backward-compat), API tokens (ts_ prefix, SHA-256 hashed), and JWTs (HS256, 24h expiry). Username:password login via bcrypt. Hierarchical scopes: read < write < approve. New tables: users (username, password_hash), api_tokens (token_hash, scopes, expires), channel_users (future channel integrations). user_id column added to sessions and workstreams for attribution. Console owns admin CRUD (6 endpoints under /api/admin/). Server validates JWTs locally with shared signing secret. Public /api/auth/setup endpoint for first-time admin creation (atomic, only works with zero users). turnstone-admin CLI for user/token management. Admin console UI: Users and Tokens tabs with full CRUD modals, scope badges, token show-once with clipboard copy, keyboard accessibility (focus traps, Escape, arrow key tabs, ARIA roles). Login UI redesigned: username:password primary, token toggle for legacy, setup wizard auto-detected via /api/auth/status. Python + TypeScript SDKs updated with login(username, password), authStatus(), setup(). New docs/security.md + diagram 15-auth-architecture.puml. All existing docs updated. OpenAPI specs include all new endpoints. 64 new tests (1023 total). Dependencies: PyJWT, bcrypt. * Fix auth bugs, XSS vector, and doc inaccuracies from PR #23 review Address Copilot review feedback: escape double quotes in escapeHtml() to prevent XSS in HTML attributes, add JWT validation fallback so config tokens containing dots still work, add user_id to AuthLoginResponse schema, return created field from admin_create_user, and correct five documentation files to match actual API behavior.
5.1 KiB
Docker Deployment
Docker Compose stack for running the full turnstone platform or the simulator.
Quick Start
# Copy and edit environment config
cp .env.example .env
# Full stack (needs an LLM API on the host)
docker compose up
# Simulator only (no LLM needed)
docker compose --profile sim up redis console sim
Console dashboard: http://localhost:8090
See also: Deployment diagram
Services
| Service | Port | Profile | Description |
|---|---|---|---|
redis |
6379 | default | Message broker, pub/sub, node registry |
server |
8080 | default | Web UI + chat workstreams + LLM |
bridge |
— | default | Redis-to-HTTP bridge (multi-node routing) |
console |
8090 | default | Cluster dashboard |
sim |
— | sim | Multi-node cluster simulator |
Profiles
Default (no flag) — starts redis, server, bridge, console. Requires an OpenAI-compatible LLM API running on the host (default: http://localhost:8000/v1).
docker compose up
Sim — adds the simulator. Can run alongside the full stack or standalone with just Redis and the console:
# Sim + console (no LLM needed)
docker compose --profile sim up redis console sim
# Everything including sim
docker compose --profile sim up
Configuration
All configuration is via environment variables in .env (copy from .env.example):
LLM Backend
| Variable | Default | Description |
|---|---|---|
LLM_BASE_URL |
http://host.docker.internal:8000/v1 |
OpenAI-compatible API URL |
OPENAI_API_KEY |
dummy |
API key (dummy for local servers) |
TAVILY_API_KEY |
— | Web search API key (only needed for local/vLLM models; Anthropic and OpenAI search models use native search) |
Redis
| Variable | Default | Description |
|---|---|---|
REDIS_PASSWORD |
— | Redis auth password (empty = no auth) |
REDIS_PORT |
6379 |
Host port mapping |
Server
| Variable | Default | Description |
|---|---|---|
SERVER_PORT |
8080 |
Host port mapping |
SKIP_PERMISSIONS |
— | Set to any value to auto-approve all tools |
Console
| Variable | Default | Description |
|---|---|---|
CONSOLE_PORT |
8090 |
Host port mapping |
CONSOLE_POLL_INTERVAL |
10 |
Node polling interval (seconds) |
Auth
| Variable | Default | Description |
|---|---|---|
TURNSTONE_AUTH_ENABLED |
— | Set to 1 to require authentication |
TURNSTONE_AUTH_TOKEN |
— | Config-file token for server/bridge/console (backward compat, works alongside JWT) |
TURNSTONE_JWT_SECRET |
— | Secret key for signing JWTs (required when using user identity / JWT auth) |
Database
| Variable | Default | Description |
|---|---|---|
TURNSTONE_DB_BACKEND |
sqlite |
Storage backend: sqlite or postgresql |
TURNSTONE_DB_URL |
— | Database URL (e.g. postgresql://user:pass@db:5432/turnstone). For SQLite, defaults to /data/.turnstone.db |
The database stores workstream history, user accounts, and API tokens. When using JWT auth, a database backend is required for user storage.
First-time setup: After deploying with auth enabled, create an initial admin user by running
turnstone-admin create-userinside the container:docker compose exec server turnstone-admin create-user --username admin --name "Admin"You will be prompted to set a password. Use it to log in via the UI or SDK, then create additional users through the admin API. Pass
--token --scopes read,write,approveto also generate an initial API token.
Simulator
| Variable | Default | Description |
|---|---|---|
SIM_NODES |
100 |
Number of simulated nodes |
SIM_SCENARIO |
steady |
Scenario: steady, burst, node_failure, directed, lifecycle |
SIM_DURATION |
60 |
Duration in seconds |
SIM_MPS |
5.0 |
Messages per second (steady scenario) |
SIM_LOG_LEVEL |
INFO |
Log verbosity |
SIM_SEED |
— | Random seed for reproducibility |
SIM_METRICS_FILE |
— | Write JSON report to file |
Scaling
Scale to multiple server/bridge pairs:
docker compose up --scale server=3 --scale bridge=3
Each bridge auto-generates a unique node ID from its container hostname. When scaling server, remove the host port mapping (or use a reverse proxy) to avoid port conflicts.
Volumes
| Volume | Mount | Purpose |
|---|---|---|
redis-data |
/data |
Redis persistence |
turnstone-data |
/data |
SQLite database (.turnstone.db) |
Building
The image uses a multi-stage Dockerfile:
# Build all services
docker compose build
# Rebuild without cache
docker compose build --no-cache
All five entry points are installed in a single image: turnstone-server, turnstone-bridge, turnstone-console, turnstone-sim, turnstone-eval.
Cleanup
# Stop and remove containers
docker compose down
# Stop, remove containers and volumes
docker compose down -v