{"id":50989896,"url":"https://github.com/paganini2008/fastrag","last_synced_at":"2026-06-20T01:01:22.121Z","repository":{"id":345712968,"uuid":"1186937270","full_name":"paganini2008/fastrag","owner":"paganini2008","description":"A full-stack, multi-tenant RAG platform that turns documents, URLs, and FAQs into a searchable knowledge base with AI-powered question answering. Built with Django + React, powered by OpenAI embeddings and Claude / GPT-4o LLMs.","archived":false,"fork":false,"pushed_at":"2026-03-20T09:17:46.000Z","size":299,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-21T02:02:44.424Z","etag":null,"topics":["llm","minio","postgresql","qdrant","rag"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/paganini2008.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-20T06:40:01.000Z","updated_at":"2026-03-20T09:21:01.000Z","dependencies_parsed_at":"2026-03-21T02:03:06.919Z","dependency_job_id":null,"html_url":"https://github.com/paganini2008/fastrag","commit_stats":null,"previous_names":["paganini2008/fastrag"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/paganini2008/fastrag","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paganini2008%2Ffastrag","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paganini2008%2Ffastrag/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paganini2008%2Ffastrag/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paganini2008%2Ffastrag/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/paganini2008","download_url":"https://codeload.github.com/paganini2008/fastrag/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/paganini2008%2Ffastrag/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34553456,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-19T02:00:06.005Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["llm","minio","postgresql","qdrant","rag"],"created_at":"2026-06-20T01:01:20.795Z","updated_at":"2026-06-20T01:01:22.056Z","avatar_url":"https://github.com/paganini2008.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n# 🧠 RAG Platform\n\n**Production-grade Multi-tenant Retrieval-Augmented Generation Platform**\n\n[![Python](https://img.shields.io/badge/Python-3.13-3776AB?style=flat-square\u0026logo=python\u0026logoColor=white)](https://python.org)\n[![Django](https://img.shields.io/badge/Django-6.x-092E20?style=flat-square\u0026logo=django\u0026logoColor=white)](https://djangoproject.com)\n[![React](https://img.shields.io/badge/React-19-61DAFB?style=flat-square\u0026logo=react\u0026logoColor=black)](https://react.dev)\n[![TypeScript](https://img.shields.io/badge/TypeScript-5.9-3178C6?style=flat-square\u0026logo=typescript\u0026logoColor=white)](https://typescriptlang.org)\n[![Tailwind CSS](https://img.shields.io/badge/Tailwind-4.x-06B6D4?style=flat-square\u0026logo=tailwindcss\u0026logoColor=white)](https://tailwindcss.com)\n[![Qdrant](https://img.shields.io/badge/Qdrant-1.17-FF4785?style=flat-square)](https://qdrant.tech)\n[![Tests](https://img.shields.io/badge/Tests-27%20passed-22C55E?style=flat-square\u0026logo=pytest\u0026logoColor=white)]()\n[![License](https://img.shields.io/badge/License-MIT-8B5CF6?style=flat-square)](LICENSE)\n\nA full-stack, multi-tenant RAG platform that turns documents, URLs, and FAQs into a searchable knowledge base with AI-powered question answering. Built with Django + React, powered by OpenAI embeddings and Claude / GPT-4o LLMs.\n\n[Features](#-features) · [Architecture](#-architecture) · [Tech Stack](#-tech-stack) · [Quick Start](#-quick-start) · [API](#-api-overview) · [Testing](#-testing)\n\n\u003c/div\u003e\n\n---\n\n## ✨ Features\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003ctd width=\"50%\"\u003e\n\n**Knowledge Management**\n- 📁 Upload PDF, DOCX, XLSX, PPTX, TXT, HTML, Markdown\n- 🌐 Import web pages (static + Playwright dynamic rendering)\n- ❓ FAQ management with bulk import\n- 🔄 Automatic async ingestion pipeline\n- ♻️ Per-KB reindex with embedding model switching + live progress\n\n\u003c/td\u003e\n\u003ctd width=\"50%\"\u003e\n\n**AI-Powered Retrieval**\n- 🔍 Vector similarity search (cosine, top-K)\n- 🤖 Full RAG answers via Claude or GPT-4o\n- 📊 Score-based relevance ranking\n- 📝 Prompt builder with token estimation\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n**Multi-tenant \u0026 Secure**\n- 🏢 Full tenant isolation at DB + Qdrant level\n- 🔑 JWT authentication + API Key for agents\n- 👥 Role-based access (owner / admin / member)\n- 📋 Audit logs for every search \u0026 answer\n\n\u003c/td\u003e\n\u003ctd\u003e\n\n**Developer Experience**\n- 📖 Auto-generated Swagger / OpenAPI 3.0 docs\n- ⚡ Celery async processing with Redis\n- 🧪 27 pytest tests, all mocked externals\n- 🐳 Docker-ready, `uv` package manager\n\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\n---\n\n## 🏗 Architecture\n\n### System Overview\n\n```mermaid\ngraph TB\n    subgraph Client[\"🖥️ Browser (React 19 + Vite)\"]\n        UI[React UI\u003cbr/\u003eTailwind CSS + Ant Design]\n        RTK[RTK Query\u003cbr/\u003eState \u0026 Cache]\n        AUTH[JWT Auth\u003cbr/\u003eRedux Slice]\n    end\n\n    subgraph Gateway[\"🌐 API Gateway\"]\n        VITE_PROXY[Vite Dev Proxy\u003cbr/\u003e:5173 → :8000]\n        NGINX[Nginx\u003cbr/\u003eProduction Reverse Proxy]\n    end\n\n    subgraph Backend[\"⚙️ Django 6 + DRF\"]\n        direction TB\n        URLS[URL Router\u003cbr/\u003e/api/v1/]\n        MW[TenantMiddleware\u003cbr/\u003eJWT → tenant_id]\n\n        subgraph Apps[\"Django Apps\"]\n            AUTH_APP[accounts\u003cbr/\u003eJWT + API Key Auth]\n            KB[knowledge_bases\u003cbr/\u003eCRUD]\n            DOCS[documents\u003cbr/\u003eUpload · URL · Chunks]\n            FAQ_APP[faq\u003cbr/\u003eQ\u0026A Management]\n            RETRIEVAL[retrieval\u003cbr/\u003eSearch · Prompt · Answer]\n            AUDIT[audit\u003cbr/\u003eRetrieval \u0026 Query Logs]\n        end\n\n        subgraph Pipeline[\"Ingestion Pipeline\"]\n            direction LR\n            PARSE[parsers\u003cbr/\u003ePDF·DOCX·XLSX·HTML]\n            CHUNK[chunking\u003cbr/\u003eLlamaIndex Splitter]\n            EMBED_SVC[embeddings\u003cbr/\u003eOpenAI API]\n            VSTORE[vector_store\u003cbr/\u003eQdrant Client]\n        end\n    end\n\n    subgraph Workers[\"🔄 Celery Workers\"]\n        INGEST[ingest_document\u003cbr/\u003eparse→chunk→embed→index]\n        INGEST_URL[ingest_url\u003cbr/\u003efetch→parse→chunk→embed]\n        EMBED_FAQ[embed_faq_item\u003cbr/\u003equestion+answer→embed]\n    end\n\n    subgraph Storage[\"💾 Data Layer\"]\n        PG[(PostgreSQL\u003cbr/\u003eschema: rag)]\n        QDRANT[(Qdrant\u003cbr/\u003edocument_chunks)]\n        MINIO[(MinIO\u003cbr/\u003eraw files)]\n        REDIS[(Redis\u003cbr/\u003eCelery broker)]\n    end\n\n    subgraph LLM[\"🤖 AI Services\"]\n        OPENAI[OpenAI\u003cbr/\u003etext-embedding-3-small\u003cbr/\u003eGPT-4o / GPT-4o-mini]\n        ANTHROPIC[Anthropic\u003cbr/\u003eClaude Sonnet 4.6\u003cbr/\u003eClaude Haiku 4.5]\n    end\n\n    UI --\u003e RTK --\u003e VITE_PROXY --\u003e URLS\n    URLS --\u003e MW --\u003e Apps\n    AUTH_APP --\u003e PG\n    KB --\u003e PG\n    DOCS --\u003e PG\n    DOCS --\u003e MINIO\n    DOCS --\u003e REDIS\n    FAQ_APP --\u003e PG\n    FAQ_APP --\u003e REDIS\n    RETRIEVAL --\u003e QDRANT\n    RETRIEVAL --\u003e LLM\n    AUDIT --\u003e PG\n\n    REDIS --\u003e Workers\n    Workers --\u003e PARSE --\u003e CHUNK --\u003e EMBED_SVC --\u003e VSTORE\n    EMBED_SVC --\u003e OPENAI\n    VSTORE --\u003e QDRANT\n    Workers --\u003e MINIO\n```\n\n---\n\n### RAG Ingestion Pipeline\n\n```mermaid\nflowchart LR\n    A([📄 File Upload\\nor URL]) --\u003e B\n\n    subgraph B[\"① Parse\"]\n        B1[PDF → pypdf\\nDOCX → python-docx\\nXLSX → openpyxl\\nHTML → BeautifulSoup4]\n    end\n\n    B --\u003e C\n\n    subgraph C[\"② Chunk\"]\n        C1[LlamaIndex\\nSentenceSplitter\\nchunk_size=512 tokens\\noverlap=64 tokens]\n    end\n\n    C --\u003e D\n\n    subgraph D[\"③ Embed\"]\n        D1[OpenAI\\ntext-embedding-3-small\\nor 3-large per KB]\n    end\n\n    D --\u003e E\n\n    subgraph E[\"④ Index\"]\n        E1[Qdrant upsert\\nper-KB collection\\nor shared collection]\n    end\n\n    E --\u003e F([✅ indexed\\nDocument.status])\n\n    style A fill:#4f46e5,color:#fff\n    style F fill:#10b981,color:#fff\n```\n\n---\n\n### RAG Query Flow\n\n```mermaid\nsequenceDiagram\n    actor User\n    participant FE as React Frontend\n    participant API as Django API\n    participant QD as Qdrant\n    participant LLM as Claude / GPT-4o\n    participant DB as PostgreSQL\n\n    User-\u003e\u003eFE: Ask a question\n    FE-\u003e\u003eAPI: POST /api/v1/rag/answer/\\n{query, knowledge_base_id, llm_model}\n\n    API-\u003e\u003eAPI: Embed query\\n(OpenAI text-embedding-3-small)\n    API-\u003e\u003eQD: query_points(vector, filter={tenant_id, kb_id}, top_k=5)\n    QD--\u003e\u003eAPI: Top-K chunks with scores\n\n    API-\u003e\u003eAPI: Build prompt\\n(system + context + question)\n    API-\u003e\u003eLLM: Chat completion request\n    LLM--\u003e\u003eAPI: Generated answer\n\n    API-\u003e\u003eDB: Save QueryLog\\n(query, answer, tokens, latency_ms)\n    API--\u003e\u003eFE: {answer, sources, usage, latency_ms}\n    FE--\u003e\u003eUser: Display answer + cited sources\n```\n\n---\n\n### Multi-tenant Data Isolation\n\n```mermaid\nerDiagram\n    TENANT {\n        uuid id PK\n        string name\n        string slug\n        string plan\n    }\n    USER {\n        uuid id PK\n        uuid tenant_id FK\n        string email\n        string role\n    }\n    KNOWLEDGE_BASE {\n        uuid id PK\n        uuid tenant_id FK\n        string name\n        int chunk_size\n        int retrieval_top_k\n    }\n    DOCUMENT {\n        uuid id PK\n        uuid tenant_id FK\n        uuid knowledge_base_id FK\n        string status\n        string file_path\n    }\n    DOCUMENT_CHUNK {\n        uuid id PK\n        uuid tenant_id FK\n        uuid document_id FK\n        text text\n        int chunk_index\n        bool is_embedded\n    }\n    FAQ_ITEM {\n        uuid id PK\n        uuid tenant_id FK\n        uuid knowledge_base_id FK\n        text question\n        text answer\n        bool is_embedded\n    }\n\n    TENANT ||--o{ USER : has\n    TENANT ||--o{ KNOWLEDGE_BASE : owns\n    KNOWLEDGE_BASE ||--o{ DOCUMENT : contains\n    KNOWLEDGE_BASE ||--o{ FAQ_ITEM : contains\n    DOCUMENT ||--o{ DOCUMENT_CHUNK : split_into\n```\n\n---\n\n## 🛠 Tech Stack\n\n### Backend\n\n| Layer | Technology | Purpose |\n|-------|-----------|---------|\n| Runtime | Python 3.13 + **uv** | Fast dependency management |\n| Framework | **Django 6** + **DRF 3.16** | Web framework + REST APIs |\n| Auth | **simplejwt** + API Key | JWT tokens + agent access |\n| Task Queue | **Celery 5** + **Redis** | Async ingestion pipeline |\n| Vector DB | **Qdrant 1.17** | Cosine similarity search |\n| Object Storage | **MinIO** | Raw file storage (S3-compatible) |\n| Database | **PostgreSQL** (schema: `rag`) | Structured data |\n| Chunking | **LlamaIndex** `SentenceSplitter` / `SemanticSplitter` | Token-aware text splitting |\n| Embedding | **OpenAI** `text-embedding-3-small` / `3-large` | Per-KB configurable, 1536 / 3072-dim |\n| LLM | **Claude Sonnet 4.6** / **GPT-4o** | Answer generation |\n| API Docs | **drf-spectacular** | OpenAPI 3.0 / Swagger |\n| Document Parsing | pypdf · python-docx · openpyxl · python-pptx · BeautifulSoup4 | Multi-format support |\n\n### Frontend\n\n| Technology | Purpose |\n|-----------|---------|\n| **React 19** + **TypeScript 5.9** | UI framework |\n| **Vite 7** | Build tool + dev proxy |\n| **Redux Toolkit** + **RTK Query** | State management + data fetching |\n| **React Router 7** | Client-side routing |\n| **Ant Design 6** | UI components (tables, modals, forms) |\n| **Tailwind CSS 4** | Dark theme + layout + utilities |\n\n---\n\n## 🚀 Quick Start\n\n### Prerequisites\n\n```bash\n# Start infrastructure services\ndocker run -d -p 6333:6333 qdrant/qdrant\ndocker run -d -p 19000:9000 -e MINIO_ROOT_USER=admin -e MINIO_ROOT_PASSWORD=admin123 \\\n  minio/minio server /data --console-address \":9001\"\nredis-server --requirepass yourpassword\n```\n\n### Backend\n\n```bash\ncd backend\n\n# Install dependencies (uv auto-creates virtualenv)\nuv sync\n\n# Configure environment\ncp .env.example .env\n# Edit .env: set DB credentials, OPENAI_KEY, ANTHROPIC_API_KEY, REDIS_URL\n\n# Database setup\nuv run python src/manage.py migrate\nuv run python src/manage.py init_qdrant   # Create Qdrant collection\nuv run python src/manage.py createsuperuser\n\n# Run server\nuv run python src/manage.py runserver     # http://localhost:8000\n\n# Run Celery worker (separate terminal)\ncd src \u0026\u0026 uv run celery -A config.celery worker --loglevel=info\n```\n\n### Frontend\n\n```bash\ncd frontend\nnpm install\nnpm run dev     # http://localhost:5173\n```\n\n\u003e **Dev proxy**: All `/api/*` requests from `:5173` are automatically forwarded to `:8000` by Vite — no CORS config needed.\n\n---\n\n## 📁 Project Structure\n\n```\nrag/\n├── backend/\n│   ├── .env                      # All configuration\n│   ├── pyproject.toml            # uv dependencies\n│   └── src/\n│       ├── config/\n│       │   ├── settings/         # base / development / production\n│       │   ├── api_router.py     # /api/v1/ route registration\n│       │   └── celery.py         # Celery app\n│       ├── apps/\n│       │   ├── common/           # Base models, MinIO client, pagination\n│       │   ├── tenants/          # Tenant model + TenantMiddleware\n│       │   ├── accounts/         # User auth (JWT + API Key)\n│       │   ├── knowledge_bases/  # KB CRUD\n│       │   ├── documents/        # Upload, URL import, chunk preview\n│       │   ├── faq/              # FAQ management + bulk import\n│       │   ├── ingestion/        # Celery task orchestration\n│       │   ├── parsers/          # PDF/DOCX/XLSX/PPTX/HTML parsers\n│       │   ├── chunking/         # LlamaIndex SentenceSplitter / SemanticSplitter\n│       │   ├── embeddings/       # OpenAI embedding service\n│       │   ├── vector_store/     # Qdrant client wrapper\n│       │   ├── retrieval/        # Search + prompt builder + RAG answer\n│       │   └── audit/            # Search \u0026 query logs\n│       └── tests/                # 27 pytest tests\n│\n├── frontend/\n│   ├── .env                      # VITE_API_URL, VITE_APP_NAME\n│   └── src/\n│       ├── components/Layout/    # Collapsible sidebar + sticky header\n│       ├── pages/                # Login, Dashboard, KB, Docs, FAQ,\n│       │                         # Retrieval, Jobs, Logs\n│       ├── store/\n│       │   ├── api/              # RTK Query endpoints (4 APIs)\n│       │   └── slices/authSlice  # JWT token management\n│       └── index.css             # Tailwind v4 + Ant Design dark theme\n│\n└── docs/\n    └── README.md                 # Full technical documentation (CN)\n```\n\n---\n\n## 🔌 API Overview\n\nAll endpoints are prefixed with `/api/v1/`. Interactive docs at **`/api/schema/swagger-ui/`**.\n\n### Authentication\n```http\nPOST /auth/login/          # Returns access + refresh JWT\nPOST /auth/token/refresh/  # Refresh access token\nGET  /auth/me/             # Current user info\n```\n\n### Tenant Settings\n```http\nGET   /tenants/settings/  # Get tenant-level defaults (embedding_model, llm_model)\nPATCH /tenants/settings/  # Update tenant-level defaults\n```\n\n### Knowledge Bases\n```http\nGET    /knowledge-bases/            # List (paginated)\nPOST   /knowledge-bases/            # Create\nPATCH  /knowledge-bases/{id}/       # Update settings\nDELETE /knowledge-bases/{id}/       # Delete\nPOST   /knowledge-bases/{id}/rebuild/  # Async reindex with new embedding model\n```\n\n### Documents\n```http\nPOST /knowledge-bases/{kbId}/documents/upload/       # Upload file (multipart)\nPOST /knowledge-bases/{kbId}/documents/import-url/   # Import URL\nGET  /knowledge-bases/{kbId}/documents/{id}/chunks/  # Preview chunks\nPOST /knowledge-bases/{kbId}/documents/{id}/reindex/ # Re-trigger pipeline\n```\n\n### FAQ\n```http\nGET    /knowledge-bases/{kbId}/faq/               # List FAQ items\nPOST   /knowledge-bases/{kbId}/faq/               # Create (auto-embeds)\nPOST   /knowledge-bases/{kbId}/faq/bulk-import/   # Bulk import\nPATCH  /knowledge-bases/{kbId}/faq/{id}/          # Update\nDELETE /knowledge-bases/{kbId}/faq/{id}/          # Delete\n```\n\n### Retrieval \u0026 RAG\n\n```http\nPOST /retrieval/search/  # Vector search — returns top-K chunks with scores\nPOST /rag/prompt/        # Build RAG prompt (no LLM call)\nPOST /rag/answer/        # Full RAG: retrieve + LLM → answer + sources\n```\n\n**Search request:**\n```json\n{\n  \"query\": \"What is RAG?\",\n  \"knowledge_base_id\": \"uuid\",\n  \"top_k\": 5,\n  \"score_threshold\": 0.0\n}\n```\n\n**Answer request:**\n```json\n{\n  \"query\": \"What is RAG?\",\n  \"knowledge_base_id\": \"uuid\",\n  \"top_k\": 5,\n  \"llm_model\": \"claude-sonnet-4-6\"\n}\n```\n\n**Answer response:**\n```json\n{\n  \"answer\": \"RAG (Retrieval-Augmented Generation) is...\",\n  \"sources\": [\n    { \"source\": \"intro.pdf · page 3\", \"score\": 0.921 }\n  ],\n  \"usage\": { \"prompt_tokens\": 1240, \"completion_tokens\": 187, \"total_tokens\": 1427 },\n  \"latency_ms\": 1267\n}\n```\n\n---\n\n## ⚙️ Configuration\n\n### Backend `.env`\n\n```ini\n# Django\nDJANGO_SETTINGS_MODULE=config.settings.development\nSECRET_KEY=your-secret-key\n\n# PostgreSQL\nDB_HOST=localhost\nDB_PORT=5432\nDB_DATABASE=demo\nDB_USER=postgres\nDB_PASSWORD=yourpassword\nDB_SCHEMA=rag\n\n# MinIO\nMINIO_URL=localhost:19000\nMINIO_USER=admin\nMINIO_PASSWORD=admin123\nMINIO_BUCKET=rag-documents\n\n# Qdrant\nVDB_HOST=localhost\nVDB_PORT=6333\nQDRANT_COLLECTION=document_chunks\n\n# Redis / Celery\nREDIS_URL=redis://:yourpassword@localhost:6379/0\n\n# AI Keys\nOPENAI_KEY=sk-proj-...\nANTHROPIC_API_KEY=sk-ant-...\nDEFAULT_LLM_MODEL=claude-sonnet-4-6\n```\n\n### Frontend `.env`\n\n```ini\nVITE_API_URL=http://localhost:8000\nVITE_APP_NAME=RAG Platform\n```\n\n---\n\n## 🧪 Testing\n\n```bash\ncd backend\n\n# Run all 27 tests\nuv run pytest\n\n# With reuse-db (faster on re-runs)\nuv run pytest --reuse-db\n\n# Specific file\nuv run pytest src/tests/test_retrieval.py -v\n\n# With coverage\nuv run pytest --cov=apps --cov-report=html\n```\n\n**Test strategy:**\n- External services (MinIO, Qdrant, LLMs, background tasks) are all **mocked** — tests run without any infrastructure\n- Real PostgreSQL is used with a `test_` prefixed database\n- `conftest.py` auto-creates the `rag` schema if missing\n\n```\n✓ test_auth.py            — login, token refresh, protected endpoints\n✓ test_knowledge_bases.py — CRUD, tenant isolation\n✓ test_documents.py       — upload, URL import, chunk preview\n✓ test_faq.py             — create, list, delete, bulk import\n✓ test_retrieval.py       — vector search, RAG answer, error handling\n\n27 passed in 4.5s\n```\n\n---\n\n## 🐳 Docker\n\n```bash\n# Build images\ndocker build -t rag-backend  ./backend\ndocker build -t rag-frontend ./frontend\n\n# Run backend (point to your infra)\ndocker run -d --env-file backend/.env -p 8000:8000 rag-backend\n\n# Run frontend\ndocker run -d -p 80:80 rag-frontend\n```\n\n---\n\n## 📖 Pages\n\n| Page | Route | Description |\n|------|-------|-------------|\n| **Login** | `/login` | Email + password, JWT stored in localStorage |\n| **Dashboard** | `/dashboard` | Stats overview, KB summary, quick actions |\n| **Knowledge Bases** | `/knowledge-bases` | Create/edit KBs, configure chunk size \u0026 top-K, reindex with model switching |\n| **Documents** | `/knowledge-bases/:id/documents` | Upload files, import URLs, preview chunks |\n| **FAQ** | `/knowledge-bases/:id/faq` | Manage Q\u0026A pairs, view embedding status |\n| **Retrieval Test** | `/retrieval` | Test vector search and RAG answers interactively |\n| **Jobs** | `/jobs` | Monitor ingestion pipeline progress per document |\n| **Logs** | `/logs` | Retrieval logs and RAG query logs with latency |\n\n---\n\n## 📄 License\n\nMIT License — see [LICENSE](LICENSE) for details.\n\n---\n\n\u003cdiv align=\"center\"\u003e\n\nBuilt with Django · React · Qdrant · OpenAI · Anthropic · Tailwind CSS\n\n\u003c/div\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpaganini2008%2Ffastrag","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpaganini2008%2Ffastrag","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpaganini2008%2Ffastrag/lists"}