Cost-aware LLM gateway with a React chat UI. A Go proxy authenticates users (OAuth2 / JWT cookie), routes prompts by budget + complexity, and streams responses over SSE from OpenAI, Anthropic, Gemini, or Perplexity.
Provider API keys stay on the server. End users never paste them into the UI.
| Epic | Focus | Status |
|---|---|---|
| 1 Identity & profiles | Google/GitHub OAuth, JWT HttpOnly cookie, user config API + settings UI |
Done (mock auth when IdP unset) |
| 2 Proxy & persistence | SQLite / PostgreSQL store, multi-provider SSE (incl. Perplexity) | Done |
| 3 Routing engine | Sliding 24h budget throttle, preferred models, cost deltas, semantic classifier | Done |
| 4 Frontend | Chat UI, metrics panel, sessions, usage on load, SSE auto-retry, logout | Done |
Remaining work is tracked in BACKLOG.md. Local runbook: quick_start.md. Production ops: docs/ops.md. Deploy samples: deploy/.
| Layer | Technology |
|---|---|
| Frontend | React + TypeScript + Vite (frontend/) |
| Backend | Go (cmd/server, internal/) |
| Persistence | SQLite by default; PostgreSQL when DATABASE_URL is set |
| Streaming | SSE on POST /api/v1/chat/stream |
Browser (Vite :5173)
└─ /api/* proxied ──► Go server (:8080)
├─ auth (OAuth2 + JWT cookie)
├─ user config / usage / sessions
├─ router (simple / advanced)
├─ proxy (OpenAI / Anthropic / Gemini / Perplexity / mock)
└─ store (SQLite | Postgres | memory tests)
- Identity: Google or GitHub OAuth when client credentials are configured.
- Local/dev: mock auth when IdP credentials are unset (
ALLOW_MOCK_AUTHdefaults on in development). - Session: JWT in
session_tokencookie (HttpOnly;Securein production;SameSiteviaCOOKIE_SAMESITE). - Provider keys: server env only. Missing keys mock in development; fail loud when
ALLOW_MOCK_PROVIDERS=falseorAPP_ENV=production.
db.NewStoreFromEnv() selects SQLite (DATABASE_PATH) or PostgreSQL (DATABASE_URL).
- Trailing 24h budget throttle at ≥85% of cap
- Simple mode → low-cost preferred models
- Advanced mode →
semantic_heuristic_v2+ preferred premium/low-cost + cost delta
| Event | Purpose |
|---|---|
metrics |
Selected model, rationale, cost delta, budget flag |
text |
Streaming text_delta chunks |
final_usage |
Input/output tokens + updated trailing-24h total |
error |
Provider/config failure |
| Method | Path | Auth | Notes |
|---|---|---|---|
| GET | /api/v1/auth/login?provider=google|github |
No | Returns IdP URL or mock URL |
| GET | /api/v1/auth/login?intent=status |
No | Available providers (no side effects) |
| GET/POST | /api/v1/auth/callback |
No | Code exchange; sets cookie |
| GET | /api/v1/auth/me |
Yes | Current user config |
| POST | /api/v1/auth/logout |
No | Clears session cookie |
| GET/PUT | /api/v1/user/config |
Yes | Daily cap, strategy, preferred models |
| GET | /api/v1/user/usage |
Yes | Trailing 24h token usage vs cap |
| GET | /api/v1/sessions |
Yes | List user sessions |
| GET | /api/v1/sessions/{id}/messages |
Yes | Restore session history |
| POST | /api/v1/chat/stream |
Yes | SSE chat stream |
git clone https://github.com/Senthilsivam41/camper-vane.git
cd camper-vane
git checkout main # or: git checkout v0.1.0
go mod tidy && go test ./...
go run ./cmd/server/main.go
npm --prefix frontend install
npm --prefix frontend run devOpen http://localhost:5173. Use Continue with local mock auth when OAuth client IDs are not set.
Same-origin Docker path: docker compose up --build → http://localhost/.
See quick_start.md and docs/ops.md.
-
/api/v1/auth/callbackhandles token exchange (real IdP or mock) - Session token stored via
HttpOnlycookie (Securein production) - First-time login provisions default profile + daily token cap
-
PUT /api/v1/user/configendpoint - Validation rejects negative caps / invalid strategies
- Frontend settings UI saves with confirmation
-
UserRepository/SessionRepository(+Store) with SQLite + Memory contract tests - Env-driven init (
DATABASE_PATH/DATABASE_URL) - Versioned schema migrations without dropping chat context
- PostgreSQL implementation via
NewStoreFromEnv()
- JSON request → isolated provider client call
- Streaming parsers for OpenAI, Anthropic, Gemini, Perplexity
- Structured
event: text(plusmetrics/final_usage/error) to the frontend
- Every prompt checks trailing-24h usage
- ≥85% of cap forces low-cost preferred model
-
budget_throttledflag inmetricsevent
-
semantic_heuristic_v2analytics module (centroids + structural signals) - High-complexity prompts route to premium preferred models
- Session history hydration influences scoring / topic continuity
- Active model badge (provider-colored)
- Trailing-24h usage gauge (loads on open via
/user/usage) - Optimization rationale + cost delta from SSE
metrics
- Sequential event parsing without dropped deltas
- Branches on
metrics/text/final_usage/error - Auto-retry with backoff on transient disconnects
See repository for license terms.