Skip to content

Commit 4ec9ca4

Browse files
sanmaxdevclaude
andcommitted
Add README and license, keep planning docs local
Wrote the project README with overview, architecture diagram, setup, env reference, the document and RAG pipelines, API examples, security notes and a roadmap. Added an MIT license and a screenshots folder for readme images. Moved the internal docs folder out of version control by gitignoring it, since those are planning notes rather than part of the published project. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent b2ac281 commit 4ec9ca4

6 files changed

Lines changed: 149 additions & 830 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ pnpm-debug.log*
3838
/storage/
3939
*.sqlite3
4040

41+
# ---- Internal planning docs (kept local, not published) ----
42+
/docs/
43+
4144
# ---- OS / editors ----
4245
.DS_Store
4346
Thumbs.db

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 sanmaxdev
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 125 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -3,50 +3,55 @@
33
# DOC-007-AI
44

55
**A multi-tenant AI Knowledge Base for businesses.**
6-
Upload documents, organize them by workspace, and ask questions — every answer is grounded in and cited from your own documents.
6+
Upload your documents, ask questions in natural language, and get answers that are **grounded in — and cited from — your own sources.**
7+
8+
[![CI](https://github.com/sanmaxdev/doc-007-ai/actions/workflows/ci.yml/badge.svg)](https://github.com/sanmaxdev/doc-007-ai/actions/workflows/ci.yml)
9+
![Python](https://img.shields.io/badge/Python-3.12-3776AB?logo=python&logoColor=white)
10+
![FastAPI](https://img.shields.io/badge/FastAPI-async-009688?logo=fastapi&logoColor=white)
11+
![Next.js](https://img.shields.io/badge/Next.js-16-000000?logo=nextdotjs&logoColor=white)
12+
![Qdrant](https://img.shields.io/badge/Qdrant-vector%20db-DC244C)
13+
![License](https://img.shields.io/badge/License-MIT-green)
714

815
</div>
916

1017
---
1118

1219
## Overview
1320

14-
DOC-007-AI is a production-style SaaS RAG (Retrieval-Augmented Generation) platform. Companies upload policies, SOPs, contracts, reports, and manuals; team members ask natural-language questions; the AI answers **only** from the uploaded documents and includes citations (document name, page, and source snippet). If the answer isn't in the documents, it says so instead of hallucinating.
21+
DOC-007-AI is a production-style **RAG (Retrieval-Augmented Generation)** SaaS. Teams upload policies, SOPs, contracts, reports, and manuals; members ask natural-language questions; the AI answers **only** from the uploaded documents and returns citations (document name, page, and a source snippet). If the answer isn't in the documents, it says so instead of making something up.
22+
23+
It's built as a real product, not a demo: multi-tenant workspaces with strict isolation, role-based access, an asynchronous document-processing pipeline with a visible status state machine, and a swappable AI-provider layer.
1524

1625
## The problem it solves
1726

18-
Teams drown in documents, and generic chatbots hallucinate. DOC-007-AI gives teams **grounded, verifiable, workspace-isolated** answers from their own knowledge base — with the access control, audit trail, and processing pipeline a real business needs.
27+
Teams drown in documents, and generic chatbots hallucinate. DOC-007-AI gives teams **grounded, verifiable, workspace-isolated** answers from their own knowledge base — with the access control, processing pipeline, and audit trail a business actually needs.
1928

2029
## Key features
2130

22-
- 🔐 **Auth & RBAC** — JWT auth, workspaces with owner/admin/member roles, email invitations
23-
- 🏢 **Multi-tenant workspaces**strict isolation at the SQL **and** vector-store layers
24-
- 📄 **Document management** — upload PDF/TXT/MD (DOCX later), tags, status, search/filter
25-
- ⚙️ **Async ingestion pipeline** — extract → clean → chunk → embed → store, with a visible status state machine
31+
- 🔐 **Auth & RBAC** — JWT (access + refresh), argon2 password hashing, workspaces with owner/admin/member roles
32+
- 🏢 **Multi-tenant isolation**enforced at the SQL layer **and** the vector store (every search is workspace-filtered); cross-tenant requests return `404`, not `403`, so existence isn't leaked
33+
- 📄 **Document management** — upload PDF / TXT / MD / DOCX, validation, tags-ready metadata, search, reprocess, delete
34+
- ⚙️ **Async ingestion pipeline**`extract → clean → chunk → embed → store`, with a live status state machine (`uploaded → extracting → chunking → embedding → ready | failed`) and graceful failure capture
2635
- 🔎 **Vector search** — Qdrant with mandatory per-workspace filtering and top-k retrieval
27-
- 💬 **Grounded Q&A with citations** — answers cite document, page, and snippet; "not found" fallback
28-
- 🛡️ **Prompt-safety layer** — grounded system prompt + prompt-injection defenses
29-
- 📊 **Dashboard & usage** — documents, chunks, questions, storage, failed jobs
30-
- 🧪 **RAG eval/debug mode** — inspect retrieved chunks + similarity scores; feedback buttons
36+
- 💬 **Grounded Q&A with citations** — answers cite document, page, and snippet; a confidence/coverage indicator; a strict "not found in your documents" fallback
37+
- 🛡️ **Prompt-safety layer** — grounded system prompt; retrieved chunks are treated as untrusted data (prompt-injection defense), never as instructions
38+
- 🔌 **Swappable providers** — OpenRouter (LLM) + OpenAI (embeddings), each with a deterministic **mock** so the whole app runs and tests without any API key
39+
- 📊 **Dashboard** — documents, conversations, members, recent activity
40+
- 🐳 **Dockerized** — one `docker compose up` brings up the full stack
3141

32-
> Full feature scope, roadmap, and design rationale live in [`docs/TECHNICAL_PLAN.md`](docs/TECHNICAL_PLAN.md).
42+
## Screenshots
3343

34-
## Tech stack
44+
> Add screenshots to `screenshots/` and they'll render here.
3545
36-
| Layer | Tech |
37-
|---|---|
38-
| Frontend | Next.js 16 (App Router), React 19, TypeScript, Tailwind CSS, shadcn/ui, TanStack Query, Zustand |
39-
| Backend | FastAPI, SQLAlchemy 2.0 (async), Alembic, Pydantic v2 |
40-
| Data | PostgreSQL 16, Qdrant (`VECTOR_DIM=1536`), Redis |
41-
| Jobs | Celery + Redis |
42-
| AI | OpenRouter (LLM), OpenAI `text-embedding-3-small` (embeddings) |
43-
| Infra | Docker Compose |
46+
| Dashboard | Documents | Chat with citations |
47+
|---|---|---|
48+
| ![Dashboard](screenshots/dashboard.png) | ![Documents](screenshots/documents.png) | ![Chat](screenshots/chat.png) |
4449

4550
## Architecture
4651

4752
```mermaid
4853
flowchart LR
49-
U[User / Next.js] -->|JWT| API[FastAPI]
54+
U[User · Next.js 16] -->|JWT| API[FastAPI]
5055
API --> PG[(PostgreSQL)]
5156
API --> RDS[(Redis)]
5257
API --> Q[(Qdrant)]
@@ -55,68 +60,135 @@ flowchart LR
5560
EX --> EMB[OpenAI Embeddings]
5661
EMB --> Q
5762
W --> PG
58-
API -->|retrieve top-k, workspace-filtered| Q
63+
API -->|retrieve top-k · workspace-filtered| Q
5964
API -->|grounded prompt| LLM[OpenRouter LLM]
6065
LLM --> API
6166
API -->|answer + citations| U
6267
```
6368

69+
**Backend layering is enforced:** thin routers → services (business logic) → `rag/` (extraction · chunking · embeddings · vector store · retrieval · prompt · answer) and `providers/` (LLM + embeddings). No business logic or LLM calls live in routers.
70+
71+
## Tech stack
72+
73+
| Layer | Tech |
74+
|---|---|
75+
| Frontend | Next.js 16 (App Router), React 19, TypeScript, Tailwind CSS, shadcn-style UI, TanStack Query, Zustand |
76+
| Backend | FastAPI, SQLAlchemy 2.0 (async), Alembic, Pydantic v2 |
77+
| Data | PostgreSQL 16, Qdrant (`VECTOR_DIM=1536`), Redis |
78+
| Background jobs | Celery + Redis |
79+
| AI | OpenRouter (LLM, e.g. `gpt-4o-mini`), OpenAI `text-embedding-3-small` (embeddings) |
80+
| Infra | Docker Compose, GitHub Actions (ruff · mypy · pytest · eslint · tsc · build) |
81+
6482
## Getting started (local)
6583

6684
**Prerequisites:** Docker + Docker Compose.
6785

6886
```bash
6987
# 1. Configure environment
7088
cp .env.example .env
71-
# then add your OPENROUTER_API_KEY and OPENAI_API_KEY
89+
# then add your OPENROUTER_API_KEY and OPENAI_API_KEY (see below)
7290

73-
# 2. Boot the stack (postgres, redis, qdrant, api, worker, web)
91+
# 2. Bring up the full stack (postgres, redis, qdrant, api, worker, web)
7492
docker compose up --build
7593

76-
# 3. Open
77-
# Frontend: http://localhost:3000
78-
# API docs: http://localhost:8000/docs
79-
# Health: http://localhost:8000/healthz
94+
# 3. Apply database migrations (first run)
95+
docker compose exec api alembic upgrade head
96+
97+
# 4. Open
98+
# App: http://localhost:3000
99+
# API docs: http://localhost:8000/docs
80100
```
81101

82-
Database migrations (run once the stack is up):
102+
Register an account, create a workspace, upload a document, watch it reach **Ready**, then ask questions on the Chat page.
83103

84-
```bash
85-
docker compose exec api alembic upgrade head
86-
```
104+
> **No API keys?** The app still runs end to end using built-in **mock** providers — uploads process and the UI works — but answers will return the "not found" fallback because mock embeddings aren't semantically meaningful. Add real keys for genuine grounded answers.
87105
88-
### Local dev without Docker (API)
106+
## Environment variables
89107

90-
```bash
91-
cd apps/api
92-
python -m venv .venv && . .venv/Scripts/activate # Windows
93-
pip install -e ".[dev]"
94-
uvicorn doc007.main:app --reload
108+
See [`.env.example`](.env.example) for the full, documented list. The important ones:
109+
110+
| Variable | Description |
111+
|---|---|
112+
| `DATABASE_URL` | Async Postgres URL (`postgresql+asyncpg://…`) |
113+
| `REDIS_URL`, `CELERY_BROKER_URL`, `CELERY_RESULT_BACKEND` | Redis / Celery |
114+
| `QDRANT_URL`, `VECTOR_DIM` | Vector store (dim must match the embedding model; 1536 for `text-embedding-3-small`) |
115+
| `JWT_SECRET_KEY` | Token signing secret (`openssl rand -hex 32`) |
116+
| `OPENROUTER_API_KEY`, `LLM_MODEL` | LLM (generation) — server-side only |
117+
| `OPENAI_API_KEY`, `EMBEDDING_MODEL` | Embeddings — server-side only |
118+
| `CHUNK_SIZE_TOKENS`, `CHUNK_OVERLAP_TOKENS`, `RETRIEVAL_TOP_K`, `RETRIEVAL_MIN_SCORE` | RAG tuning |
119+
| `MAX_UPLOAD_MB`, `STORAGE_LOCAL_PATH` | Upload limits / storage |
120+
121+
**API keys are server-side only and are never exposed to the frontend.**
122+
123+
## Document processing flow
124+
125+
```
126+
upload → validate (type + size) → store file → row created (status=uploaded) → enqueue
127+
worker: extracting → chunking → embedding → ready (failures → failed, with the error)
95128
```
96129

97-
### Local dev without Docker (Web)
130+
The status is persisted at each step so the UI can follow progress live, and the pipeline is idempotent (reprocess clears prior chunks/vectors first).
131+
132+
## RAG pipeline
133+
134+
**Query:** embed the question → Qdrant search filtered by `workspace_id` (top-k) → **guardrail** (if the best match is below the relevance threshold, return "not found" without calling the LLM) → build a safe prompt → LLM → parse `[n]` citations → map back to source chunks → persist conversation, messages, and citations.
135+
136+
**Prompt safety:** grounding and citation rules live in the system role. Retrieved chunks are wrapped in a `<context>` block and explicitly marked as untrusted reference data, so document content can never override the instructions (prompt-injection defense). Document text never enters the system role.
137+
138+
## API
139+
140+
Interactive docs at `http://localhost:8000/docs`. A minimal flow with `curl`:
98141

99142
```bash
100-
cd apps/web
101-
npm install
102-
npm run dev
143+
# Register + login
144+
curl -s localhost:8000/api/v1/auth/register -H 'content-type: application/json' \
145+
-d '{"email":"you@co.com","password":"password123"}'
146+
TOKEN=$(curl -s localhost:8000/api/v1/auth/login -H 'content-type: application/json' \
147+
-d '{"email":"you@co.com","password":"password123"}' | jq -r .access_token)
148+
149+
# Create a workspace
150+
WID=$(curl -s localhost:8000/api/v1/workspaces -H "authorization: Bearer $TOKEN" \
151+
-H 'content-type: application/json' -d '{"name":"Acme"}' | jq -r .id)
152+
153+
# Upload a document
154+
curl -s localhost:8000/api/v1/workspaces/$WID/documents \
155+
-H "authorization: Bearer $TOKEN" -F file=@handbook.pdf
156+
157+
# Ask a question
158+
curl -s localhost:8000/api/v1/workspaces/$WID/chat/ask \
159+
-H "authorization: Bearer $TOKEN" -H 'content-type: application/json' \
160+
-d '{"question":"How many vacation days do we get?"}'
103161
```
104162

105-
## Environment variables
163+
## Security notes
106164

107-
See [`.env.example`](.env.example) for the full, documented list. Key ones: `DATABASE_URL`, `REDIS_URL`, `QDRANT_URL`, `VECTOR_DIM`, `JWT_SECRET_KEY`, `OPENROUTER_API_KEY`, `OPENAI_API_KEY`. **API keys are server-side only and never exposed to the frontend.**
165+
- **Tenant isolation** at three layers: workspace-scoped SQL queries, a mandatory `workspace_id` filter on every Qdrant search, and membership checks on every request (returning `404` to avoid leaking existence).
166+
- **Prompt-injection defense:** retrieved document text is treated as untrusted data, never as instructions.
167+
- **File validation** by type/extension and size; **argon2id** password hashing; JWT access + refresh.
168+
- API keys are **server-side only**; secrets are never committed (`.env` is gitignored, `.env.example` documents the shape).
108169

109-
## Security notes
170+
## Testing
171+
172+
```bash
173+
cd apps/api && pytest # backend: auth, isolation, chunking, ingestion, RAG
174+
cd apps/web && npm run lint && npm run typecheck && npm run build
175+
```
176+
177+
Coverage includes the security-critical **workspace isolation** tests, the ingestion pipeline (with a fake vector store + mock embeddings), and the RAG answer path including citation mapping and the not-found guardrail.
110178

111-
- **Tenant isolation** is enforced at the SQL layer (workspace-scoped queries + membership checks) **and** the vector layer (every Qdrant search carries a mandatory `workspace_id` filter).
112-
- Uploaded files are validated by type/MIME and size.
113-
- Retrieved document chunks are treated as **data, not instructions** (prompt-injection defense).
114-
- Important actions are recorded in audit logs.
179+
## Project status & roadmap
115180

116-
## Project status
181+
**MVP complete** — the full loop works: upload → process → ask → cited answer, workspace-isolated.
117182

118-
🚧 Under active construction. Current: **Phase 0 — foundation scaffold.** See the phased roadmap in [`docs/TECHNICAL_PLAN.md`](docs/TECHNICAL_PLAN.md).
183+
- [x] **Phase 0** — Foundation (monorepo, Docker, CI, healthchecks)
184+
- [x] **Phase 1** — Auth + workspaces + RBAC
185+
- [x] **Phase 2** — Documents + async ingestion pipeline
186+
- [x] **Phase 3** — RAG Q&A with citations
187+
- [ ] **Phase 4** — Email invitations, full role enforcement, audit logs, tags, answer feedback
188+
- [ ] **Phase 5** — RAG debug/eval mode (retrieved chunks + scores), hybrid search + reranking
189+
- [ ] **Phase 6** — Public API + API keys, usage quotas, rate limiting
190+
- [ ] **Phase 7** — SSO, streaming answers, advanced analytics
119191

120192
## License
121193

122-
MIT (planned).
194+
[MIT](LICENSE)

docs/ARCHITECTURE.md

Lines changed: 0 additions & 41 deletions
This file was deleted.

0 commit comments

Comments
 (0)