Skip to content

Repository files navigation

Agent Chat

A production-grade, multi-tenant AI chat assistant SaaS. Users sign in, chat with a tool-calling agent, watch responses stream in real time, and track their usage on a dashboard — with free AI models enabled out of the box.

  • Real-time streaming — replies stream token-by-token over Server-Sent Events (SSE).
  • Tool-calling agent — a LangGraph createReactAgent that uses real tools (calculator, web search) with a forced tool loop.
  • Queue-backed runs — messages are enqueued to BullMQ/Redis and processed by a separate worker, so the API never blocks.
  • Per-user usage tracking — token counts and estimated cost attributed to every account.
  • Multi-tenant auth — Better Auth (email/password) with fully isolated per-user data.
  • Conversation management — modify, rename, and delete conversations inline.
  • Public site — landing page plus Privacy Policy and Terms of Service.

Architecture

┌────────────┐    /api (REST, SSE)    ┌─────────────┐    BullMQ    ┌──────────────┐
│ React app  │ ◄────────────────────► │ Express API │ ───────────► │ BullMQ worker│
│ (Vite)     │                        │  (port 4000)│ ◄─────────── │  (LangGraph) │
└────────────┘                        └──────┬──────┘  +events    └──────┬───────┘
                                             │                           │
                                             ▼                           ▼
                                        PostgreSQL                     Redis (6389)
                                    (users, conversations,          (queue + pub/sub
                                     messages, runs, usage)          brokers SSE events)

Stack

  • Client: React 18, Vite, TypeScript, Redux Toolkit, TanStack Query, react-router-dom, Tailwind CSS
  • API: Express 4, better-auth, pino-http, Prisma
  • Agent: LangGraph createReactAgent, @langchain/openai, Zod tool schemas
  • Queue: BullMQ + Redis (also used as the SSE pub/sub transport)
  • Models: OpenRouter (OpenAI-compatible endpoint) with free-tier model support

Repository layout

apps/
  client/   # React SPA (chat UI, dashboard, landing, legal pages)
  server/   # Express API (REST + SSE)
  worker/   # BullMQ consumer that runs the LangGraph agent
packages/
  agent/    # model wiring, tools, runAgent() graph orchestration
  config/   # shared env loading (dotenv)
  db/       # Prisma schema + client
  queue/    # BullMQ queue + worker definitions
  shared/   # shared TS types (AgentEvent, ChatMessage, RunSummary)

Prerequisites

  • Node.js 20+ (developed on 24)
  • pnpm (corepack enable or npm i -g pnpm)
  • A PostgreSQL instance on localhost:5432 (default connection: fsa/fsa, database fsa)
  • Redis on localhost:6389 (the included docker-compose.yml provides exactly this)

Getting started

# 1. Install dependencies
pnpm install

# 2. Configure environment
cp .env.example .env        # then fill in OPENROUTER_API_KEY (and AUTH_SECRET in production)

# 3. Start Postgres + Redis (Redis via Docker)
#    Postgres: your local install must be running on 5432
docker compose up -d redis

# 4. Generate the Prisma client and run migrations
pnpm db:generate
pnpm db:migrate             # applies schema migrations to your local Postgres

# 5. Run everything (API, worker, client with HMR)
pnpm dev

# 6. Open http://localhost:5173

Sign up for an account, or press Use demo account on the login screen (demo@test.com / password123).

Running individual services

pnpm dev:api      # API only (http://localhost:4000)
pnpm dev:worker   # agent worker only
pnpm dev:client   # Vite dev server (http://localhost:5173)

Environment variables

Variable Description
PORT API port (default 4000)
CLIENT_URL Allowed client origin for auth/SSE (default http://localhost:5173)
DATABASE_URL Prisma Postgres connection string
REDIS_URL Redis connection string (default redis://localhost:6389)
AUTH_SECRET Better Auth session secret — generate with openssl rand -base64 32
OPENROUTER_API_KEY OpenRouter API key (required for free-tier models)
AGENT_MODEL Model id, e.g. nex-agi/nex-n2.5-pro:free (see below)
OPENAI_BASE_URL OpenAI-compatible base URL (OpenRouter's API by default)
OPENAI_API_KEY Optional — direct-OpenAI fallback if no OpenRouter key

Model selection & determinism

The agent runs the model with temperature: 0 and a fixed seed: 42, and AGENT_MODEL is pinned to a specific model (nex-agi/nex-n2.5-pro:free by default). This keeps runs reproducible: the same prompt returns the same tool calls and the same answer.

If you hit rate limits on the free tier, set AGENT_MODEL=openrouter/free instead — OpenRouter automatically routes to whichever free model is available. You trade strict reproducibility for availability.

How a message flows

  1. Client POST /api/conversations/:id/messages → API saves the message, creates a run (queued), and enqueues a BullMQ job. Returns 202 + runId.
  2. Worker picks up the job, marks the run running, and streams the LangGraph agent (streamMode: ["updates", "messages"]).
  3. Every event (tokens, tool calls, tool results, completion) is published to a Redis pub/sub channel; the API relays them to the browser via the SSE GET /api/events stream.
  4. On completion the worker records token usage (cost $0 for free-tier models) and the client invalidates its queries so history and the dashboard stay in sync.

npm scripts

Script Description
pnpm dev API + worker + client (parallel, HMR)
pnpm build Build all workspace packages
pnpm typecheck Type-check all workspace packages
pnpm db:generate Regenerate the Prisma client
pnpm db:migrate Apply Prisma migrations to Postgres
pnpm db:studio Open Prisma Studio

License

MIT — see LICENSE.

About

Multi-tenant AI chat SaaS: React client, Express API, LangGraph agent (OpenRouter free models), BullMQ queue with Redis, and real-time SSE token streaming. Track usage per user on a live dashboard. (or a more compact version: "Multi-tenant AI chat SaaS powered by LangGraph + BullMQ with SSE streaming, usage billing, and a React dashboard.")

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages