Unified server

bun start (or bun dev for watch mode) launches a single Bun HTTP server on PORT (default 4242) that hosts every network-facing interface in this repo.

Routes

Path Owner Purpose
GET / Bun Landing page listing every interface
GET /health Bun { ok, name, version, uptimeSeconds } (also accepts /healthz as a quiet alias for backward compat - some Google front-ends reserve /healthz)
* /mcp Bun Streamable HTTP MCP transport - same tools as bun mcp
* /api/* Bun Booking API (api.md)
POST /slack/events Bun Slack Events webhook (slack.md)
* /dobby-browser-extension.zip Bun (static) Chrome extension download (extension.md)
* /favicon.*, /site.webmanifest, etc. Bun (static) Anything in ./public/
* everything else Next Forwarded to the Next.js subprocess (UI at /ui)

Bun-owned routes always work. The Next.js subprocess is best-effort: if it fails to spawn, crashes, or has never been built, the proxy returns a clean 503 on /ui while the rest of the server keeps responding.

Subprocess strategy (src/server/next/proxy/lifecycle.ts)

On startup the proxy probes DOBBY_NEXT_PORT (default 4243):

  1. If something already responds, reuse it. Useful in dev - run bun next:dev -p 4243 separately and the unified server picks it up so HMR works against the dev server directly.
  2. Otherwise, spawn .next/standalone/server.js.
  3. If neither path works, set status to failed and let /ui return 503.

WebSocket upgrades are not forwarded (Next dev's HMR doesn't survive the proxy). Hit localhost:3000/ui directly when iterating on the UI.

Environment

Var Default Used by
PORT 4242 Bun listener
DOBBY_PUBLIC_URL https://dobby.diegoalto.app Canonical public URL; surfaced in docs as $DOBBY_PUBLIC_URL/mcp
DOBBY_NEXT_PORT 4243 Internal Next.js port
DOBBY_NEXT_READINESS_TIMEOUT_MS 60000 How long the proxy waits for Next to bind on startup; raise for slow cold-starts
SLACK_BOT_TOKEN (none) Slack bot, optional
SLACK_SIGNING_SECRET (none) Slack request verification, optional
DOBBY_DB_PATH ~/.booking-bot/dobby.sqlite SQLite job store for Slack-triggered jobs + LLM usage
DOBBY_LLM_ENABLED true Set false to disable the natural-language fallback
DOBBY_LLM_PROVIDER anthropic anthropic or openai
DOBBY_LLM_MODEL provider default Override e.g. claude-sonnet-4-6 or gpt-4o
DOBBY_LLM_DAILY_BUDGET_USD 5 Daily cost cap; new requests refused once spent
ANTHROPIC_API_KEY (none) Required when DOBBY_LLM_PROVIDER=anthropic
OPENAI_API_KEY (none) Required when DOBBY_LLM_PROVIDER=openai
SHOPPER_EMAIL dobby@testing.eurostar.com Set by the server before any env-loader

See .env.sample for the full set used by the booking pipeline.