SPB Git

spb/chat-spboucher Public

Private universal chat interface over the OpenRouter ecosystem — 400+ models, branching, streaming, usage tracking. Next.js 16 + SQLite, PWA, deployed on m4m64a at chat.spboucher.ai

TypeScript 78.8% CSS 15.1% JavaScript 4.9% Shell 1.2%
4.8 KB

# chat.spboucher.ai

Status Models Next.js TypeScript SQLite Gateway PWA Node License

Author: Simon-Pierre Boucher Contact: contact@spboucher.ai Production: https://chat.spboucher.ai

A private, universal chat interface over the entire OpenRouter ecosystem — one login, one server-side API key, 400+ models behind a single catalog, full conversation persistence with branching and per-message model attribution. Designed mobile-first as an installable PWA: a personal ChatGPT/Claude-class product, not an API demo.


# Highlights

  • One gateway, hundreds of models — the catalog is synced dynamically from OpenRouter into SQLite (never hand-maintained); removed models are marked Unavailable, historical conversations stay intact forever.
  • Real streaming — normalized SSE event protocol (generation.start, content.delta, reasoning.delta, usage, …) with 15 s keep-alive pings that survive ngrok and mobile radio sleep. Stop truly aborts the upstream OpenRouter stream.
  • Branching & regeneration — regenerating never destroys an answer; siblings live side by side with ‹ 1/2 › navigation, so the same prompt can be compared across models.
  • Generation state machinequeued → starting → streaming → completed | cancelled | failed, persisted per generation; a dropped mobile connection resyncs from the server.
  • Usage & cost tracking — prompt/completion/reasoning/cached tokens and reported cost per generation, with a Today / 7d / 30d / All-time dashboard broken down by model.
  • Instrument Panel design — ink/graphite surfaces, one teal accent for "alive", one amber accent for "cost", mono type for model IDs and meters, and the signature Model Rail cartridge attached to the composer (provider glyph · mono model ID · live context meter · price-per-1M chip).
  • Security posture for a public tunnel — argon2id single-user auth, DB-backed sessions, aggressive login rate limiting, Secure/HttpOnly/SameSite cookies, CSP + security headers, zero unauthenticated API surface.

# Architecture

text
Browser (phone or desktop, PWA)
   │  POST /api/chat  (SSE)

Next.js 16 backend — node m4m64a (Apple Silicon, macOS)
   │  src/lib/openrouter/  (single client module, normalized errors/streaming)

OpenRouter API ──► Anthropic · OpenAI · Google · Meta · Qwen · DeepSeek · Mistral · …
  • Runtime: single Node.js process (API + UI), port 3000, exposed via ngrok at chat.spboucher.ai
  • Database: SQLite (better-sqlite3, WAL) — conversations, message tree, generations, usage, model catalog cache, sessions
  • Supervision: three launchd agents (app, ngrok, nightly backup at 03:30 with 14-day retention)

# Local development

bash
cp .env.example .env                          # fill in OPENROUTER_API_KEY
npm install
npm run set-password <username> [password]    # generates a strong one if omitted
npm run dev

# Deployment (m4m64a)

bash
rsync -az --delete --exclude node_modules --exclude .next --exclude data --exclude .env \
  ~/Desktop/chat-spboucher/ M4M64a:apps/chat.spboucher.ai/
ssh M4M64a '~/apps/chat.spboucher.ai/ops/deploy.sh'
launchd agent Role
ai.spboucher.chat.app npm run start on port 3000, KeepAlive
ai.spboucher.chat.ngrok ngrok http --url=chat.spboucher.ai 3000, KeepAlive
ai.spboucher.chat.backup nightly SQLite backup 03:30, 14-day retention

# API surface

All routes require a session cookie except POST /api/auth/login.

Endpoint Purpose
POST /api/chat send a message or regenerate ({regenerateOf}) — returns a normalized SSE stream
POST /api/generations/:id/cancel abort the upstream OpenRouter generation
GET /api/models · POST /api/models/sync cached catalog · manual refresh
POST /api/models/prefs favorites / pinned models
GET/PATCH/DELETE /api/conversations[/:id] conversation CRUD, branch leaf selection
GET /api/usage?period=today|7d|30d|all usage & cost dashboard data

# License

Private software — © Simon-Pierre Boucher. All rights reserved.


Simon-Pierre Boucher · contact@spboucher.ai · chat.spboucher.ai