diff --git a/README.md b/README.md index 4371964..e15058d 100644 --- a/README.md +++ b/README.md @@ -140,30 +140,40 @@ curl -X POST http://localhost:8000/api/repos \ ## MCP Integration -CodeIntel works as an MCP server with Claude Desktop: +CodeIntel works as an MCP server with Claude Desktop. **[📚 Full MCP Setup Guide](./docs/MCP_SETUP.md)** + +**Quick Setup:** ```json -// Add to Claude Desktop config (~/.config/claude/config.json) +// Add to Claude Desktop config { "mcpServers": { "codeintel": { "command": "python", - "args": ["/path/to/pebble/mcp-server/server.py"] + "args": ["/path/to/opencodeintel/mcp-server/server.py"], + "env": { + "BACKEND_API_URL": "http://localhost:8000", + "API_KEY": "your-api-key" + } } } } ``` **Available MCP Tools:** -- `search_code` - Semantic code search -- `list_repositories` - View indexed repos -- `get_dependency_graph` - Analyze architecture -- `analyze_code_style` - Team patterns -- `analyze_impact` - Change impact prediction -- `get_repository_insights` - Comprehensive metrics +| Tool | Description | +|------|-------------| +| `search_code` | Semantic code search - finds code by meaning | +| `list_repositories` | View all indexed repos | +| `get_dependency_graph` | Visualize architecture and file connections | +| `analyze_code_style` | Team conventions and patterns | +| `analyze_impact` | Know what breaks before you change it | +| `get_repository_insights` | High-level codebase overview | Now ask Claude: *"What's the authentication logic in the user service?"* and it searches your actual codebase. +**[→ Complete setup guide with troubleshooting](./docs/MCP_SETUP.md)** + ## Architecture ``` diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 6978c11..4e52382 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -1,21 +1,27 @@ -# Development version with hot reload -# Usage: docker compose -f docker-compose.dev.yml up - services: + # Redis Cache redis: image: redis:7-alpine - container_name: codeintel-redis-dev + container_name: codeintel-redis ports: - "6379:6379" + volumes: + - redis_data:/data command: redis-server --appendonly yes + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 10s + timeout: 3s + retries: 3 networks: - codeintel-network + # Backend API (with hot reload) backend: build: context: ./backend dockerfile: Dockerfile - container_name: codeintel-backend-dev + container_name: codeintel-backend ports: - "8000:8000" environment: @@ -26,14 +32,36 @@ services: - PINECONE_INDEX_NAME=${PINECONE_INDEX_NAME} - SUPABASE_URL=${SUPABASE_URL} - SUPABASE_KEY=${SUPABASE_KEY} + - SUPABASE_SERVICE_ROLE_KEY=${SUPABASE_SERVICE_ROLE_KEY} - API_KEY=${API_KEY} - BACKEND_API_URL=http://backend:8000 volumes: - - ./backend:/app # Mount entire backend for hot reload - - backend-venv:/app/venv # Cache venv + - ./backend:/app + - ./backend/repos:/app/repos + depends_on: + redis: + condition: service_healthy + networks: + - codeintel-network + restart: unless-stopped + + # Frontend DEV (Vite dev server with hot reload) + frontend: + image: node:20-alpine + container_name: codeintel-frontend-dev + working_dir: /app + ports: + - "3000:5173" + environment: + - VITE_API_URL=http://localhost:8000 + - VITE_SUPABASE_URL=${SUPABASE_URL} + - VITE_SUPABASE_ANON_KEY=${SUPABASE_KEY} + volumes: + - ./frontend:/app + - /app/node_modules # Anonymous volume to prevent overwriting node_modules + command: sh -c "npm install && npm run dev -- --host 0.0.0.0" depends_on: - - redis - command: uvicorn main:app --host 0.0.0.0 --port 8000 --reload # Hot reload enabled + - backend networks: - codeintel-network @@ -42,4 +70,5 @@ networks: driver: bridge volumes: - backend-venv: + redis_data: + driver: local diff --git a/docs/MCP_SETUP.md b/docs/MCP_SETUP.md new file mode 100644 index 0000000..904158c --- /dev/null +++ b/docs/MCP_SETUP.md @@ -0,0 +1,257 @@ +# MCP Setup Guide + +Most AI coding assistants forget your codebase the moment you close the chat. You explain your auth flow, close the window, come back tomorrow - and Claude has no idea what you're talking about. + +CodeIntel fixes this. It's an MCP server that gives Claude (or any MCP-compatible AI) persistent memory of your entire codebase - semantic search, dependency graphs, impact analysis, the works. + +Here's how to set it up in under 5 minutes. + +--- + +## What is MCP? + +MCP (Model Context Protocol) is Anthropic's open standard for connecting AI assistants to external tools and data sources. Think of it as USB for AI - a universal way to plug in capabilities. + +Instead of copy-pasting code into Claude, MCP lets Claude directly search your codebase, analyze dependencies, and understand impact of changes. + +**The result?** Claude that actually knows your code. + +--- + +## Prerequisites + +Before you start, make sure you have: + +- **Claude Desktop** installed ([download here](https://claude.ai/download)) +- **CodeIntel backend** running (either locally or hosted) +- **Python 3.11+** for the MCP server +- **5 minutes** of your time + +--- + +## Setup Steps + +### Step 1: Clone the MCP Server + +If you haven't already, grab the CodeIntel repo: + +```bash +git clone https://github.com/OpenCodeIntel/opencodeintel.git +cd opencodeintel/mcp-server +``` + +### Step 2: Install Dependencies + +```bash +pip install -r requirements.txt +``` + +That's it. No virtual environment drama for a simple MCP server. + +### Step 3: Configure Environment + +Create your `.env` file: + +```bash +cp .env.example .env +``` + +Edit `.env` with your settings: + +```env +# Where's your CodeIntel backend running? +BACKEND_API_URL=http://localhost:8000 + +# Your API key (get this from the CodeIntel dashboard) +API_KEY=your-api-key-here +``` + +**Using hosted CodeIntel?** Replace `localhost:8000` with your hosted URL. + +### Step 4: Configure Claude Desktop + +This is where the magic happens. You need to tell Claude Desktop about the MCP server. + +**Find your config file:** + +| OS | Config Location | +|----|-----------------| +| macOS | `~/Library/Application Support/Claude/claude_desktop_config.json` | +| Windows | `%APPDATA%\Claude\claude_desktop_config.json` | +| Linux | `~/.config/Claude/claude_desktop_config.json` | + +**Add CodeIntel to your config:** + +```json +{ + "mcpServers": { + "codeintel": { + "command": "python", + "args": ["/absolute/path/to/opencodeintel/mcp-server/server.py"], + "env": { + "BACKEND_API_URL": "http://localhost:8000", + "API_KEY": "your-api-key-here" + } + } + } +} +``` + +> âš ī¸ **Important:** Use the absolute path to `server.py`. Relative paths won't work. + +**Example for macOS:** +```json +{ + "mcpServers": { + "codeintel": { + "command": "python3", + "args": ["/Users/yourname/projects/opencodeintel/mcp-server/server.py"], + "env": { + "BACKEND_API_URL": "http://localhost:8000", + "API_KEY": "dev-secret-key" + } + } + } +} +``` + +### Step 5: Restart Claude Desktop + +Completely quit Claude Desktop (not just close the window) and reopen it. + +You should see a 🔧 icon in the chat input - that means MCP tools are available. + +--- + +## Available Tools + +Once connected, Claude has access to these tools: + +### `search_code` +Semantic search across your codebase. Finds code by meaning, not just keywords. + +``` +"Find authentication middleware" +"Show me error handling patterns" +"Where's the database connection logic?" +``` + +### `list_repositories` +See all indexed repositories. + +``` +"What repos do you have access to?" +"List my codebases" +``` + +### `get_dependency_graph` +Understand how files connect. See which files are critical (many dependents) vs isolated. + +``` +"Show me the dependency graph for this repo" +"What files does auth.py depend on?" +``` + +### `analyze_code_style` +Team patterns: naming conventions, async usage, type hints, common imports. + +``` +"What coding conventions does this repo use?" +"Is this team using snake_case or camelCase?" +``` + +### `analyze_impact` +Before you change a file, know what breaks. Shows direct dependents, indirect impact, and related tests. + +``` +"What happens if I modify src/auth/middleware.py?" +"What's the blast radius of changing this file?" +``` + +### `get_repository_insights` +High-level overview: file count, critical files, architecture patterns. + +``` +"Give me an overview of this codebase" +"What are the most important files here?" +``` + +--- + +## Example Prompts + +Here's how to actually use CodeIntel with Claude: + +**Understanding new code:** +> "I just joined this project. Search for the main entry points and explain the architecture." + +**Before refactoring:** +> "I want to refactor UserService. What's the impact? What tests cover it?" + +**Finding patterns:** +> "How does this codebase handle errors? Find examples of error handling." + +**Code review prep:** +> "Search for all usages of the deprecated `oldAuth()` function." + +**Matching team style:** +> "Analyze the code style. I want to write a new module that fits in." + +--- + +## Troubleshooting + +### Claude doesn't show the 🔧 icon + +1. **Check the config path** - Make sure you're editing the right config file +2. **Validate JSON** - A single missing comma breaks everything +3. **Use absolute paths** - Relative paths don't work +4. **Restart fully** - Quit Claude Desktop completely, not just close window + +### "Connection refused" errors + +Your CodeIntel backend isn't running. Start it: + +```bash +cd opencodeintel/backend +python main.py +``` + +### "Unauthorized" errors + +Check your `API_KEY` in both: +- The `.env` file in `mcp-server/` +- The Claude Desktop config + +They need to match what your backend expects. + +### Tools work but return no results + +You probably haven't indexed any repositories yet. Open the CodeIntel dashboard and add a repo first. + +### Python command not found + +On macOS, you might need `python3` instead of `python`: + +```json +{ + "command": "python3", + "args": ["/path/to/server.py"] +} +``` + +--- + +## What's Next? + +Once you're set up: + +1. **Index a repository** through the CodeIntel dashboard +2. **Start chatting** with Claude about your code +3. **Try impact analysis** before your next refactor + +Questions? Issues? [Open a GitHub issue](https://github.com/OpenCodeIntel/opencodeintel/issues) or reach out. + +--- + +*Built because AI assistants shouldn't have amnesia about your code.* diff --git a/frontend/package-lock.json b/frontend/package-lock.json index f80b30b..793f448 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -2309,9 +2309,9 @@ ] }, "node_modules/@supabase/auth-js": { - "version": "2.84.0", - "resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.84.0.tgz", - "integrity": "sha512-J6XKbqqg1HQPMfYkAT9BrC8anPpAiifl7qoVLsYhQq5B/dnu/lxab1pabnxtJEsvYG5rwI5HEVEGXMjoQ6Wz2Q==", + "version": "2.86.2", + "resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.86.2.tgz", + "integrity": "sha512-7k8IAhgSnZuD9Zex2+ohHKY3aWGDd4ls0xlxMGl3/jPyHSSXrIYfmtJyUH0+DPd4B3psBqHC0Ev0/nZEHdW58w==", "dependencies": { "tslib": "2.8.1" }, @@ -2320,9 +2320,9 @@ } }, "node_modules/@supabase/functions-js": { - "version": "2.84.0", - "resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.84.0.tgz", - "integrity": "sha512-2oY5QBV4py/s64zMlhPEz+4RTdlwxzmfhM1k2xftD2v1DruRZKfoe7Yn9DCz1VondxX8evcvpc2udEIGzHI+VA==", + "version": "2.86.2", + "resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.86.2.tgz", + "integrity": "sha512-OLpy3NIlj7q3yGMFwUpPkDPJbRx4aU+u73SiXqiMnA5ARwzVcOReSzI2u4oOqioE+3ud0fRx7sRsfoklBwYOmg==", "dependencies": { "tslib": "2.8.1" }, @@ -2331,9 +2331,9 @@ } }, "node_modules/@supabase/postgrest-js": { - "version": "2.84.0", - "resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-2.84.0.tgz", - "integrity": "sha512-oplc/3jfJeVW4F0J8wqywHkjIZvOVHtqzF0RESijepDAv5Dn/LThlGW1ftysoP4+PXVIrnghAbzPHo88fNomPQ==", + "version": "2.86.2", + "resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-2.86.2.tgz", + "integrity": "sha512-KVgOF2QASvUfQnzMGAmxR7f3ZF/eZ8PFp2F5Q7SAPQlmB83FEaZ7C/QMzfVXXqkMbotfh96xcaBNSKnxowFObA==", "dependencies": { "tslib": "2.8.1" }, @@ -2342,9 +2342,9 @@ } }, "node_modules/@supabase/realtime-js": { - "version": "2.84.0", - "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.84.0.tgz", - "integrity": "sha512-ThqjxiCwWiZAroHnYPmnNl6tZk6jxGcG2a7Hp/3kcolPcMj89kWjUTA3cHmhdIWYsP84fHp8MAQjYWMLf7HEUg==", + "version": "2.86.2", + "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.86.2.tgz", + "integrity": "sha512-uLUYrOMeK1qXHISxdMFVfBs0sGV5PmqYewIHvLBnMYbb//LERojxfKlVSJBgZ+aAwxANmtQKcprjGZI7DJ6lNQ==", "dependencies": { "@types/phoenix": "^1.6.6", "@types/ws": "^8.18.1", @@ -2356,10 +2356,11 @@ } }, "node_modules/@supabase/storage-js": { - "version": "2.84.0", - "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.84.0.tgz", - "integrity": "sha512-vXvAJ1euCuhryOhC6j60dG8ky+lk0V06ubNo+CbhuoUv+sl39PyY0lc+k+qpQhTk/VcI6SiM0OECLN83+nyJ5A==", + "version": "2.86.2", + "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.86.2.tgz", + "integrity": "sha512-zyR4PkO7R4f4/xRBVJho3Dm7y4512BoCqGmD7LjNV2GVtWt8vEmambiuMB2Ty3l76mqw+ynQyHY8yFWSERrHXA==", "dependencies": { + "iceberg-js": "^0.8.0", "tslib": "2.8.1" }, "engines": { @@ -2367,15 +2368,15 @@ } }, "node_modules/@supabase/supabase-js": { - "version": "2.84.0", - "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.84.0.tgz", - "integrity": "sha512-byMqYBvb91sx2jcZsdp0qLpmd4Dioe80e4OU/UexXftCkpTcgrkoENXHf5dO8FCSai8SgNeq16BKg10QiDI6xg==", + "version": "2.86.2", + "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.86.2.tgz", + "integrity": "sha512-KXoiqFf7zZhL/+lj7oBFFUvVDQ6gy03v9wQ5E++f7xiJUuqmI4DuBhrv8uFo6B2EGTQTA3vkXjbxmYIug/zfWw==", "dependencies": { - "@supabase/auth-js": "2.84.0", - "@supabase/functions-js": "2.84.0", - "@supabase/postgrest-js": "2.84.0", - "@supabase/realtime-js": "2.84.0", - "@supabase/storage-js": "2.84.0" + "@supabase/auth-js": "2.86.2", + "@supabase/functions-js": "2.86.2", + "@supabase/postgrest-js": "2.86.2", + "@supabase/realtime-js": "2.86.2", + "@supabase/storage-js": "2.86.2" }, "engines": { "node": ">=20.0.0" @@ -2848,9 +2849,9 @@ } }, "node_modules/baseline-browser-mapping": { - "version": "2.8.29", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.29.tgz", - "integrity": "sha512-sXdt2elaVnhpDNRDz+1BDx1JQoJRuNk7oVlAlbGiFkLikHCAQiccexF/9e91zVi6RCgqspl04aP+6Cnl9zRLrA==", + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.4.tgz", + "integrity": "sha512-ZCQ9GEWl73BVm8bu5Fts8nt7MHdbt5vY9bP6WGnUh+r3l8M7CgfyTlwsgCbMC66BNxPr6Xoce3j66Ms5YUQTNA==", "dev": true, "bin": { "baseline-browser-mapping": "dist/cli.js" @@ -2879,9 +2880,9 @@ } }, "node_modules/browserslist": { - "version": "4.28.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.0.tgz", - "integrity": "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", "dev": true, "funding": [ { @@ -2899,11 +2900,11 @@ ], "peer": true, "dependencies": { - "baseline-browser-mapping": "^2.8.25", - "caniuse-lite": "^1.0.30001754", - "electron-to-chromium": "^1.5.249", + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", "node-releases": "^2.0.27", - "update-browserslist-db": "^1.1.4" + "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" @@ -2921,9 +2922,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001756", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001756.tgz", - "integrity": "sha512-4HnCNKbMLkLdhJz3TToeVWHSnfJvPaq6vu/eRP0Ahub/07n484XHhBF5AJoSGHdVrS8tKFauUQz8Bp9P7LVx7A==", + "version": "1.0.30001759", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001759.tgz", + "integrity": "sha512-Pzfx9fOKoKvevQf8oCXoyNRQ5QyxJj+3O0Rqx2V5oxT61KGx8+n6hV/IUyJeifUci2clnmmKVpvtiqRzgiWjSw==", "dev": true, "funding": [ { @@ -3215,9 +3216,9 @@ "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" }, "node_modules/electron-to-chromium": { - "version": "1.5.257", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.257.tgz", - "integrity": "sha512-VNSOB6JZan5IQNMqaurYpZC4bDPXcvKlUwVD/ztMeVD7SwOpMYGOY7dgt+4lNiIHIpvv/FdULnZKqKEy2KcuHQ==", + "version": "1.5.266", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.266.tgz", + "integrity": "sha512-kgWEglXvkEfMH7rxP5OSZZwnaDWT7J9EoZCujhnpLbfi0bbNtRkgdX2E3gt0Uer11c61qCYktB3hwkAS325sJg==", "dev": true }, "node_modules/esbuild": { @@ -3458,6 +3459,14 @@ "resolved": "https://registry.npmjs.org/highlightjs-vue/-/highlightjs-vue-1.0.0.tgz", "integrity": "sha512-PDEfEF102G23vHmPhLyPboFCD+BkMGu+GuJe2d9/eH4FsCwvgBpnc9n0pGE+ffKdph38s6foEZiEjdgHdzp+IA==" }, + "node_modules/iceberg-js": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/iceberg-js/-/iceberg-js-0.8.1.tgz", + "integrity": "sha512-1dhVQZXhcHje7798IVM+xoo/1ZdVfzOMIc8/rgVSijRK38EDqOJoGula9N/8ZI5RD8QTxNQtK/Gozpr+qUqRRA==", + "engines": { + "node": ">=20.0.0" + } + }, "node_modules/is-alphabetical": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", @@ -4032,9 +4041,9 @@ } }, "node_modules/react-remove-scroll": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.1.tgz", - "integrity": "sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz", + "integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==", "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", @@ -4520,9 +4529,9 @@ "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==" }, "node_modules/update-browserslist-db": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz", - "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.2.tgz", + "integrity": "sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==", "dev": true, "funding": [ { diff --git a/frontend/package.json b/frontend/package.json index aa1ff99..89da25f 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -5,7 +5,8 @@ "type": "module", "scripts": { "dev": "vite --host", - "build": "tsc && vite build", + "build": "vite build", + "typecheck": "tsc --noEmit", "preview": "vite preview" }, "dependencies": { diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 228b448..43ca19e 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -4,6 +4,8 @@ import { LoginPage } from './pages/LoginPage'; import { SignupPage } from './pages/SignupPage'; import { LandingPage } from './pages/LandingPage'; import { Dashboard } from './components/Dashboard'; +import { DocsHomePage } from './pages/DocsHomePage'; +import { MCPSetupPage } from './pages/MCPSetupPage'; function ProtectedRoute({ children }: { children: React.ReactNode }) { const { user, loading } = useAuth(); @@ -51,7 +53,7 @@ function AppRoutes() { element={user ? : } /> @@ -59,6 +61,17 @@ function AppRoutes() { } /> + {/* Documentation Routes - Public, no auth required */} + } /> + } /> + + {/* Placeholder routes for future docs pages */} + } /> + } /> + } /> + } /> + } /> + {/* Fallback */} } /> diff --git a/frontend/src/components/dashboard/Sidebar.tsx b/frontend/src/components/dashboard/Sidebar.tsx index 8aede9f..98a9d02 100644 --- a/frontend/src/components/dashboard/Sidebar.tsx +++ b/frontend/src/components/dashboard/Sidebar.tsx @@ -47,6 +47,7 @@ interface NavItem { name: string href: string icon: React.ReactNode + external?: boolean } const mainNavItems: NavItem[] = [ @@ -55,7 +56,7 @@ const mainNavItems: NavItem[] = [ ] const bottomNavItems: NavItem[] = [ - { name: 'Documentation', href: '/docs', icon: }, + { name: 'Documentation', href: '/docs', icon: , external: true }, { name: 'Settings', href: '/dashboard/settings', icon: }, ] @@ -70,23 +71,49 @@ export function Sidebar({ collapsed, onToggle }: SidebarProps) { return location.pathname === href } - const NavLink = ({ item }: { item: NavItem }) => ( - - - {item.icon} - - {!collapsed && ( - {item.name} - )} - - ) + const NavLink = ({ item }: { item: NavItem }) => { + // External links open in new tab + if (item.external) { + return ( + + + {item.icon} + + {!collapsed && ( + <> + {item.name} + + + + + )} + + ) + } + + return ( + + + {item.icon} + + {!collapsed && ( + {item.name} + )} + + ) + } return (