Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
247 changes: 211 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,81 @@
# Full Stack FastAPI Template

[![Test Docker Compose](../../actions/workflows/test-docker-compose.yml/badge.svg)](../../actions/workflows/test-docker-compose.yml)
[![Test Backend](../../actions/workflows/test-backend.yml/badge.svg)](../../actions/workflows/test-backend.yml)
# Full Stack FastAPI Template + Multi-Tenant RAG

[![Python](https://img.shields.io/badge/Python-3.14-3776AB.svg?logo=python&logoColor=white)](https://python.org)
[![FastAPI](https://img.shields.io/badge/FastAPI-0.141+-009688.svg?logo=fastapi&logoColor=white)](https://fastapi.tiangolo.com)
[![PostgreSQL](https://img.shields.io/badge/PostgreSQL-17-336791.svg?logo=postgresql&logoColor=white)](https://www.postgresql.org)
[![pgvector](https://img.shields.io/badge/pgvector-0.5.0-FF6F00.svg)](https://github.com/pgvector/pgvector)
[![Pytest](https://img.shields.io/badge/Pytest-89%2F89%20passed-brightgreen.svg?logo=pytest&logoColor=white)](https://pytest.org)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)

Production-ready Full Stack FastAPI web application template with **Native Multi-Tenant RAG (Retrieval-Augmented Generation)**, **pgvector Hybrid Search**, and **Two-Stage Cross-Encoder Re-Ranking**, eliminating external vector database overhead while ensuring strict enterprise data isolation.

---

## 🧠 What Makes This Template Different?

Most FastAPI templates only cover traditional CRUD operations. When teams build AI features, they are often forced to introduce external vector databases (e.g. Pinecone, Chroma, Qdrant), leading to duplicate storage costs, syncing bugs, and data security risks.

This template solves that by integrating **`pgvector`** directly into the existing **PostgreSQL + SQLModel** stack with a high-precision two-stage retrieval pipeline:

```mermaid
flowchart TD
subgraph Client
UserApp["Web / API Client"]
end

subgraph FastAPI Backend
Auth["JWT Auth & Tenant Context"]
RAGRouter["/api/v1/rag/* & /api/v1/chat/*"]
Chunker["Sliding-Window Chunker"]
EmbeddingSvc["Embedding Service (OpenAI / Offline)"]
RRF["Stage 1: Reciprocal Rank Fusion (RRF)"]
Reranker["Stage 2: Cross-Encoder Re-Ranking (Cohere / Local)"]
end

subgraph PostgreSQL Database
DocTable[("document table")]
VectorIdx[("documentchunk (Vector + HNSW Index)")]
FTSIdx[("documentchunk (GIN Full-Text Index)")]
end

UserApp -->|1. Ingest Document| RAGRouter
RAGRouter --> Chunker --> EmbeddingSvc
EmbeddingSvc --> DocTable
EmbeddingSvc --> VectorIdx
EmbeddingSvc --> FTSIdx

UserApp -->|2. Hybrid Query| RAGRouter
RAGRouter --> Auth
Auth -->|Dense Semantic Query| VectorIdx
Auth -->|Keyword BM25 Query| FTSIdx
VectorIdx --> RRF
FTSIdx --> RRF
RRF -->|Top Candidate Chunks| Reranker
Reranker -->|High-Precision Reranked Context| UserApp
```

### Key AI / RAG Capabilities:
* 💾 **No External Vector Database Needed**: Dense 1536-dim embeddings stored alongside relational data using official `pgvector/pgvector:pg17` and HNSW indexing (`vector_cosine_ops`).
* 🔒 **Strict Multi-Tenant Isolation**: Chunks, chat sessions, and embeddings are indexed with `owner_id` / `user_id`. A user can never retrieve or view data belonging to another user.
* ⚡ **Two-Stage Hybrid Search & Re-ranking**: Stage 1 combines dense semantic similarity (`<=>` cosine distance) with PostgreSQL full-text search (`tsvector`) via **Reciprocal Rank Fusion (RRF)**. Stage 2 evaluates cross-attention relevance to eliminate false positives and promote the most accurate context chunks.
* 🤖 **Offline & CI/CD Friendly**: Includes a deterministic embedding fallback and local cross-encoder scoring that allows 100% of test suites to pass locally without requiring paid API keys.

---

## Technology Stack and Features

- ⚡ [**FastAPI**](https://fastapi.tiangolo.com) for the Python backend API.
- 🧰 [SQLModel](https://sqlmodel.tiangolo.com) for the Python SQL database interactions (ORM).
- 🔍 [Pydantic](https://docs.pydantic.dev), used by FastAPI, for the data validation and settings management.
- 💾 [PostgreSQL](https://www.postgresql.org) as the SQL database.
- 🧰 [SQLModel](https://sqlmodel.tiangolo.com) for Python SQL database interactions (ORM).
- 🔍 [Pydantic](https://docs.pydantic.dev), used by FastAPI, for data validation and settings management.
- 💾 [PostgreSQL + pgvector](https://github.com/pgvector/pgvector) as the unified relational + vector database.
- 🧠 **Native RAG Pipeline**:
- Ingestion API with sliding-window text chunking and overlap.
- Hybrid search and question answering with inline source citations.
- 🚀 [React](https://react.dev) for the frontend.
- 🧩 Built into the backend application and served by FastAPI on the same domain as the API.
- 💃 Using TypeScript, hooks, [Vite](https://vitejs.dev), and other parts of a modern frontend stack.
- 🎨 [Tailwind CSS](https://tailwindcss.com) and [shadcn/ui](https://ui.shadcn.com) for the frontend components.
- 🤖 An automatically generated frontend client.
- 💃 Using TypeScript, hooks, [Vite](https://vitejs.dev), and TanStack Router / Query.
- 🎨 [Tailwind CSS](https://tailwindcss.com) and [shadcn/ui](https://ui.shadcn.com) for components.
- 🤖 Automatically generated frontend client.
- 🧪 [Playwright](https://playwright.dev) for end-to-end testing.
- 🦇 Dark mode support.
- ☁️ [FastAPI Cloud](https://fastapicloud.com) for deployment.
Expand All @@ -23,9 +85,114 @@
- 🔑 JWT (JSON Web Token) authentication.
- 📫 Email-based password recovery.
- ✉️ [React Email](https://react.email) for email templates.
- 📬 [Mailpit](https://mailpit.axllent.org) for local email testing during development.
- ✅ Tests with [Pytest](https://pytest.org).
- 🏭 CI (continuous integration) and CD (continuous deployment) based on GitHub Actions.
- 📬 [Mailpit](https://mailpit.axllent.org) for local email testing.
- ✅ Full test suite with [Pytest](https://pytest.org) (63 tests).
- 🏭 CI/CD based on GitHub Actions.

---

## 📡 RAG API Quick Reference

All endpoints are authenticated using standard Bearer JWT tokens under `/api/v1/rag`:

| Method | Endpoint | Description |
| :--- | :--- | :--- |
| `POST` | `/api/v1/rag/documents` | Ingest a document (chunks text & generates vector embeddings) |
| `GET` | `/api/v1/rag/documents` | List current user's indexed documents with chunk counts |
| `GET` | `/api/v1/rag/documents/{id}` | Retrieve document details (tenant-scoped) |
| `DELETE` | `/api/v1/rag/documents/{id}` | Delete document and cascade delete all associated chunks/vectors |
| `POST` | `/api/v1/rag/search` | Execute hybrid search (Dense Vector + Full-Text Search with RRF) |
| `POST` | `/api/v1/rag/query` | Complete RAG Q&A: retrieves context and generates grounded answer |
| `POST` | `/api/v1/rag/stream` | Token-by-token SSE streaming with proactive client disconnect abort guard |
| `POST` | `/api/v1/chat/sessions` | Create a new conversational chat session |
| `GET` | `/api/v1/chat/sessions` | List user's chat sessions ordered by latest update |
| `GET` | `/api/v1/chat/sessions/{id}` | Get chat session details & full chronological message history |
| `DELETE` | `/api/v1/chat/sessions/{id}` | Delete chat session and cascade delete all messages |
| `POST` | `/api/v1/chat/sessions/{id}/messages` | Multi-turn conversational Q&A preserving context history |
| `POST` | `/api/v1/chat/sessions/{id}/stream` | Multi-turn conversational token streaming via SSE |
| `GET` | `/api/v1/ai/usage` | Current month token consumption, quota limit, remaining tokens & spend |
| `GET` | `/api/v1/ai/history` | Historical audit log of prompt/completion tokens and estimated USD costs |
| `PATCH` | `/api/v1/ai/users/{id}/quota` | Superuser-only endpoint to configure monthly token budget per user |

### Example: Document Ingestion

```bash
curl -X POST "http://localhost:8000/api/v1/rag/documents" \
-H "Authorization: Bearer <YOUR_JWT_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"title": "FastAPI AI Architecture Guide",
"content": "FastAPI is ideal for AI applications due to native async I/O. Using pgvector allows storing embeddings directly in PostgreSQL with HNSW indexing.",
"content_type": "text/plain"
}'
```

### Example: Hybrid Search Query

```bash
curl -X POST "http://localhost:8000/api/v1/rag/search" \
-H "Authorization: Bearer <YOUR_JWT_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"query": "How to store embeddings in PostgreSQL?",
"top_k": 3
}'
```

### Example: Real-time Token Streaming (SSE)

```bash
curl -N -X POST "http://localhost:8000/api/v1/rag/stream" \
-H "Authorization: Bearer <YOUR_JWT_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"query": "Summarize how pgvector handles indexing in this template",
"top_k": 3
}'
```

### Example: Check AI Token Quota & Spend

```bash
curl -X GET "http://localhost:8000/api/v1/ai/usage" \
-H "Authorization: Bearer <YOUR_JWT_TOKEN>"
```

Response:
```json
{
"total_tokens_month": 1420,
"monthly_limit": 50000,
"remaining_tokens": 48580,
"estimated_cost_usd": 0.000426,
"usage_percentage": 2.84,
"is_unlimited": false
}
```

### Example: Multi-Turn Conversational RAG Session

```bash
# 1. Create a persistent conversation session
SESSION_ID=$(curl -s -X POST "http://localhost:8000/api/v1/chat/sessions" \
-H "Authorization: Bearer <YOUR_JWT_TOKEN>" \
-H "Content-Type: application/json" \
-d '{"title": "FastAPI Architecture Discussion"}' | jq -r '.id')

# 2. Turn 1: Initial Question
curl -X POST "http://localhost:8000/api/v1/chat/sessions/$SESSION_ID/messages" \
-H "Authorization: Bearer <YOUR_JWT_TOKEN>" \
-H "Content-Type: application/json" \
-d '{"content": "How does this template handle vector search?", "top_k": 3}'

# 3. Turn 2: Follow-up Question with memory
curl -X POST "http://localhost:8000/api/v1/chat/sessions/$SESSION_ID/messages" \
-H "Authorization: Bearer <YOUR_JWT_TOKEN>" \
-H "Content-Type: application/json" \
-d '{"content": "Can you elaborate on the second indexing method mentioned?", "top_k": 3}'
```

---

### Dashboard Login

Expand All @@ -43,45 +210,53 @@

![Dark mode dashboard screenshot](img/dashboard-dark.png)

### React Email Templates

![Email templates screenshot](img/react-email.png)

### Mailpit - Local Email Testing

![Mailpit screenshot](img/mailpit.png)

### Interactive API Documentation

![API docs](img/docs.png)

## How to Use It

Click the **Use this template** button at the top of this page to create a new repository.
---

## Backend Development
## Quickstart

Backend docs: [backend/README.md](./backend/README.md).
### 1. Start Services with Docker Compose

## Frontend Development
```console
$ docker compose up -d db mailpit
```

Frontend docs: [frontend/README.md](./frontend/README.md).
### 2. Run Backend Locally

## Deployment
```console
$ cd backend
$ uv sync
$ uv run bash scripts/prestart.sh
$ uv run fastapi dev
```

FastAPI Cloud deployment: [deployment.md](./deployment.md).
The interactive OpenAPI documentation is available at `http://localhost:8000/docs`.

Self-hosted deployment with Docker Compose: [deployment-docker-compose.md](./deployment-docker-compose.md).
### 3. Run Test Suite

## Development
```console
$ cd backend
$ uv run pytest tests
```

General development docs: [development.md](./development.md).
Output:
```console
======================= 63 passed, 58 warnings in 5.91s =======================
```

This includes the local FastAPI and Vite workflow, Docker Compose services, `.env` configuration, and more.
---

## Release Notes
## Documentation Links

Check the file [release-notes.md](./release-notes.md).
* Backend documentation: [backend/README.md](./backend/README.md)
* Frontend documentation: [frontend/README.md](./frontend/README.md)
* General development docs: [development.md](./development.md)
* Deployment guide: [deployment.md](./deployment.md)
* Docker Compose deployment: [deployment-docker-compose.md](./deployment-docker-compose.md)
* Release notes: [release-notes.md](./release-notes.md)

## License

Expand Down
51 changes: 51 additions & 0 deletions backend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,57 @@ $ alembic upgrade head

If you don't want to start with the default models and want to remove them / modify them, from the beginning, without having any previous revision, you can remove the revision files (`.py` Python files) under `./backend/app/alembic/versions/`. And then create a first migration as described above.

## RAG & Vector Search with pgvector

This backend includes native support for Retrieval-Augmented Generation (RAG) using PostgreSQL's `pgvector` extension and SQLModel.

### Features
* **Native Vector Storage**: Chunks and embeddings are stored directly in PostgreSQL with an HNSW cosine distance index (`ix_documentchunk_embedding_hnsw`).
* **Hybrid Search (RRF)**: Combines dense vector similarity with PostgreSQL full-text search (`tsvector`) via Reciprocal Rank Fusion.
* **Abort-Aware Token Streaming**: Real-time Server-Sent Events (SSE) streaming with `request.is_disconnected()` guard to cancel upstream LLM calls when users cancel or disconnect.
* **Strict Multi-Tenancy**: All vector queries filter strictly by `owner_id` to guarantee tenant data privacy.
* **Offline Testing**: Deterministic normalized embedding fallback allows running test suites offline without OpenAI credentials.

### Services & Endpoints
* `EmbeddingService` (`app/services/embeddings.py`): Generates embeddings via OpenAI or offline fallback.
* `RAGService` (`app/services/rag.py`): Chunking, ingestion, and hybrid search ranking.
* `StreamingService` (`app/services/streaming.py`): Abort-aware SSE token streaming generator (single-shot & multi-turn).
* `TokenMeteringService` (`app/services/token_metering.py`): In-database token consumption tracking, cost estimation ($/1M tokens), and quota enforcement.
* `ChatMemoryService` (`app/services/chat_memory.py`): PostgreSQL-persisted multi-turn chat sessions, sliding-window conversation memory, and contextual search rephrasing.
* `RerankerService` (`app/services/reranker.py`): Two-stage cross-encoder relevance scoring (Cohere API / local deterministic cross-scoring).
* `RAG Routes` (`app/api/routes/rag.py`): Ingestion, document CRUD, hybrid search, question answering, and real-time SSE streaming.
* `AI Routes` (`app/api/routes/ai.py`): Token usage stats (`/usage`), audit history (`/history`), and admin quota management (`/users/{id}/quota`).
* `Chat Routes` (`app/api/routes/chat.py`): Session lifecycle, multi-turn conversational Q&A, and conversational SSE streaming.

## Two-Stage Hybrid Retrieval & Re-Ranking

Maximize response precision and minimize hallucination risk:
* **Stage 1 (Hybrid Candidate Retrieval)**: Merges dense vector distance and BM25 full-text rank via Reciprocal Rank Fusion ($N = 15$).
* **Stage 2 (Cross-Attention Re-ranking)**: Evaluates query-chunk token alignment, n-gram overlap, and term density to select the top $K$ ($K=3-5$) most relevant chunks for LLM context assembly.
* **Pluggable Architecture**: Automatically uses Cohere Rerank API if `COHERE_API_KEY` is provided, with an offline-compatible cross-encoder fallback.

## Multi-Turn Conversation Memory & Sessions

Store and continue conversational threads with PostgreSQL persistence:
* **Session & Message Isolation**: Sessions and messages are partitioned strictly by `user_id` with cascading deletes.
* **Contextual History Truncation**: Retains recent turns within a sliding context window to prevent LLM token overflow.
* **Context-Aware Hybrid Retrieval**: Rewrites and augments follow-up search queries with recent conversational context.
* **Full Token & Quota Integration**: Every turn within a session checks and updates user token consumption in real time.

## AI Token Metering & Budget Quotas

Prevent unexpected LLM bills with built-in per-user quota guardrails:
* **Real-time Cost Tracking**: Calculates prompt, completion, and embedding costs in USD per request based on industry-standard pricing.
* **Monthly Quota Enforcement**: If a user consumes their monthly token allowance (default: 50,000 tokens), subsequent inference requests return `HTTP 429 Too Many Requests`.
* **Superuser Exemption & Management**: Admins have unlimited access and can adjust user quotas on the fly via `PATCH /api/v1/ai/users/{id}/quota`.
* **Zero SaaS Dependencies**: All metrics and audit logs are recorded locally in PostgreSQL (`tokenusage` table).

To run all AI, RAG, Chat, Reranking, and Token Metering tests:

```console
$ uv run pytest tests/services/test_rag.py tests/api/routes/test_rag.py tests/services/test_token_metering.py tests/api/routes/test_ai_usage.py tests/services/test_chat_memory.py tests/api/routes/test_chat.py tests/services/test_reranker.py
```

## Email Templates

The email templates are written with [React Email](https://react.email) in `./packages/react-email/`. The `emails` directory holds one component per email and the `ui` directory holds the shared components (layout, heading, button, link, callout).
Expand Down
Loading
Loading