An AI-powered knowledge base. Capture notes in Markdown, search them by meaning (not keywords), and chat with your own notes — answers are streamed and grounded in your content with cited sources.
Built to showcase a modern, production-shaped full-stack + AI stack end to end.
Live demo: https://second-brain-ai-knowledge-base.vercel.app
| Feature | How it works |
|---|---|
| 📝 Markdown notes | Type-safe CRUD via React Server Components + Server Actions |
| 🔎 Semantic search | Query is embedded (Gemini) and ranked against note embeddings using pgvector cosine similarity over an HNSW index — find notes by meaning, not exact words |
| 💬 Chat with your brain (RAG) | Retrieval-Augmented Generation: your question retrieves the most relevant notes, which ground the streamed answer — with inline [Note N] citations |
| ✨ AI auto-enrichment | Every save generates a title, one-line summary, and topical tags via structured outputs (guaranteed schema, no brittle parsing) |
| 🔐 Auth & multi-tenancy | Clerk authentication; every note, search, and chat is scoped to the signed-in user's id — full per-user data isolation |
Each save runs enrichment and embedding in parallel, then stores the 1024-dim vector alongside the note so it's instantly searchable and chat-ready. If an AI call ever fails, the note still saves with a sensible fallback — the app never hard-crashes on an API hiccup.
- Next.js 16 — App Router, React Server Components, Server Actions, streaming route handlers
- TypeScript (strict) + React 19
- Tailwind CSS v4 — custom dark design system
- Postgres + pgvector on Neon (serverless) — vector similarity search
- Drizzle ORM — type-safe schema, queries, and migrations
- Google Gemini (
gemini-2.5-flashfor generation,gemini-embedding-001for embeddings) via the official@google/genaiSDK — runs entirely on the AI Studio free tier - Clerk — authentication & session management
- Vitest — unit/integration tests with mocked externals
- Vercel — deployment
Browser (React 19)
│ Server Actions (save / search / delete) POST /api/chat (RAG, streamed)
▼ │
┌──────────────────────────────────────────┐ │
│ saveNote() │ ▼
│ ├─ Gemini Flash → title/summary/tags │ retrieveContext(question)
│ └─ Gemini → 1024-d embedding │ └─ embed → pgvector top-k
│ │ (run in parallel) │ │
│ ▼ │ ▼
│ Postgres + pgvector (Drizzle) ◄────────┼──── Gemini Flash (streamed
│ ▲ │ answer + citations)
│ │ cosine similarity (HNSW, <=>) │
│ searchNotes(query) │
└──────────────────────────────────────────┘
Key files:
src/db/schema.ts— Drizzle schema with thevector(1024)column + HNSW indexsrc/lib/actions.ts— Server Actions: CRUD,searchNotes,retrieveContextsrc/lib/embeddings.ts— Gemini embeddings (asymmetric query/document task types)src/lib/ai.ts— Gemini client + structured-output enrichmentsrc/app/api/chat/route.ts— streaming RAG endpoint
| Service | Purpose | Get a key |
|---|---|---|
| Neon | Serverless Postgres w/ pgvector | https://neon.tech |
| Google AI Studio | Gemini (generation + embeddings), free tier | https://aistudio.google.com/apikey |
| Clerk | Authentication | https://dashboard.clerk.com |
cp .env.example .env.local
# then paste your DATABASE_URL, GEMINI_API_KEY, and Clerk keysnpm install
npm run db:migrate # creates the pgvector extension, table, and indexes
npm run db:seed # optional: adds a few demo notesnpm run dev
# → http://localhost:3000| Command | Description |
|---|---|
npm run dev |
Start the dev server |
npm run build / start |
Production build / serve |
npm run db:generate |
Generate a migration from the schema |
npm run db:migrate |
Apply migrations (enables pgvector, creates tables) |
npm run db:push |
Push schema directly (dev convenience) |
npm run db:studio |
Open Drizzle Studio to inspect data |
npm run db:seed |
Insert demo notes |
npm test |
Run the Vitest suite |
npm run test:watch |
Run tests in watch mode |
The suite (npm test) covers the core logic with all external services mocked, so it runs anywhere with no keys, DB, or network:
retry— transient-failure backoff (absorbs Neon cold starts)embeddings— Gemini request shape (asymmetric task types), vector mapping, missing-key handlingai— Gemini enrichment: structured-output parsing, tag capping, safe defaultsactions— auth scoping, the create/update save flow (enrich + embed + insert), input validationchatroute — RAG orchestration: grounding the prompt in retrieved notes, streamed output,x-sourcescitations, and graceful degradation when retrieval fails
npm test
# Test Files 5 passed (5)
# Tests 22 passed (22)A few deliberate choices keep it fast and lean:
- Region co-location — serverless functions run in
iad1, the same region as the Neon database (us-east-1), so queries don't cross the country. - Parallel writes — each save fires enrichment and embedding concurrently, so a save costs ~one API round-trip, not two.
- Streamed answers — the RAG endpoint streams tokens as they're generated; the client renders incrementally and memoizes completed messages so they aren't re-parsed on every token.
- Cold-start resilience — DB reads retry with backoff to absorb Neon's serverless compute wake-up.
- Lean bundle — no unused dependencies; the AI SDK is kept out of the client bundle.
- Push to GitHub and import the repo into Vercel.
- Add
DATABASE_URL,GEMINI_API_KEY,NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY, andCLERK_SECRET_KEYas environment variables. - Run
npm run db:migrateagainst your Neon database once (locally or via a Vercel build step). - Deploy. ✅
- Note chunking for long documents (embed per-section for finer retrieval)
- Conversation memory in chat + follow-up questions
- Tag filtering and a graph view of linked notes
Built by Jason. Feedback and PRs welcome.