Get Started
Wall-E — Open-Source RAG Chatbot Platform

Wall-E — Open-Source RAG Chatbot Platform

Building a multi-tenant, embeddable AI chatbot platform from scratch — RAG pipelines, vanilla JS widget architecture, Razorpay subscriptions, and a fully open-source monorepo.

January 1, 202512 min read
FastAPILangChainChromaDBNext.jsGemini 2.5 FlashClerkRazorpaySystem DesignRAG

Project Overview

Wall-E is an open-source RAG-powered chatbot platform that lets any website owner embed a custom AI assistant trained on their own content — docs, PDFs, URLs, or plain text — without writing a single line of backend code.

Built as a solo indie project under hellocoders.in, it is a full-stack SaaS with a public dashboard, a FastAPI backend handling ingestion and retrieval, and a tiny vanilla JS embed widget that drops onto any site with a one-line script tag.

Timeline: Jan 2025 → Ongoing Role: Solo Full-Stack + GenAI Engineer (open-source)

The Problem

Most chatbot-builder tools in the market are either locked behind expensive SaaS paywalls, lack real RAG (they just prompt-stuff context), or produce bulky embeds that break site styling.

The specific gaps Wall-E targets:

  • No open-source alternative with a usable hosted tier
  • Existing tools offer no partial-source ingestion (upload a folder, skip certain files)
  • Widget customization is usually theme-only — no behavioral config
  • Payment flows for Indian founders are an afterthought (USD-only, no Razorpay)
  • Deployment is typically a black box — no self-host path

Architecture & Tech Stack

  • Frontend: Next.js 14 (App Router) + Tailwind CSS, hosted on Vercel
  • Auth: Clerk (multi-tenant user management, org isolation)
  • Backend: FastAPI (Python) — ingestion, retrieval, chat, webhook handling
  • Vector DB: ChromaDB (per-chatbot collection isolation)
  • LLM: Gemini 2.5 Flash via LangChain
  • Payments: Razorpay (subscriptions + webhooks, migrated from Next.js API routes to FastAPI)
  • Embed: Vanilla JS widget — four modular source files (styles, HTML, animations, core)
  • Infra: Docker Compose, shared PostgreSQL, GitHub Actions CI/CD

Data Model

Chatbot
├── id, userId, name, settings, widgetConfig
├── DataSource[]
│   ├── id, type (pdf | url | text), status, chunkCount
│   └── ingestionError?
├── ChatSession[]
│   ├── id, visitorId, createdAt
│   └── Message[]
│       ├── role, content, retrievedChunks[]
│       └── latencyMs
└── Subscription
    ├── razorpaySubscriptionId, plan, status
    └── currentPeriodEnd

RAG Pipeline Design

The ingestion and retrieval pipeline was the core engineering challenge.

Ingestion Flow

  1. User uploads a source (PDF, URL, or raw text) via the dashboard
  2. FastAPI queues a background ingestion job
  3. Source is chunked with LangChain's RecursiveCharacterTextSplitter (chunk_size=800, overlap=100)
  4. Each chunk is embedded via Gemini embeddings and stored in a per-chatbot ChromaDB collection
  5. Ingestion status tracked in PostgreSQL (pending → processing → done / failed)

Retrieval Flow (per user message)

  1. Query is embedded and top-k similar chunks retrieved from ChromaDB
  2. Retrieved chunks are ranked and injected into a structured prompt
  3. Gemini 2.5 Flash generates a response grounded in retrieved context
  4. Source citations optionally surfaced to the end user

Key Design Decisions - Per-chatbot ChromaDB collections (not a shared collection with metadata filters) for clean tenant isolation and faster retrieval - Async ingestion — dashboard shows live status without blocking the UI - Idempotent re-ingestion — re-uploading the same source deletes old chunks before re-embedding

Embeddable Widget System

The widget is a self-contained vanilla JS bundle — no React, no build step for the site owner. It injects a chat bubble + panel into any page with:

<script src="https://wall-e.hellocoders.in/widget.js" data-chatbot-id="abc123"></script>

Architecture After Refactor (four modular source files) - widget-styles.js — injects scoped CSS into shadow DOM, preventing host-site style collisions - widget-html.js — declarative HTML template for the chat panel and trigger button - widget-animations.js — open/close transitions, typing indicator, message entrance - widget-core.js — event listeners, API calls, session management, message rendering

Notable Bugs Resolved - Double-listener click bug — trigger button was accumulating event listeners across re-renders; fixed by tracking listener attachment state and removing before re-adding - z-index wars — shadow DOM encapsulation was the correct fix, not z-index escalation - Mobile keyboard pushing layout — viewport meta detection + dynamic height recalculation

Payments & Subscription Flow

Razorpay subscription integration was migrated from Next.js API routes to FastAPI to consolidate all payment logic server-side.

Subscription Flow

  1. User selects a plan on the dashboard
  2. FastAPI creates a Razorpay subscription and returns a checkout token
  3. Razorpay Checkout SDK handles payment on the frontend
  4. Webhook (POST /payments/webhook) validates signature, activates plan, updates PostgreSQL
  5. Failed payments trigger grace period logic (3-day window before chatbot deactivation)

Key Integration Details - Webhook signature validation using Razorpay HMAC — no raw body parsing issues after switching to FastAPI's Request.body() - Idempotency on webhook handler — duplicate events from Razorpay are deduplicated by event ID - Subscription status synced to chatbot active/inactive state — unpaid chatbots return a soft error to the widget

Open-Source Monorepo Setup

Wall-E is fully open-source with a production-grade repo structure:

  • README with architecture diagram, quickstart, and self-host guide
  • CONTRIBUTING.md with PR guidelines and issue templates
  • LICENSE (MIT)
  • Docker Compose — spins up FastAPI + Next.js + PostgreSQL + ChromaDB with one command
  • GitHub Actions CI — lint, type-check, and test on every PR
  • Environment variable schema documented with .env.example

The goal was to make self-hosting achievable in under 30 minutes for any developer familiar with Docker.

Key Learnings

  1. Shadow DOM is the right abstraction for embeddable widgets — fighting z-index and CSS specificity without it is a losing battle
  2. Per-tenant vector collections beat metadata-filtered shared collections for both isolation guarantees and query latency
  3. Migrate payment webhooks to your primary backend early — Next.js API routes are too fragile for webhook reliability (cold starts, body parsing edge cases)
  4. Modular widget source files pay off immediately — debugging a monolithic 800-line widget.js is miserable
  5. Open-source scaffolding should be set up at project start, not retrofitted — it shapes how you write code from day one