Skip to content

Repository files navigation

OyeChats

A SaaS chatbot platform: customers sign up, create chatbot instances, upload a knowledge base, and embed a RAG-powered chatbot on their website with one <script> tag. Includes live-chat handoff to human operators, BANT/MEDDIC lead qualification, and a Razorpay billing system (INR, single rail).

Modules

Module Stack Purpose
api/ FastAPI · SQLAlchemy 2.0 · pgvector · LiteLLM · ARQ REST + SSE + WebSocket; RAG pipeline; auth; ingestion; billing
widget/ React 19 · Vite 7 · Tailwind v4 Embeddable chat widget: a ~3KB loader IIFE (oyechats-widget.js) plus code-split ESM chunks it lazy-loads into a shadow root
app/ React 19 · Vite 8 · React Router 7 · Recharts Admin dashboard (bot config, KB, leads, billing, operator console)

The marketing site lives in a separate sibling repo (oyechats-website/, Next.js 16) and is not part of this monorepo.

Prerequisites

  • Python 3.11 (pinned in api/.python-version)
  • Node.js 20+ and npm
  • PostgreSQL 16+ with the pgvector extension
  • Redis 7+ (queue · cache · rate-limit; required in production, optional in dev)
  • uv — Python dependency manager — install
  • conda — optional, for local Python isolation only. Production runs Python under systemd directly; there is no conda env on the server.

Quick start

Option 1 — Docker (recommended)

Brings up Postgres + pgvector and the FastAPI backend in containers.

git clone <repo-url> && cd platform
cp api/.env.example api/.env       # edit at minimum: OPENAI_API_KEY, GOOGLE_API_KEY
docker compose up --build
Service URL
Backend API http://localhost:8000
Swagger UI http://localhost:8000/docs
Postgres localhost:5432 (db oyechats, user oyechats)

Option 2 — Native (conda + uv)

conda is a local-development convenience. Production uses systemd directly.

# 1. Python env
conda create -n oye python=3.11 -y
conda activate oye
pip install uv          # or: curl -LsSf https://astral.sh/uv/install.sh | sh

# 2. Configure
cp api/.env.example api/.env
# Edit api/.env — see "Environment variables" below

# 3. Install backend deps
cd api
uv sync

# 4. Database
createdb oyechats         # ensure pgvector extension is installed
uv run alembic upgrade head

# 5. Run dev server
uv run uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload

Frontends

# Chat widget (host-page-embeddable IIFE)
cd widget && npm install && npm run dev      # http://localhost:5173

# Admin dashboard (SPA)
cd app && npm install && npm run dev          # http://localhost:5174

The Vite dev server on port 5173 cannot be embedded on external sites because of the React Fast Refresh preamble. To test embedding, run npm run build && npx vite preview --port 4173 in widget/.

Environment variables

Create api/.env from api/.env.example. The full list with defaults lives in api/app/config.py; the most important ones:

Required

Variable Description
DB_URL Postgres connection string (postgresql://oyechats:oyechats@localhost:5432/oyechats)
APP_ENV development, testing, or production
OPENAI_API_KEY OpenAI key — primary chat completions (gpt-5.4-mini) and the moderation pre-check
GOOGLE_API_KEY Google Gemini key — embeddings (gemini-embedding-001), the fallback chat model, and the gate / enrichment LLM

Required in production

Variable Description
REDIS_URL Redis connection string (queue · cache · rate-limit). App fails fast on startup without it in production.
CORS_ORIGINS Comma-separated allowlist (no wildcard with credentials)
R2_KEY_ID, R2_APPLICATION_KEY, R2_BUCKET_NAME, R2_ENDPOINT Cloudflare R2 (S3-compatible) for file storage. Legacy B2_* env names are accepted as fallbacks.
BREVO_API_KEY Transactional email
RAZORPAY_KEY_ID, RAZORPAY_KEY_SECRET, RAZORPAY_WEBHOOK_SECRET Payment provider (INR) — the sole rail. BILLING_PROVIDER defaults to razorpay; there is no billing_service.py and no Stripe service module, only vestigial stripe_* columns on plans.
SENTRY_DSN_BACKEND Error tracking

Tunable feature flags

Variable Default Effect
LLM_MODEL openai/gpt-5.4-mini Primary chat model (LiteLLM identifier)
FALLBACK_MODEL gemini/gemini-2.5-flash Auto-fallback chain
GEMINI_EMBED_MODEL gemini-embedding-001 Google embedding, Matryoshka-truncated to 768-dim (EMBED_DIMENSIONS)
CHUNK_SIZE / CHUNK_OVERLAP 1000 / 200 Document chunking
CRAWL_PROVIDER_PRIMARY jina Which scrape backend page fetches try first; the other becomes the fallback
MODERATION_ENABLED true OpenAI moderation pre-check
CAG_LITE_THRESHOLD 20 Skip retrieval for bots with ≤ N chunks
RELEVANCE_GATE_ENABLED true CRAG-style relevance scoring — the control behind "answers only from your knowledge base". An empty value counts as unset (relevance_gate.py:63); see deploy-api.yml's ${VAR:-true}.
RERANK_ENABLED false FlashRank cross-encoder rerank
WORKER_ENABLED true If false, worker tasks fall back to in-process thread pool
LANGFUSE_FORCE_DISABLE Escape hatch for low-memory hosts

Full reference: docs/configuration.md and the system-design environments page.

Common commands

Backend

# All commands assume conda env `oye` is active and cwd is api/
uv sync                                                 # install / sync deps
uv run uvicorn app.main:app --reload --port 8000        # dev server
uv run pytest                                           # tests
uv run ruff check .                                     # lint
uv run ruff format .                                    # format
uv run alembic upgrade head                             # run migrations
uv run alembic revision --autogenerate -m "<message>"   # new migration

Frontends

cd widget && npm run lint && npm test && npm run build          # widget
cd app && npm run lint && npx tsc --noEmit && npx vitest run && npm run build   # admin

app/ is TypeScript, and npm run build does not typecheck — tsc --noEmit is a separate, required gate. See CLAUDE.md.

Docker

docker compose up --build         # full stack
docker compose up db -d            # database only
docker compose down                 # stop (preserves volume)
docker compose down -v              # stop + delete data volume

API surface

Once the backend is running:

Routers (each is mounted at the root, no /api prefix):

Prefix File Purpose
/auth/* api/app/api/auth_routes.py Register, login, OTP password reset
/bots/* api/app/api/bot_routes.py Bot CRUD, public widget settings
/chat/* api/app/api/chat_routes.py SSE chat stream, history, feedback
/ws/* api/app/api/ws_routes.py WebSocket live-chat
/documents/* api/app/api/document_routes.py Upload, crawl, list, delete
/leads/* api/app/api/lead_routes.py Leads, BANT signals, qualification config
/operators/* api/app/api/operator_routes.py Operator CRUD, handoff, assignment
/canned-responses/* api/app/api/canned_response_routes.py Snippet CRUD
/offline-messages/* api/app/api/offline_message_routes.py Offline form submissions
/analytics/* api/app/api/analytics_routes.py Dashboard metrics
/subscriptions/*, /credits/* api/app/api/subscription_routes.py Plans, invoices, top-ups
/webhooks/* api/app/api/webhook_routes.py Customer webhook registrations
/webhooks/billing/* api/app/api/webhook_billing_routes.py Inbound Razorpay webhooks
/superadmin/* api/app/api/superadmin_routes.py + superadmin_routes_v2.py, superadmin_plan_routes.py, superadmin_promotion_routes.py, superadmin_ops_routes.py Super-admin only
/client/* api/app/api/client_routes.py Client account settings
/quotation/* api/app/api/quotation_routes.py Widget quotation flow
/affiliates/* api/app/api/affiliate_routes.py Affiliate / referral program

This table is a selection. api/app/api/ holds 32 route modules and main.py mounts 36 routers; read main.py for the complete wiring.

Tests

cd api
uv run pytest                       # all
uv run pytest tests/test_chat_security.py
uv run pytest -v                    # verbose

Embedding the widget

cd widget && npm run build          # → dist/oyechats-widget.js + dist/app/*
<script src="https://cdn.oyechats.com/oyechats-widget.js" data-bot-key="bot-xxx"></script>

The widget reads data-bot-key from its own <script> tag, mounts a <div id="oyechats-widget-root">, and lazy-loads its React bundle. See widget/README.md for the loader/chunk strategy.

Project structure

platform/
├── api/                              # FastAPI + ARQ + RAG
│   ├── app/
│   │   ├── main.py                   # entry · middleware · router wiring
│   │   ├── config.py                 # env-driven settings
│   │   ├── api/                      # route modules (32 files, 36 mounted routers)
│   │   │   ├── auth.py               # auth dependencies (get_current_*)
│   │   │   ├── auth_routes.py        # register · login · OTP reset
│   │   │   ├── bot_routes.py         # bot CRUD
│   │   │   ├── chat_routes.py        # SSE chat stream
│   │   │   ├── ws_routes.py          # WebSocket live-chat
│   │   │   ├── document_routes.py    # upload + crawl
│   │   │   ├── lead_routes.py        # leads + BANT
│   │   │   ├── operator_routes.py    # live-chat staff
│   │   │   ├── subscription_routes.py # plans + credits + top-ups
│   │   │   ├── webhook_routes.py     # customer webhook regs
│   │   │   ├── webhook_billing_routes.py # inbound Razorpay
│   │   │   └── …
│   │   ├── services/                 # business logic
│   │   │   ├── rag_service.py        # hybrid search + context assembly
│   │   │   ├── llm_service.py        # LiteLLM wrapper (OpenAI → Gemini)
│   │   │   ├── live_chat_service.py  # WebSocket ConnectionManager
│   │   │   ├── razorpay_service.py   # Razorpay (sole payment rail)
│   │   │   ├── credit_service.py     # FIFO credit ledger
│   │   │   ├── qualification_service.py # BANT / MEDDIC
│   │   │   ├── lead_service.py       # tier transitions + decay
│   │   │   ├── webhook_service.py    # outbound HMAC + retry
│   │   │   ├── email_service.py      # Brevo
│   │   │   ├── crawl_orchestrator.py # crawl waves + streaming ingest
│   │   │   ├── jina_service.py       # Jina Reader (primary crawl provider)
│   │   │   ├── spider_service.py     # Spider.cloud (fallback)
│   │   │   ├── ws_backplane.py       # Redis pub/sub for cross-process live chat
│   │   │   ├── intent_service.py     # intent routing
│   │   │   ├── relevance_gate.py     # CRAG-style gate
│   │   │   ├── reranker.py           # FlashRank
│   │   │   └── r2_service.py         # Cloudflare R2 (S3-compat)
│   │   ├── ingestion/                # RAG input pipeline
│   │   │   ├── pipeline.py           # orchestrator
│   │   │   ├── extraction.py         # pypdf · python-docx · text
│   │   │   ├── cleaner.py
│   │   │   ├── chunking.py           # recursive splitter
│   │   │   ├── embedder.py           # Gemini gemini-embedding-001 (768-dim)
│   │   │   └── enrichment.py         # optional Gemini chunk-summary
│   │   ├── worker/                   # ARQ tasks
│   │   ├── db/                       # models · session · repository
│   │   ├── core/                     # middleware · security · thread-pool
│   │   └── schemas/                  # Pydantic v2
│   ├── alembic/                      # migrations
│   ├── tests/
│   ├── systemd/                      # production unit files
│   ├── nginx/                        # production nginx config
│   └── scripts/                      # backup.sh, seed scripts
├── widget/                           # embeddable IIFE
├── app/                              # admin dashboard SPA
├── docs/                             # markdown + interactive system-design site
│   └── system-design/                # VitePress site (28+ pages, 44+ diagrams)
├── docker-compose.yml                # local dev stack
├── CLAUDE.md                         # AI-assistant conventions
└── README.md                         # this file

Tech stack

Layer Technology
LLM (primary) OpenAI gpt-5.4-mini via LiteLLM
LLM (fallback) Google gemini-2.5-flash
Embeddings Google gemini-embedding-001 (768-dim, L2-normalized)
Vector DB PostgreSQL 16 + pgvector (hybrid search with TSVECTOR keyword)
Backend FastAPI · SQLAlchemy 2.0 · Alembic · Pydantic v2
Background queue ARQ on Redis
Frontend React 19 · Vite 7/8 · Tailwind v4 · React Router 7
Web crawl Jina Reader (primary) + Spider.cloud (fallback) — HTTP only, no local browser
File storage Cloudflare R2 (S3-compatible)
Email Brevo
Payments Razorpay (INR) — single provider
Real-time WebSocket (ws_routes.py)
Rate limiting SlowAPI on Redis
Observability Sentry · Langfuse (enabled whenever both keys are set; LANGFUSE_FORCE_DISABLE=true is the kill switch)
CDN Cloudflare R2 + CDN — cdn.oyechats.com/oyechats-widget.js
Deploy DigitalOcean droplet · systemd · Nginx · GitHub Actions (ci.yml, deploy-api.yml, deploy-widget.yml, deploy-app.yml)
Dependency mgmt uv (Python) + npm (JavaScript)
Containerisation Docker + Docker Compose (local dev only)

Documentation

  • CLAUDE.md — engineering conventions and AI-assistant guide
  • docs/ — markdown reference (architecture, configuration, RAG pipeline, runbooks)
  • docs/system-design/ — VitePress site with C4 diagrams, critical-flow sequence diagrams, ER diagrams, and deployment topology. Run locally:
    cd docs/system-design && npm install && npm run dev

Contributing

The git repo is digibranders/oye-chats-platform on GitHub. All work happens on the development branch; production is main and updates only via PR merge. See CLAUDE.md for the full workflow and pre-commit checks (ruff, pytest, npm run lint, npm run build).

About

OyeChats Platform

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages