- Project Overview
- Architecture
- Technology Stack
- Complete Flow Diagrams
- Key Components
- Data Flow
- Authentication Flow
- Chatbot Widget Flow
- RAG (Retrieval-Augmented Generation) Flow
- Realtime Updates Flow
- API Routes
- Database Schema
Quickbots is a multi-tenant SaaS platform for creating, configuring, and managing AI-powered chatbots. The platform allows users to:
- Create and customize chatbots with unique personalities
- Configure UI settings (themes, colors, behavior)
- Manage bot settings, runtime configurations, and API keys
- Embed chatbots as widgets on websites
- Real-time updates to chatbot configurations
┌─────────────────────────────────────────────────────────────┐
│ Next.js Application │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Clerk Authentication Provider │ │
│ └──────────────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Supabase Provider (with JWT) │ │
│ └──────────────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Main App Routes │ │
│ │ - /bots (dashboard) │ │
│ │ - /bots/[slug]/* (bot management) │ │
│ └──────────────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ @qb/quickbot Package (Widget) │ │
│ │ - Embedded chatbot widget │ │
│ │ - Standalone package │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Supabase Database │
│ - bots │
│ - bot_configs │
│ - bot_settings │
│ - bot_runtime_settings │
│ - bot_ui_settings │
│ - api_keys │
└─────────────────────────────────────────────────────────────┘
│
├─► Upstash Search (RAG indexing)
│
├─► Upstash Redis (Rate limiting)
│
├─► Groq LLM (Chat responses)
│ - qwen/qwen3-32b
│
└─► Google Gemini (Field generation)
- gemini-2.5-flash
- Next.js 16 (App Router)
- React 19
- TypeScript
- Tailwind CSS
- Shadcn UI (Radix UI components)
- Framer Motion (animations)
- React Hook Form + Zod (form validation)
- Next.js API Routes (serverless functions)
- Supabase (PostgreSQL database + Realtime)
- Clerk (authentication)
- Groq (LLM for chat responses -
qwen/qwen3-32b) - Google Gemini 2.5 Flash (AI field generation)
- Upstash Search (RAG - Retrieval-Augmented Generation)
- Upstash Redis (Rate limiting)
- Monorepo (workspaces)
- @qb/quickbot (internal package for chatbot widget)
User visits app
│
▼
┌─────────────────────────────────────┐
│ Root Layout (layout.tsx) │
│ - ClerkProvider │
│ - SupabaseProvider │
│ - ThemeProvider │
│ - Chatbot widget (hardcoded) │
└─────────────────────────────────────┘
│
├─► Clerk Authentication
│ └─► JWT token for Supabase
│
├─► Supabase Client Creation
│ └─► Anon key + Clerk JWT
│
└─► Chatbot Widget Initialization
└─► Fetches config from /api/config/[bot_id]
User navigates to /bots
│
▼
┌─────────────────────────────────────┐
│ BotsList Component │
│ - Fetches user's bots from Supabase│
│ - Displays bot cards │
└─────────────────────────────────────┘
│
▼
User clicks on a bot
│
▼
┌─────────────────────────────────────┐
│ /bots/[slug]/layout.tsx │
│ - BotLayoutClient │
│ └─► Fetches full bot data │
│ - bot │
│ - bot_configs │
│ - bot_settings │
│ - bot_runtime_settings │
│ - api_keys │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ Tab Navigation │
│ - Configure │
│ - Settings │
│ - Advance │
│ - Quickbots API │
│ - Danger Zone │
└─────────────────────────────────────┘
Chatbot Component Mounts
│
▼
┌─────────────────────────────────────┐
│ Chatbot.tsx │
│ 1. Fetches config from API │
│ GET /api/config/[bot_id] │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ API Route: /api/config/[bot_id] │
│ 1. Validates bot_id │
│ 2. Fetches bot profile │
│ 3. Fetches bot_ui_settings │
│ 4. Filters allowed fields │
│ 5. Signs payload with ECDSA │
│ 6. Returns {ui_settings, signature}│
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ fetchBotConfig() │
│ 1. Parses response with Zod │
│ 2. Verifies ECDSA signature │
│ 3. Transforms to camelCase │
│ 4. Returns uiSettings │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ ChatbotPreview.tsx │
│ - Renders chat UI │
│ - Handles open/close/expand │
│ - Manages email prompt │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ ChatInterface.tsx │
│ - Message display │
│ - Input handling │
│ - File upload │
│ - Emoji picker │
│ - Markdown rendering │
└─────────────────────────────────────┘
User sends message
│
▼
┌─────────────────────────────────────┐
│ ChatInterface.handleSend() │
│ - Validates email (if required) │
│ - Adds message to state │
│ - Prepares FormData/JSON │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ POST /api/chat/[bot_id] │
│ 1. Validates bot_id & session │
│ 2. Rate limiting check │
│ 3. Parses request (JSON/FormData) │
│ 4. Authenticates (API key or none) │
│ 5. Loads bot profile │
│ 6. RAG: Upstash Search query │
│ - Searches bot config context │
│ - Retrieves relevant snippets │
│ 7. Builds system prompt + RAG ctx │
│ 8. Calls Groq LLM (qwen/qwen3-32b) │
│ 9. Returns JSON response │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ Groq LLM │
│ - Processes message + context │
│ - Generates JSON response │
│ - Returns {answer, suggestedQuestions}│
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ ChatInterface displays response │
│ - Updates message │
│ - Renders markdown │
│ - Shows suggested questions │
└─────────────────────────────────────┘
User updates UI settings in Preview Form
│
▼
┌─────────────────────────────────────┐
│ previewFormLayout.tsx │
│ - Submits form data │
│ - Calls updatePreview() │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ usePreviewActions.updatePreview() │
│ - Converts to snake_case │
│ - Filters allowed fields │
│ - Updates bot_ui_settings table │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ Supabase Realtime │
│ - Triggers UPDATE event │
│ - Broadcasts to subscribers │
└─────────────────────────────────────┘
│
├─► Preview Form Subscription
│ └─► Updates form state
│
└─► Chatbot Widget Subscription
└─► Fetches new config
└─► Updates UI
- Creates authenticated Supabase client
- Uses Clerk JWT token for authentication
- Provides client via React Context
- Fetches complete bot data
- Provides bot context to children
- Exposes refetch function on window object
- Web Component (custom element
<quick-bot>) - Creates Shadow DOM for style isolation
- Injects CSS styles
- Observes dark mode changes on parent page
- Renders React Chatbot component
- Main widget component
- Fetches and validates config
- Subscribes to realtime updates
- Renders ChatbotPreview
- Renders chat UI (floating button, windows)
- Handles auto-open, auto-greet
- Manages email prompt flow
- Position and theme styling
- Core chat functionality
- Message display and input
- File upload, emoji picker (with dark mode support)
- Markdown rendering
- Timestamp display
- Auto-scroll on open and streaming completion
- Chat history persistence (sessionStorage)
- Form for editing UI settings
- Live preview of chatbot
- Realtime subscription for updates
- Split-pane layout
-
bots
- Core bot information
bot_id(UUID, primary key)user_id(Clerk user ID)name,description, etc.
-
bot_configs
- Bot personality and behavior
greetings,personality,temperature, etc.
-
bot_settings
- General bot settings
- Various configuration options
-
bot_runtime_settings
- Runtime-specific settings
- Performance and behavior tuning
-
bot_ui_settings ⭐ (Critical for widget)
- UI customization
theme,chatbot_name,welcome_messagequick_questions,positionauto_open_delay_ms,auto_greet_on_openask_email_before_chat,show_timestampspersist_chat
-
api_keys
- API keys for server-to-server access
- Hashed tokens
Database (snake_case)
│
▼
API Route (filters allowed fields)
│
▼
ECDSA Signature
│
▼
Client (Zod validation)
│
▼
Transform to camelCase
│
▼
React Components (camelCase)
1. User signs in via Clerk
2. ClerkProvider manages session
3. SupabaseProvider gets JWT token:
session.getToken({ template: "supabase" })
4. Supabase client created with:
- Anon key
- Authorization: Bearer <JWT>
5. RLS policies enforce user access
1. Widget requests config from /api/config/[bot_id]
2. API base URL is hardcoded (http://localhost:3000)
3. Server signs payload with private key
4. Widget verifies signature with public key
5. No user authentication required for widget
6. Signature ensures config integrity
1. Server-to-server requests include:
Authorization: Bearer <api_key>
2. Server looks up API key in database
3. Verifies bot_id matches
4. Allows access to chat endpoint
The widget can be integrated via three methods:
-
Script Tag Auto-Mount:
<script src="CDN_URL" data-bot-id="BOT_ID" defer></script>
- Automatically creates
<quick-bot>element - API base URL is hardcoded (no need to specify)
- Automatically creates
-
Custom Element:
<quick-bot bot-id="BOT_ID"></quick-bot>
- Manual placement
- Requires script to be loaded first
-
JavaScript API:
window.QuickBot.init({ botId: "BOT_ID" });
- Programmatic initialization
- Can specify custom container
1. Widget loads via script tag or custom element <quick-bot>
2. QuickBotWidget (Web Component) initializes:
- Creates Shadow DOM (mode: "open")
- Injects CSS styles into Shadow DOM
- Sets up dark mode observer (MutationObserver)
- Detects dark mode from parent page's <html> element
3. Chatbot component mounts within Shadow DOM
4. useEffect fetches config:
- Calls fetchBotConfig(botId)
- GET /api/config/[bot_id]
- API base URL is hardcoded to http://localhost:3000
5. Validates response:
- Zod schema validation
- ECDSA signature verification
6. Transforms data:
- snake_case → camelCase
- Adds theme pack
7. Sets uiSettings state
8. Subscribes to realtime updates
9. Renders ChatbotPreview
10. Auto-scrolls to bottom on initial load
1. User clicks floating button
2. Chat opens (if autoOpenDelayMs > 0, auto-opens)
3. Auto-scrolls to bottom when opened
4. If autoGreetOnOpen: shows welcome message
5. If askEmailBeforeChat:
- User can send message first
- Then prompted for email
- Email validated with regex
6. User types message
7. Message sent to /api/chat/[bot_id]
8. Response streamed back
9. Message displayed with markdown
10. Auto-scrolls to bottom when streaming completes
11. If showTimestamps: timestamp shown
12. Chat history persisted to sessionStorage
- Auto-open: Opens after
autoOpenDelayMs - Auto-greet: Shows welcome message on open
- Email prompt: Collects email before chat (if enabled)
- File upload: Images and files supported
- Emoji picker: Always enabled (with dark mode support)
- Markdown: Always enabled
- Timestamps: Optional display
- Quick questions: Clickable preset questions
- Themes: 5 themes (modern, classic, minimal, bubble, retro)
- Auto-scroll: Automatically scrolls to bottom on open and when streaming completes
- Chat persistence: Uses sessionStorage for chat history (7-day retention)
- Dark mode: Automatically detects
class="dark"on<html>element
User saves bot configuration
│
▼
┌─────────────────────────────────────┐
│ Config Form / Settings Form │
│ - Updates Supabase (bot_configs) │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ POST /api/vector/ingest │
│ - Triggers ingestion (non-blocking)│
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ ingestBotContent(botId) │
│ 1. Fetches persona & botthesis │
│ 2. Upserts to Upstash Search │
│ - ID: bot:{botId}:persona │
│ - ID: bot:{botId}:botthesis │
│ - Metadata: {botId, field} │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ Upstash Search Index │
│ - Index: "bot-configs" │
│ - Stores config text for retrieval │
└─────────────────────────────────────┘
User sends chat message
│
▼
┌─────────────────────────────────────┐
│ POST /api/chat/[bot_id] │
│ - retrieveContext(botId, message) │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ Upstash Search Query │
│ - Searches "bot-configs" index │
│ - Filters by metadata.botId │
│ - Returns top 3 results │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ System Prompt Builder │
│ - Injects RAG context │
│ - Format: "CONTEXT START / END" │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ Groq LLM │
│ - Uses context for better answers │
└─────────────────────────────────────┘
Key Points:
- Non-blocking: Ingestion failures don't break config saves
- Idempotent: Safe to re-ingest (upsert by ID)
- Scoped: Each bot has isolated search results
- Optional: If Upstash Search is not configured, chat works without RAG
- Fallback: If no RAG results, LLM proceeds with base prompt
1. previewFormLayout.tsx mounts
2. useEffect sets up subscription:
supabase.channel(`ui-settings-${bot_id}`)
.on("postgres_changes", {
event: "*",
table: "bot_ui_settings",
filter: `bot_id=eq.${bot_id}`
})
3. On update:
- Checks if local update (isLocalUpdateRef)
- Compares timestamps
- Updates form state
4. Cleanup on unmount
1. Chatbot.tsx subscribes after initial load
2. subscribeToBotUpdates():
- Creates Supabase client (anon key, no JWT)
- Subscribes to bot_ui_settings updates
- On update: fetches new config
- Updates uiSettings state
3. Polling fallback:
- Polls every 2 seconds
- Ensures updates are received
4. Cleanup on unmount
1. User saves in Preview Form
2. updatePreview() updates database
3. Supabase Realtime broadcasts UPDATE
4. Both subscriptions receive event:
- Preview form: Updates form state
- Widget: Fetches new config
5. Widget re-renders with new settings
Purpose: Provides signed bot UI configuration to widget
Flow:
- Validates
bot_id - Fetches bot profile and UI settings
- Filters to allowed fields only
- Signs payload with ECDSA P-256
- Returns
{ ui_settings, signature }
Security:
- ECDSA signature ensures integrity
- No authentication required (public endpoint)
- Whitelist prevents unauthorized fields
Note: Widget uses hardcoded API base URL (https://quickbots-ai.vercel.app).
Purpose: Handles chat messages and returns AI responses with RAG
Flow:
- Validates
bot_id, session ID, and message - Rate limiting (20 requests/minute per session)
- Supports JSON or FormData (for files)
- Authenticates (API key or none for widget)
- Loads bot profile
- RAG: Queries Upstash Search for relevant bot config context
- Builds system prompt with RAG context (if available)
- Calls Groq LLM (
qwen/qwen3-32b) with JSON response format - Returns structured JSON:
{answer, suggestedQuestions}
Authentication:
- Optional:
Authorization: Bearer <api_key>for server-to-server - Widget requests: No auth (authenticated via config signature)
Features:
- RAG (Retrieval-Augmented Generation): Context-aware responses using bot config
- Rate limiting: 20 requests/minute per session
- Short-circuit optimization: Skips LLM for obvious out-of-scope messages
- JSON response format: Structured answers with suggested questions
- Token limit: 512 tokens max per response
- Fallback handling: Returns bot's fallback message on errors
Purpose: Generates bot configuration fields using AI
Flow:
- Validates bot ID and field type
- Rate limiting (10 requests/minute per bot)
- Loads bot settings for context
- Calls Google Gemini (
gemini-2.5-flash) with field-specific prompt - Returns generated content
Features:
- AI-powered generation: Creates persona, botthesis, greetings, etc.
- Context-aware: Uses existing bot settings as context
- Rate limited: 10 requests/minute per bot
- Token limit: 2000 tokens max per generation
- Field-specific prompts: Optimized prompts for each field type
quick-bot-ai/
├── src/
│ ├── app/ # Next.js App Router
│ │ ├── api/ # API routes
│ │ │ ├── config/ # Config endpoint
│ │ │ ├── chat/ # Chat endpoint (with RAG)
│ │ │ ├── generate-field/# AI field generation
│ │ │ └── vector/ # Search ingestion trigger
│ │ ├── bots/ # Bot management pages
│ │ │ └── [slug]/ # Individual bot routes
│ │ └── layout.tsx # Root layout
│ ├── components/ # React components
│ │ ├── bot-*.tsx # Bot-related components
│ │ └── ui/ # Shadcn UI components
│ ├── features/ # Feature modules
│ │ ├── preview/ # Preview form
│ │ ├── config/ # Config form
│ │ └── ...
│ ├── lib/ # Utilities
│ │ ├── client/ # Client-side actions
│ │ ├── db/ # Database helpers
│ │ ├── supabase/ # Supabase config
│ │ ├── upstash/ # Upstash services
│ │ │ ├── search/ # Upstash Search (RAG)
│ │ │ └── rate-limit/ # Rate limiting
│ │ ├── llm/ # LLM utilities
│ │ │ └── system-prompt-builder.ts
│ │ └── ...
│ ├── providers/ # Context providers
│ │ └── SupabaseProvider.tsx
│ └── types/ # TypeScript types
│
└── packages/
└── quickbot/ # Chatbot widget package
├── src/
│ ├── QuickBotWidget.ts # Web Component
│ ├── Chatbot.tsx
│ ├── ChatbotPreview.tsx
│ ├── ChatInterface.tsx
│ └── index.ts # CDN entry point
└── lib/
├── api/ # API client
├── crypto/ # Signature verification
├── realtime/ # Realtime subscriptions
├── themes/ # Theme packs
├── utils/ # Utilities (chat session, transformers)
└── validators.tsx # Zod schemas
# Clerk
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=
CLERK_SECRET_KEY=
# Supabase
NEXT_PUBLIC_SUPABASE_URL=
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=
SUPABASE_SERVICE_ROLE_KEY=
# ECDSA Keys (for config signing)
QUICKBOT_PRIVATE_KEY_RAW=
NEXT_PUBLIC_QUICKBOT_PUBLIC_KEY=
# Groq (LLM for chat)
GROQ_API_KEY=
# Google Gemini (AI field generation)
GEMINI_API_KEY=
# Upstash Search (RAG)
UPSTASH_SEARCH_REST_URL=
UPSTASH_SEARCH_REST_TOKEN=
# Upstash Redis (Rate limiting)
UPSTASH_REDIS_REST_URL=
UPSTASH_REDIS_REST_TOKEN=
# CDN (Production)
CDN_URL=https://quickbot-ai.smit090305.workers.dev/v1/quickbot.iife.jsNote: The widget's API base URL is hardcoded in quickbot/src/index.ts as https://quickbots-ai.vercel.app.
Optional Services:
- Upstash Search: If not configured, RAG is disabled (chat still works)
- Upstash Redis: If not configured, rate limiting is disabled (all requests allowed)
Each theme has predefined colors:
- modern: Blue/gray professional
- classic: Traditional colors
- minimal: Clean, simple
- bubble: Playful, rounded
- retro: Vintage aesthetic
backgroundColor: Chat backgroundheaderColor: Header background (with decorative clip-path)accentColor: User message bubblestextColor: Text colorborderColor: Border colors
- Automatically detects
class="dark"on<html>element - Uses MutationObserver to watch for theme changes
- Applies dark theme styles within Shadow DOM
- Emoji picker adapts to dark mode automatically
- Monorepo: Build
@qb/quickbotpackage before deploying - CDN Build: Widget is built as IIFE for CDN deployment
- CDN URL:
https://quickbot-ai.smit090305.workers.dev/v1/quickbot.iife.js - API Base URL: Hardcoded to
https://quickbots-ai.vercel.app - Environment Variables: All keys must be set
- Clerk Template: Must have "supabase" JWT template
- Supabase RLS: Policies must allow authenticated access
- Realtime: Must be enabled on
bot_ui_settingstable - Web Components: Uses native Shadow DOM for style isolation
- Realtime not working: Check Supabase credentials in quickbot client
- Config errors: Verify ECDSA keys match
- RLS errors: Check Clerk JWT template exists
- Widget not loading: Check browser console for fetch errors
- Signature verification fails: Ensure allowed fields match
This is a multi-tenant SaaS platform for AI chatbots with:
- ✅ User authentication via Clerk
- ✅ Database via Supabase (PostgreSQL)
- ✅ Realtime updates via Supabase Realtime
- ✅ AI chat via Groq (
qwen/qwen3-32b) with RAG - ✅ RAG (Retrieval-Augmented Generation) via Upstash Search
- ✅ AI field generation via Google Gemini (
gemini-2.5-flash) - ✅ Rate limiting via Upstash Redis
- ✅ Embeddable widget via Web Component (
<quick-bot>) - ✅ CDN deployment via IIFE build
- ✅ Secure config via ECDSA signatures
- ✅ Multi-tenant via user_id isolation
- ✅ Dark mode automatic detection
- ✅ Chat persistence via sessionStorage
- ✅ CORS support for cross-origin widget requests
The architecture separates concerns:
- Main app: Bot management UI
- Widget package: Standalone chatbot widget (Web Component)
- API routes: Server-side logic
- Realtime: Live configuration updates
- CDN: Script tag auto-mount or programmatic API
-
Script Tag (Auto-mount):
<script src="CDN_URL" data-bot-id="BOT_ID" defer></script>
-
Custom Element:
<quick-bot bot-id="BOT_ID"></quick-bot>
-
JavaScript API:
window.QuickBot.init({ botId: "BOT_ID" });