Second Brain
AI-powered note-taking app for STEM/CS students with semantic search and smart organization

Overview
I built this because I was tired of losing my notes across random text files and forgotten Google Docs. Second Brain is basically my solution to the note-taking mess that every CS student deals with - pasting code snippets, saving algorithm explanations, keeping track of stuff you learned.
The main idea: paste anything, and AI figures out where it should go and what tags make sense. No more "misc notes" folder with 500 files.
- Paste random content → AI organizes it automatically - Search by meaning, not just keywords - Rich text editor with code blocks, LaTeX math, syntax highlighting
Built it mainly for CS students, bootcamp people, and anyone learning to code who's drowning in notes.
Interface Preview

Tech Stack
Core Framework
- Next.js 15 with App Router for server and client components
- TypeScript in strict mode for type safety
- Tailwind CSS for styling
- SCSS for TipTap styling (following TipTap patterns)
- shadcn/ui for ui components
Rich Text Editor
- Tiptap Editor for rich text editing with custom components and features
- lowlight for syntax highlighting (30+ languages)
- LaTeX math support for equations
- Code blocks
- Custom AI Powered Formatter using OpenAI SDK
State Management
- React Query for server state
- Zustand for global client UI state
- useReducer for complex local state
- useState for simple local state
Project Structure
src/├── actions/ # Server actions (API layer)│ ├── aiActions.ts # AI features│ ├── noteActions.ts # Note CRUD│ ├── folderActions.ts # Folder management│ └── tagActions.ts # Tag operations├── app/ # Next.js App Router│ ├── (auth)/ # Auth pages│ ├── (main)/ # Main app│ │ ├── layout.tsx # Sidebar + header│ │ └── notes/ # Notes routes│ │ ├── page.tsx│ │ ├── new/│ │ └── [id]/│ └── api/webhooks/ # Clerk webhooks├── components/│ ├── editor/ # Note editor│ ├── modals/ # Dialogs│ │ ├── QuickCaptureModal.tsx│ │ └── SearchModal.tsx│ ├── sidebar/ # Navigation│ └── ui/ # shadcn components├── hooks/ # React Query hooks│ ├── use-notes.ts│ ├── use-folders.ts│ └── use-semantic-search.ts├── lib/ # Utilities│ ├── prisma.ts│ ├── queryClient.ts│ └── auth.ts├── services/ # External services│ └── ai/│ ├── content-analyzer.ts│ ├── semantic-search.ts│ └── prompts/└── schemas/ # Zod validation├── noteSchemas.ts└── folderSchemas.ts
Database Architecture
Core Features
Rich Text Editor
Full-featured Tiptap editor with: - Text Formatting: Bold, italic, underline, strikethrough, code, highlight - Headings: H1-H6 with visual hierarchy - Lists: Bullet, numbered, task lists with checkboxes - Code Blocks: Syntax highlighting for 30+ languages via lowlight - Math Support: Inline and block LaTeX equations - Auto-Save: Debounced saving every 2 seconds with visual indicators

Syntax highlighting for 30+ languages

Inline and block LaTeX support
Smart Folder System
Organize notes in a 3-level hierarchy with: - Custom Colors: 6 options (Gray, Red, Green, Blue, Yellow, Purple) - Special Inbox: Auto-created for unorganized content - Validation: Prevents circular references and duplicate names - Note Organization: Move notes between folders

Quick Capture (AI-Powered)
Paste anything and AI organizes it automatically: - Smart Analysis: Suggests title, folder, and tags (3-5 seconds) - Folder Matching: Prefers existing folders, creates new if needed - Tag Intelligence: Reuses existing tags + adds specific new ones - Content Formatting: Converts plain text to rich HTML
AI-Powered Content Formatter
Transform plain text into beautifully formatted rich text: - Smart Structure Detection: Automatically detects headings, lists, and code blocks - Code Syntax Highlighting: Preserves code formatting with proper language detection - Math Support: Converts LaTeX notation to rendered equations - Full Editor Support: Works seamlessly with all Tiptap features - Fast Processing: Formats content in 2-3 seconds using OpenAI GPT-4o-mini
Semantic Search
AI-powered search that understands meaning: - Natural Language: Search like "how to sort arrays efficiently" - Context-Aware: Finds related notes even without exact keywords - Fast Results: 300-500ms after first search (embeddings cached) - Similarity Scores: See how relevant each result is (0-100%)
How Quick Capture Works
Quick Capture uses AI to analyze pasted content and automatically organize it.

Quick Capture modal

Ai Analysis results
Semantic Search

First search - generates embeddings (takes 2-3s)

Second search - uses cached embeddings (300ms)
The search uses "lazy embeddings" - basically I don't generate them until you actually search for something.
- Creating notes is instant (no embedding generation) - First search takes 2-3 seconds (has to generate for all notes) - Every search after that is 300ms - Saves a ton of money on API calls - Only regenerates for notes you've edited
Embedding Freshness Logic
The system intelligently decides when to regenerate embeddings:
- No embedding exists - First time searching this note
- Missing timestamp - Corrupted metadata
- Content updated - contentUpdatedAt > embeddingUpdatedAt
Challenges & Solutions
Challenge 1: Managing Form State
The note editor has like 5 different fields that all affect each other - title, content, folder, tags, favorite status. I started with a bunch of useState hooks and it turned into a mess of sync issues.
Switched to useReducer. Now I have one source of truth for the form state and typed actions like SET_TITLE, ADD_TAG, TOGGLE_FAVORITE. Way cleaner and actually testable.
Adding new fields is easy now, and I stopped getting weird state bugs where the UI didn't match the data.
Challenge 2: Search Was Too Slow
I was generating embeddings every time someone created a note. This meant 2-3 second waits after every save. Terrible UX and was costing me money in API calls.
Switched to lazy embeddings - only generate when someone actually searches. Cache them in the database and only regenerate if the content changed. First search is slower but every search after is instant.
Note creation is instant now. First search takes a few seconds but then it's 300ms. Cut my OpenAI bill by 90%.
Challenge 3: Matching AI Folder Suggestions
The AI would suggest paths like 'Algorithms/Sorting' but my database stores folders flat with just a parentId reference. Had to figure out how to match AI suggestions to actual folder structures.
Built a recursive function that walks up the parent chain to build full paths for every folder. Then match the AI suggestion case-insensitively and return the deepest (most specific) match.
Quick Capture now pre-fills the right folders. If you have 'Algorithms/Sorting' and paste sorting code, it actually finds it.
Challenge 4: Auto-Save Without Breaking Things
Saving on every keystroke = too many API calls. Saving too rarely = risk losing work. And when people type fast, you get race conditions where saves overlap.
2-second debounced auto-save. Only saves if the note exists already. Cancels pending saves if the user keeps typing. Shows 'Last saved at...' so people know it worked.
Feels smooth, doesn't spam the API, and I haven't lost any data yet.