# Contexta — AI Chatbot SaaS Platform A full-stack SaaS platform that lets businesses build custom AI chatbots from their documents, publish them to a marketplace, and optionally export self-hostable code. --- ## Architecture at a Glance ``` contexta_be/ → FastAPI backend (Python 3.11) contexta_fe/ → React + TypeScript frontend (Vite) ``` **Key tech stack:** - **Backend**: FastAPI, Supabase (auth + DB), Qdrant (vectors), LangChain - **Frontend**: React 18, TypeScript, Tailwind CSS, TanStack Query, Zustand - **AI**: Fireworks AI (free tier), OpenAI, Anthropic, Google Gemini - **Payments**: Stripe - **Infra**: Docker, Railway/Vercel-ready --- ## Prerequisites | Tool | Version | Purpose | |------|---------|---------| | Python | 3.11+ | Backend runtime | | Node.js | 18+ | Frontend build | | Git | any | Version control | **External services you need to set up (all have free tiers):** | Service | What for | Free tier? | |---------|----------|------------| | [Supabase](https://supabase.com) | Database + Auth | ✅ Yes | | [Qdrant Cloud](https://cloud.qdrant.io) | Vector search | ✅ Yes (1GB) | | [Fireworks AI](https://fireworks.ai) | LLM (free models) | ✅ Yes | | [OpenAI](https://platform.openai.com) | Embeddings + GPT-4 | Pay-per-use | | [Stripe](https://stripe.com) | Payments | ✅ Test mode | --- ## Part 1: Supabase Setup (Database + Auth) ### 1.1 Create a Supabase project 1. Go to [supabase.com](https://supabase.com) → New project 2. Save your **Project URL** and both keys (anon + service_role) ### 1.2 Run the database schema 1. In your Supabase dashboard → **SQL Editor** 2. Open `contexta_be/supabase_schema.sql` 3. Paste the entire file → Run This creates all tables, RLS policies, and triggers. ### 1.3 Enable Email Auth 1. In Supabase → **Authentication** → **Providers** 2. Ensure "Email" is enabled 3. Optionally disable "Confirm email" for faster testing --- ## Part 2: Qdrant Setup (Vector Database) ### Option A: Qdrant Cloud (recommended) 1. Go to [cloud.qdrant.io](https://cloud.qdrant.io) → Create cluster (free tier) 2. Get your **Cluster URL** and **API Key** ### Option B: Local Qdrant (for development) ```bash docker run -p 6333:6333 qdrant/qdrant ``` Then set `QDRANT_URL=http://localhost:6333` and leave `QDRANT_API_KEY` empty. --- ## Part 3: Backend Setup (`contexta_be`) ### 3.1 Clone and configure ```bash cd contexta_be cp .env.example .env ``` Edit `.env` with your credentials: ```env # App APP_ENV=development APP_SECRET_KEY=change-this-to-a-random-string-in-production ALLOWED_ORIGINS=http://localhost:5173,http://localhost:3000 # Supabase (from your project settings) SUPABASE_URL=https://your-project.supabase.co SUPABASE_ANON_KEY=eyJ... SUPABASE_SERVICE_ROLE_KEY=eyJ... # Qdrant QDRANT_URL=https://your-cluster.qdrant.io QDRANT_API_KEY=your-key-here # LLM - MINIMUM REQUIRED: OpenAI (for embeddings) OPENAI_API_KEY=sk-... # LLM - Optional but recommended FIREWORKS_API_KEY=fw_... # Free models for starter plan ANTHROPIC_API_KEY=sk-ant-... # Claude models GOOGLE_API_KEY=AIza... # Gemini models # Stripe (use test keys for development) STRIPE_SECRET_KEY=sk_test_... STRIPE_WEBHOOK_SECRET=whsec_... STRIPE_STARTER_PRICE_ID=price_... STRIPE_PRO_PRICE_ID=price_... ``` ### 3.2 Create virtual environment and install ```bash python -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate pip install -r requirements.txt ``` ### 3.3 Start the backend ```bash uvicorn app.main:app --reload --host 0.0.0.0 --port 8000 ``` The API will be available at: - **API**: http://localhost:8000 - **Swagger docs**: http://localhost:8000/docs - **Health check**: http://localhost:8000/health ### 3.4 Docker alternative ```bash # Copy and edit .env first cp .env.example .env # Edit .env... # Start with Docker (includes Qdrant locally) docker-compose up -d ``` --- ## Part 4: Frontend Setup (`contexta_fe`) ### 4.1 Install dependencies ```bash cd contexta_fe npm install ``` ### 4.2 Configure environment ```bash cp .env.example .env ``` `.env` content: ```env VITE_API_URL=http://localhost:8000 VITE_APP_NAME=Contexta ``` ### 4.3 Start the frontend ```bash npm run dev ``` Frontend available at: http://localhost:5173 --- ## Part 5: Stripe Setup (Payments) ### 5.1 Create Stripe products 1. Go to [dashboard.stripe.com](https://dashboard.stripe.com) → Products 2. Create **Starter** product → Add price → $39/month recurring 3. Create **Pro** product → Add price → $119/month recurring 4. Copy the **Price IDs** (start with `price_`) → paste into backend `.env` ### 5.2 Set up webhook (for local testing) Install Stripe CLI: ```bash # Mac brew install stripe/stripe-cli/stripe # Others: https://stripe.com/docs/stripe-cli ``` Forward webhooks to local: ```bash stripe listen --forward-to localhost:8000/api/v1/billing/webhook ``` Copy the webhook signing secret → paste into `STRIPE_WEBHOOK_SECRET` in `.env` ### 5.3 Test a subscription Use Stripe test card: `4242 4242 4242 4242` with any future expiry and any CVC. --- ## Part 6: Testing the Full Flow ### 6.1 Create an account 1. Open http://localhost:5173 2. Click "Get started free" or go to http://localhost:5173/signup 3. Fill in company name, email, password ### 6.2 Create a chatbot 1. After login → **Dashboard** → **New Chatbot** 2. Enter a name and configure settings 3. Click **Save** ### 6.3 Upload documents 1. In the chatbot builder → **Documents** tab 2. Drag and drop a PDF, DOCX, or CSV file 3. Wait for processing (status changes to "completed" with chunk count) > ⚠️ Document processing requires a valid OpenAI API key for embeddings and a working Qdrant instance. ### 6.4 Test in preview mode 1. In the chatbot builder → **Preview** tab 2. Type a question related to your uploaded document 3. The chatbot should answer based on the document content ### 6.5 Publish to marketplace (requires paid plan) 1. Subscribe to Starter or Pro (Stripe checkout) 2. Back in Dashboard → click **Publish** on your chatbot 3. Visit http://localhost:5173/marketplace to see it listed ### 6.6 Export code (Pro plan) In the chatbot builder → click **Export Code** button → downloads a ZIP containing: - `backend/` — Complete FastAPI app with your vectors - `frontend/` — React TypeScript chat widget - `setup.py` — Interactive setup wizard - `QUICK_START.md` — 5-minute deployment guide --- ## API Reference The complete API is documented via Swagger at http://localhost:8000/docs when the backend is running. ### Key endpoints | Method | Endpoint | Description | |--------|----------|-------------| | POST | `/api/v1/auth/signup` | Create account | | POST | `/api/v1/auth/login` | Login | | GET | `/api/v1/auth/me` | Current user | | GET | `/api/v1/chatbots` | List your chatbots | | POST | `/api/v1/chatbots` | Create chatbot | | PUT | `/api/v1/chatbots/{id}` | Update chatbot | | POST | `/api/v1/chatbots/{id}/publish` | Publish to marketplace | | POST | `/api/v1/chatbots/{id}/export` | Download code export (Pro) | | POST | `/api/v1/chatbots/{chatbot_id}/documents` | Upload document | | POST | `/api/v1/chat/{chatbot_id}` | Send chat message | | GET | `/api/v1/marketplace/chatbots` | Browse marketplace | | POST | `/api/v1/billing/checkout` | Create Stripe checkout | --- ## Deployment ### Backend → Railway ```bash # Install Railway CLI npm i -g @railway/cli cd contexta_be railway login railway init railway up ``` Set all environment variables in Railway dashboard → Variables tab. ### Frontend → Vercel ```bash npm i -g vercel cd contexta_fe vercel ``` Set `VITE_API_URL` to your Railway backend URL in Vercel environment variables. ### Update CORS Once deployed, update `ALLOWED_ORIGINS` in backend to include your Vercel domain: ``` ALLOWED_ORIGINS=https://your-app.vercel.app ``` --- ## Minimal Setup (Testing Only, No Real AI) If you want to test the UI without real API keys, you can: 1. Run only the frontend 2. Mock the API responses For the quickest backend test without Qdrant/OpenAI, comment out the vector store initialization in startup and the RAG processing in document upload. The chat will still work but won't return relevant answers. --- ## Environment Variables Reference ### Backend (`contexta_be/.env`) | Variable | Required | Description | |----------|----------|-------------| | `SUPABASE_URL` | ✅ | Supabase project URL | | `SUPABASE_ANON_KEY` | ✅ | Supabase anon key | | `SUPABASE_SERVICE_ROLE_KEY` | ✅ | Supabase service role key | | `QDRANT_URL` | ✅ | Qdrant cluster URL | | `QDRANT_API_KEY` | ⚠️ | Required for Qdrant Cloud | | `OPENAI_API_KEY` | ✅ | Required for embeddings | | `FIREWORKS_API_KEY` | ⚠️ | For free-tier Llama/Mixtral models | | `ANTHROPIC_API_KEY` | ⚠️ | For Claude models (Pro plan) | | `GOOGLE_API_KEY` | ⚠️ | For Gemini models (Pro plan) | | `STRIPE_SECRET_KEY` | ⚠️ | For billing (use test key in dev) | | `STRIPE_WEBHOOK_SECRET` | ⚠️ | For Stripe webhooks | | `STRIPE_STARTER_PRICE_ID` | ⚠️ | Stripe price ID for Starter plan | | `STRIPE_PRO_PRICE_ID` | ⚠️ | Stripe price ID for Pro plan | | `ALLOWED_ORIGINS` | ✅ | Comma-separated CORS origins | | `APP_SECRET_KEY` | ✅ | Random secret for production | ### Frontend (`contexta_fe/.env`) | Variable | Required | Description | |----------|----------|-------------| | `VITE_API_URL` | ✅ | Backend API URL | --- ## Project Structure ``` contexta_be/ ├── app/ │ ├── main.py # FastAPI app + router registration │ ├── config.py # Settings + plan limits │ ├── database.py # Supabase client │ ├── models.py # Pydantic models │ ├── dependencies.py # Auth middleware │ ├── routers/ │ │ ├── auth.py # Signup, login, me │ │ ├── chatbots.py # CRUD + publish + export │ │ ├── documents.py # File upload + processing │ │ ├── chat.py # RAG chat endpoint │ │ ├── marketplace.py # Public chatbot listing │ │ └── billing.py # Stripe checkout + webhooks │ └── services/ │ ├── vector_store.py # Qdrant operations │ ├── embeddings.py # OpenAI embeddings │ ├── document_processor.py # PDF/DOCX/CSV parsing │ ├── llm.py # Multi-provider LLM routing │ ├── rag.py # RAG pipeline │ └── code_export.py # ZIP code generation ├── supabase_schema.sql # Database schema (run once) ├── requirements.txt ├── Dockerfile └── docker-compose.yml contexta_fe/ ├── src/ │ ├── main.tsx # Entry point │ ├── App.tsx # Router + routes │ ├── index.css # Tailwind + global styles │ ├── types/index.ts # TypeScript interfaces │ ├── services/api.ts # API client (axios) │ ├── store/authStore.ts # Zustand auth state │ ├── lib/utils.ts # Helpers + constants │ ├── components/ │ │ ├── ui.tsx # Reusable UI (Button, Input, Card...) │ │ ├── Layout.tsx # App shell with sidebar │ │ └── ChatInterface.tsx # Chat UI with sources │ └── pages/ │ ├── LandingPage.tsx │ ├── AuthPages.tsx # Login + Signup │ ├── DashboardPage.tsx │ ├── ChatbotBuilderPage.tsx # Builder + docs + preview │ ├── MarketplacePage.tsx │ ├── PricingPage.tsx │ └── SettingsPage.tsx ├── package.json ├── vite.config.ts └── tailwind.config.js ``` --- ## Troubleshooting ### "CORS error" in browser → Check `ALLOWED_ORIGINS` in backend `.env` includes your frontend URL ### "Could not connect to Qdrant" → Check `QDRANT_URL` is correct and the cluster is running → For local Docker: ensure the qdrant service is started ### "Invalid or expired token" on API calls → The Supabase JWT has expired. Log out and log back in. → Check `SUPABASE_SERVICE_ROLE_KEY` is correct ### Document processing stuck on "processing" → Check OpenAI API key is valid → Check Qdrant connection → Check backend logs: `docker logs contexta-api` or terminal output ### "Upgrade to publish" even after Stripe payment → Ensure Stripe webhook is configured and received the `checkout.session.completed` event → Check backend logs for webhook processing → For local testing, use `stripe listen --forward-to localhost:8000/api/v1/billing/webhook` ### Chat returns "I don't have information about that" → Document processing may have failed — check document status in builder → The uploaded content may not be relevant to the question → Try re-uploading the document --- ## Development Tips - **Backend hot reload**: `uvicorn app.main:app --reload` watches for file changes - **Frontend hot reload**: `npm run dev` automatically reloads - **API testing**: Use http://localhost:8000/docs (Swagger UI) - **Database inspection**: Supabase dashboard → Table Editor - **Vector inspection**: Qdrant dashboard at http://localhost:6333/dashboard (local only) --- ## License MIT — build freely, use commercially.