Multi-tenant Retrieval-Augmented Generation (RAG) platform. Upload PDFs, ask questions in natural language, get answers grounded in cited source excerpts.
Each workspace is an isolated tenant. Members upload PDFs; the ingestion pipeline parses, chunks, and embeds every page; queries run a hybrid (vector + full-text) search and stream an answer from gpt-4o-mini with inline citations that you can click to see the exact excerpt and page.
- Multi-tenant by Postgres RLS — every query is filtered at the database level
- Hybrid retrieval — pgvector cosine similarity (HNSW) + Postgres
tsvector, fused via Reciprocal Rank Fusion - Streaming chat with citations —
gpt-4o-minianswers stream token-by-token;[N]markers resolve to interactive popovers - Realtime status — document ingestion progress streams to the UI via Supabase Realtime
- Cost tracking — every LLM call records tokens + cost in cents into
usage_events - Built for free tiers — typical demo usage runs at ~$0.05 USD/month on OpenAI alone
A 4-page test PDF goes from upload to ready in ~5 seconds, costing about $0.000004.
┌────────────────────────────────────────────────────────────────────┐
│ Browser ─► Next.js (App Router, Server Actions, streaming) │
│ ├─ Auth via @supabase/ssr (cookie session) │
│ ├─ /api/chat: hybrid search → streamText (gpt-4o-mini)│
│ └─ /api/inngest: ingestion worker │
└────┬─────────────────────────────┬──────────────────────────┬──────┘
│ │ │
▼ ▼ ▼
┌─────────┐ ┌──────────────────┐ ┌──────────────┐
│ OpenAI │ │ Supabase │ │ Inngest │
│ embed + │ │ Postgres+pgvector│ │ async queue │
│ chat │ │ Storage / Auth │ │ │
└─────────┘ │ Realtime │ └──────────────┘
└──────────────────┘
See ARCHITECTURE.md for the full design, RLS strategy, and trade-offs.
You'll set up four free-tier accounts (Supabase, OpenAI, Inngest, Upstash), clone the repo, and have it running on localhost:3000 in roughly 15 minutes.
Install these once:
- Node.js 20+ (nodejs.org)
- pnpm 10+:
npm install -g pnpm - Git
Verify:
node --version # v20+ or v22+
pnpm --version # 10+
git --versiongit clone https://github.com/<your-username>/documind-ai.git
cd documind-ai
pnpm install- Go to supabase.com/dashboard and create a new project
- Pick a region close to you, set a strong database password, and save that password — you'll need it for migrations
- Once the project finishes provisioning (~2 minutes), open Settings → API and copy:
Project URLanon publickeyservice_rolekey
You'll paste these into .env.local in the next step.
- Go to platform.openai.com/api-keys
- Add a payment method and load $5 in credits (the demo costs cents per month — this lasts a long time)
- Create a key and copy it (
sk-...)
Inngest runs the async ingestion pipeline in production. Locally you'll use the Inngest dev server which doesn't need an account.
- Sign up at inngest.com with GitHub
- Open your default app and grab:
INNGEST_EVENT_KEYfrom Manage → Event KeysINNGEST_SIGNING_KEYfrom Manage → Signing Key
These are only needed for production deploy; in dev the SDK uses the local Inngest CLI.
Used for per-workspace rate limiting.
- Sign up at upstash.com
- Click Create Database, pick a region, Regional, eviction enabled
- Copy
UPSTASH_REDIS_REST_URLandUPSTASH_REDIS_REST_TOKEN
Copy the template and fill in the values you collected above:
cp .env.example .env.localOpen .env.local and paste your keys into the relevant slots. The file is already in .gitignore and won't be committed.
Make sure
INNGEST_DEV=1is set — it forces the SDK into dev mode so events route to the local Inngest server instead of Inngest Cloud.
We use the Supabase CLI to push our 10 migrations (schema + RLS + RPC functions + storage policies + Realtime publication).
Create a Personal Access Token at supabase.com/dashboard/account/tokens (Generate new token → name it whatever).
export SUPABASE_ACCESS_TOKEN="sbp_..." # macOS/Linux
# or on Windows PowerShell: $env:SUPABASE_ACCESS_TOKEN="sbp_..."
pnpm dlx supabase@latest link --project-ref <YOUR_PROJECT_REF> --password "<DB_PASSWORD>"
pnpm dlx supabase@latest db push --password "<DB_PASSWORD>"Your <YOUR_PROJECT_REF> is the subdomain of your Supabase URL, e.g. for https://abc123xyz.supabase.co the ref is abc123xyz.
For local development we want signup to work without bouncing through an email confirmation link. The Supabase Management API can flip this for you:
curl -X PATCH "https://api.supabase.com/v1/projects/<YOUR_PROJECT_REF>/config/auth" \
-H "Authorization: Bearer $SUPABASE_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"mailer_autoconfirm": true}'Or do it from the dashboard: Authentication → Providers → Email → uncheck "Confirm email".
Three sanity-check scripts make sure your environment is wired correctly before launching the app:
pnpm exec tsx scripts/check-env.ts # parses .env.local with Zod
pnpm exec tsx scripts/check-db.ts # confirms tables + helper RPCs exist
pnpm exec tsx scripts/check-storage.ts # bucket exists + signed-URL roundtrip worksAll three should print green checkmarks. If something fails, the message points at the exact missing piece.
You need two terminals open during development:
Terminal 1 — Next.js dev server:
pnpm devTerminal 2 — Inngest dev server (handles async ingestion):
pnpm dlx inngest-cli@latest devOpen:
- http://localhost:3000 — the app
- http://localhost:8288 — Inngest dashboard (run logs, events, function metrics)
- Sign up at
/signupwith any email + password (≥ 8 chars). The signup trigger automatically creates your profile + a personal workspace. - Upload a PDF at
/w/<workspace-id>/documents. Watch the status progress:queued → processing → ready(the badge updates via Supabase Realtime — no page refresh needed). - Ask a question at
/w/<workspace-id>/chat. The answer streams in with[N]citations. Click any citation to see the exact source excerpt and page.
You can verify the full pipeline ran cleanly with:
pnpm exec tsx scripts/check-ingestion.ts # ingests a synthetic PDF, asserts chunks+embeddings
pnpm exec tsx scripts/check-chat.ts # full RAG cycle: search → answer → citationEvery primitive lives in Storybook for isolated visual review:
pnpm storybookOpens at http://localhost:6006. You'll find the design tokens (colors, typography, radii, spacing), button variants, status badges, citation popovers, message bubbles, and the message input — each in its own story with a dark/light theme toggle.
To export a static build (for hosting or screenshots):
pnpm build-storybookdocumind-ai/
├── app/ Next.js App Router
│ ├── (auth)/ login, signup, server actions
│ ├── (dashboard)/ authenticated routes
│ │ └── w/[workspaceId]/ per-workspace pages (overview, documents, chat)
│ ├── api/
│ │ ├── chat/route.ts streaming RAG endpoint
│ │ └── inngest/route.ts Inngest function handler
│ ├── globals.css design tokens + base styles
│ └── layout.tsx
├── components/
│ ├── ui/ shadcn primitives + base button stories
│ ├── chat/ ChatWindow, MessageList, CitationCard, …
│ ├── documents/ UploadZone, DocumentList, StatusBadge
│ ├── workspace/ DashboardShell
│ ├── auth/ AuthForm
│ └── foundation/ token + page-header stories
├── lib/
│ ├── auth/ server/client/admin Supabase clients + middleware
│ ├── db/ hand-rolled types + query helpers
│ ├── storage/ Supabase Storage helpers (signed URLs, etc.)
│ ├── ingestion/ parser, chunker, embedder, pipeline
│ ├── rag/ retriever, prompt builder, citations parser
│ ├── llm/ OpenAI client + cost tracking
│ ├── inngest/ client + functions
│ └── env.ts Zod-validated env vars
├── supabase/migrations/ 10 SQL migrations (schema, RLS, RPC, storage)
├── scripts/ check-* utility scripts (env, db, vector, …)
├── tests/ unit + integration + e2e + eval (Vitest + Playwright)
├── .storybook/ Storybook config
└── ARCHITECTURE.md full system design
| Command | What it does |
|---|---|
pnpm dev |
Next.js dev server (Turbopack) |
pnpm build |
Production build |
pnpm start |
Run the production build locally |
pnpm lint |
ESLint |
pnpm typecheck |
tsc --noEmit strict type check |
pnpm format |
Prettier write |
pnpm test |
Vitest unit + integration |
pnpm test:e2e |
Playwright end-to-end |
pnpm storybook |
Start Storybook on :6006 |
pnpm build-storybook |
Static Storybook export |
Plus the verification scripts in scripts/:
check-env.ts— env vars parse with Zodcheck-db.ts— tables + helper RPCs existcheck-storage.ts— Supabase Storage bucket + signed URL roundtripcheck-vector.ts— pgvector schema + content_tsv generated columncheck-signup-trigger.ts— auth trigger creates profile + org + membercheck-ingestion.ts— full ingest pipeline E2E (generates a PDF + asserts chunks)check-chat.ts— full RAG cycle (search → stream → citations)
- Push the repo to GitHub
- Import it into Vercel, select Next.js
- Add the same environment variables you set locally in Project → Settings → Environment Variables, but remove
INNGEST_DEV(production should route to Inngest Cloud) - In the Inngest dashboard, point your app at
https://<your-deploy>.vercel.app/api/inngest - In Supabase, add your Vercel domain to Authentication → URL Configuration → Site URL and Redirect URLs
That's it. Vercel auto-deploys on every push to main.
MIT — see LICENSE.