## AI Coding Master Prompt: CodeSearch Pro MVP (Next.js)
**1. PROJECT OVERVIEW:**
CodeSearch Pro is a powerful, cloud-based code search platform designed to address the critical need for speed and efficiency in navigating large and complex codebases. Inspired by the performance gains demonstrated by tools like ripgrep, but delivered through an intuitive web interface, CodeSearch Pro allows developers to index multiple code repositories (from platforms like GitHub, GitLab, Bitbucket, or even private SFTP servers) and perform lightning-fast text and regular expression searches across them. It solves the problem of fragmented search tools, slow search performance, and the difficulty of cross-repository searching. The core value proposition is to drastically reduce the time developers spend finding specific code, bugs, or patterns, thereby boosting productivity and accelerating development cycles. The MVP will focus on core indexing, blazing-fast search, and result management.
**2. TECH STACK:**
* **Framework:** Next.js (App Router)
* **Language:** TypeScript
* **Styling:** Tailwind CSS
* **ORM:** Drizzle ORM (with PostgreSQL adapter for PlanetScale/Neon.tech)
* **UI Library:** shadcn/ui (for accessible, reusable components)
* **Authentication:** NextAuth.js (for OAuth with GitHub/Google and email/password)
* **Database:** PostgreSQL (e.g., PlanetScale, Neon.tech)
* **Search Backend:** Leverage Rust implementation of ripgrep (potentially via a separate microservice or serverless function for intensive indexing/searching tasks) OR optimize Drizzle ORM's full-text search capabilities with PostgreSQL extensions if direct ripgrep integration proves too complex for MVP.
* **State Management:** React Context API and Server State (e.g., `use` hook in App Router) for client-side state, with server actions for mutations.
* **Deployment:** Vercel
* **Other Packages:** `zod` for validation, `react-hook-form` for forms, `lucide-react` for icons, `clsx` for class name manipulation.
**3. DATABASE SCHEMA (Drizzle ORM - PostgreSQL):**
```typescript
// schema.ts
import { pgTable, uuid, varchar, timestamp, text, boolean, primaryKey, integer, foreignKey } from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm';
// User Authentication Tables
export const users = pgTable('users', {
id: uuid('id').primaryKey().defaultRandom(),
name: varchar('name'),
email: varchar('email', { length: 255 }).notNull().unique(),
emailVerified: timestamp('emailVerified'),
image: varchar('image'),
hashedPassword: text('hashedPassword'), // For email/password auth
});
export const accounts = pgTable('accounts', {
id: uuid('id').primaryKey().defaultRandom(),
userId: uuid('userId').notNull().references(() => users.id, { onDelete: 'cascade' }),
type: varchar('type', { enum: ['oauth', 'email'] }).notNull(),
provider: varchar('provider', { length: 255 }).notNull(),
providerAccountId: varchar('providerAccountId', { length: 255 }).notNull(),
refresh_token: text('refresh_token'),
access_token: text('access_token'),
expires_at: integer('expires_at'),
token_type: varchar('token_type'),
scope: varchar('scope'),
id_token: text('id_token'),
session_state: varchar('session_state'),
}, (t) => ({
userProviderProviderAccountIdIndex: primaryKey(t.userId, t.provider, t.providerAccountId)
}));
export const sessions = pgTable('sessions', {
sessionToken: varchar('sessionToken', { length: 255 }).primaryKey(),
userId: uuid('userId').notNull().references(() => users.id, { onDelete: 'cascade' }),
expires: timestamp('expires', { mode: 'date' }).notNull(),
});
export const verificationTokens = pgTable('verificationTokens', {
identifier: varchar('identifier', { length: 255 }).notNull(),
token: varchar('token', { length: 255 }).notNull(),
expires: timestamp('expires', { mode: 'date' }).notNull(),
}, (t) => ({
identifierTokenIndex: primaryKey(t.identifier, t.token)
}));
// Application Specific Tables
export const repositories = pgTable('repositories', {
id: uuid('id').primaryKey().defaultRandom(),
userId: uuid('userId').notNull().references(() => users.id, { onDelete: 'cascade' }),
name: varchar('name', { length: 255 }).notNull(),
url: varchar('url', { length: 1024 }).notNull(), // e.g., git@github.com:user/repo.git or https://github.com/user/repo.git
type: varchar('type', { enum: ['github', 'gitlab', 'bitbucket', 'sftp'] }).notNull(),
lastIndexedAt: timestamp('lastIndexedAt'),
isIndexed: boolean('isIndexed').default(false),
createdAt: timestamp('createdAt').defaultNow(),
updatedAt: timestamp('updatedAt').defaultNow(),
});
export const searchQueries = pgTable('searchQueries', {
id: uuid('id').primaryKey().defaultRandom(),
userId: uuid('userId').notNull().references(() => users.id, { onDelete: 'cascade' }),
repositoryId: uuid('repositoryId').references(() => repositories.id, { onDelete: 'set null' }), // Can be null for global search
query: text('query').notNull(), // The actual search string or regex
searchType: varchar('searchType', { enum: ['text', 'regex'] }).notNull(),
filePathFilter: varchar('filePathFilter'), // Optional file path filter
caseSensitive: boolean('caseSensitive').default(false),
savedAs: varchar('savedAs', { length: 255 }), // Name for saved query
createdAt: timestamp('createdAt').defaultNow(),
});
export const searchResults = pgTable('searchResults', {
id: uuid('id').primaryKey().defaultRandom(),
searchQueryId: uuid('searchQueryId').references(() => searchQueries.id, { onDelete: 'cascade' }),
filePath: varchar('filePath', { length: 1024 }).notNull(),
lineNumber: integer('lineNumber').notNull(),
lineContent: text('lineContent').notNull(),
repositoryId: uuid('repositoryId').references(() => repositories.id, { onDelete: 'cascade' }),
createdAt: timestamp('createdAt').defaultNow(),
});
// Relations (Example)
export const userRelations = relations(users, ({ many }) => ({
repositories: many(repositories),
searchQueries: many(searchQueries),
}));
export const repositoryRelations = relations(repositories, ({ one, many }) => ({
user: one(users, {
fields: [repositories.userId],
references: [users.id]
}),
searchQueries: many(searchQueries),
searchResults: many(searchResults)
}));
export const searchQueryRelations = relations(searchQueries, ({ one, many }) => ({
user: one(users, {
fields: [searchQueries.userId],
references: [users.id]
}),
repository: one(repositories, {
fields: [searchQueries.repositoryId],
references: [repositories.id]
}),
results: many(searchResults)
}));
export const searchResultRelations = relations(searchResults, ({ one }) => ({
searchQuery: one(searchQueries, {
fields: [searchResults.searchQueryId],
references: [searchQueries.id]
}),
repository: one(repositories, {
fields: [searchResults.repositoryId],
references: [repositories.id]
})
}));
```
**4. CORE FEATURES & USER FLOW:**
* **User Authentication:**
* Flow: User lands on the homepage -> Clicks 'Sign Up' or 'Login' -> Presented with GitHub, Google OAuth buttons and Email/Password form -> Upon successful login, redirected to the dashboard.
* Details: Use NextAuth.js. Store user info in `users` table. Handle sessions securely.
* **Repository Management:**
* Flow: User logs in -> Navigates to 'Repositories' page -> Clicks 'Add Repository' -> Selects repo type (GitHub, etc.) -> Provides URL and authentication details (e.g., PAT for GitHub) -> Repository is added to the `repositories` table, marked as `isIndexed: false`.
* Details: Server actions handle adding/deleting repos. For GitHub, use GitHub API with Personal Access Tokens (PATs). Indexing will be an asynchronous background process.
* **Indexing Process:**
* Flow: User adds a repository -> A background job (e.g., triggered by a server action or a separate worker process) fetches the repository content -> Uses a ripgrep-like engine (or optimized PostgreSQL full-text search) to index file contents -> Updates `repositories.lastIndexedAt` and `repositories.isIndexed = true`.
* Details: This is CPU/IO intensive. Consider a dedicated Rust service or a serverless function for this. For MVP, initial indexing might be done on the server side after cloning/downloading the repo.
* **Code Searching:**
* Flow: User is on the Dashboard -> Enters search query in the main search bar -> Selects repositories to search (or searches globally if enabled) -> Specifies search type (text/regex), case sensitivity, file path filters -> Clicks 'Search' -> Search results are displayed paginated on the dashboard.
* Details: Utilize Server Actions to trigger search. The backend (ripgrep-like engine or DB query) performs the search against indexed data. Results are stored in `searchResults` for quick retrieval and displayed using components.
* **Saved Queries:**
* Flow: User performs a search -> Clicks 'Save Query' -> Enters a name for the query -> Query is saved in the `searchQueries` table, linked to the user and optionally a repository.
* Details: Saved queries appear on a 'Saved Searches' page, allowing users to re-run them quickly.
* **Edge Cases:**
* **No Repositories:** Dashboard shows a prompt to add repositories.
* **Indexing in Progress:** Repository list shows an 'Indexing...' status. Search might be partially available or disabled for that repo.
* **Search Found No Results:** Display a clear 'No results found' message.
* **Authentication Errors:** Handle invalid PATs or OAuth connection issues gracefully.
* **Validation:** Use Zod for all form inputs (repo URL, search queries, login/signup).
**5. API & DATA FETCHING:**
* **Approach:** Primarily use Next.js App Router's Server Actions for mutations (adding repos, saving queries) and data fetching for dynamic content on the server. Use Server Components where possible for initial page loads and Client Components with `fetch` or libraries like SWR/React Query for interactive client-side data needs (e.g., live search updates if implemented).
* **Key Endpoints/Actions:
* `POST /api/repositories`: Add a new repository (Server Action).
* `DELETE /api/repositories/[id]`: Remove a repository (Server Action).
* `GET /api/repositories`: Fetch list of user's repositories (Server Component).
* `POST /api/search`: Perform a search query (Server Action, accepts query params, repo IDs, filters).
* `POST /api/search/save`: Save a current search query (Server Action).
* `GET /api/search/saved`: Fetch user's saved queries (Server Component).
* `GET /api/search/results/[queryId]`: Fetch paginated search results (Server Component or API Route).
* **Data Flow:** Client requests data -> Server Action/Component fetches data from DB/external services (ripgrep engine) -> Data is processed and returned to the client -> UI updates.
**6. COMPONENT BREAKDOWN (Next.js App Router Structure):**
* **`app/layout.tsx`:** Root layout (includes providers, global styles, auth provider setup).
* **`app/page.tsx`:** Landing Page (Marketing content, features, call to action).
* **`app/(auth)/login/page.tsx`:** Login page.
* **`app/(auth)/signup/page.tsx`:** Sign up page.
* **`app/dashboard/page.tsx`:** Main application view after login.
* **`components/ui/SearchBar.tsx`:** Input, regex toggle, filters button.
* **`components/ui/RepositorySelector.tsx`:** Multi-select dropdown/list for repositories.
* **`components/ui/SearchResultsList.tsx`:** Displays paginated search results. Each item shows file path, line number, and content snippet.
* **`components/ui/SearchResultItem.tsx`:** Renders a single search result line.
* **`components/ui/SaveQueryButton.tsx`:** Button to save the current search.
* **`components/ui/LoadingSpinner.tsx`:** Global or specific loading indicator.
* **`app/repositories/page.tsx`:** Page to manage connected repositories.
* **`components/ui/RepositoryTable.tsx`:** Displays user's repositories with status (Indexed, Indexing, Error) and actions (Remove, Re-index).
* **`components/forms/AddRepositoryForm.tsx`:** Form to add new repositories.
* **`app/saved-searches/page.tsx`:** Page listing and managing saved search queries.
* **`components/ui/SavedQueryList.tsx`:** Displays saved queries with options to run or delete.
* **`app/settings/page.tsx`:** User profile and settings.
* **`components/layout/Navbar.tsx`:** Main navigation bar.
* **`components/layout/Sidebar.tsx`:** Optional sidebar for navigation.
* **`components/ui/Button.tsx`, `components/ui/Input.tsx`, `components/ui/Card.tsx`, etc.:** Reusable UI components from shadcn/ui.
**7. UI/UX DESIGN & VISUAL IDENTITY:**
* **Design Style:** Modern, Clean, and Functional. Minimalist aesthetic with a focus on clarity and performance perception.
* **Color Palette:**
* Primary: `#007AFF` (Vibrant Blue for CTAs, active states)
* Secondary: `#6C757D` (Gray for subtle UI elements, disabled states)
* Accent/Code: `#FF4500` (Orange-Red for highlights, regex matches, important alerts)
* Background: `#F8F9FA` (Light Gray for main background)
* Dark Mode Background: `#1A1A1A` (Near Black)
* Text (Light): `#212529` (Dark Gray)
* Text (Dark): `#E0E0E0` (Light Gray)
* **Typography:**
* Headings: Inter (e.g., `Inter SemiBold`)
* Body Text: Inter (e.g., `Inter Regular`)
* Code/Monospace: JetBrains Mono or Fira Code
* **Layout:**
* Dashboard: Primarily a content-focused layout. Search bar prominently at the top, followed by results. Sidebar for navigation.
* Use of cards for search results, repository info.
* Clear separation of sections using whitespace and subtle borders.
* **Responsive Rules:** Mobile-first approach. Sidebar collapses into a hamburger menu on smaller screens. Search bar and results adapt to screen width. Ensure usability on devices down to 375px width.
**8. SAMPLE/MOCK DATA:**
* **User:**
* `{ id: 'uuid-user-1', name: 'Alice Developer', email: 'alice@example.com', image: 'https://...' }`
* **Repository:**
* `{ id: 'uuid-repo-1', userId: 'uuid-user-1', name: 'my-awesome-api', url: 'git@github.com:alice/my-awesome-api.git', type: 'github', isIndexed: true, lastIndexedAt: '2023-10-27T10:00:00Z' }`
* `{ id: 'uuid-repo-2', userId: 'uuid-user-1', name: 'legacy-service', url: '/path/to/legacy-service', type: 'sftp', isIndexed: false, lastIndexedAt: null }`
* **Search Query (Saved):**
* `{ id: 'uuid-query-1', userId: 'uuid-user-1', repositoryId: 'uuid-repo-1', query: 'getUserById', searchType: 'text', filePathFilter: 'src/**/*.ts', savedAs: 'Find User Getters' }`
* **Search Result:**
* `{ id: 'uuid-result-1', searchQueryId: 'uuid-query-1', repositoryId: 'uuid-repo-1', filePath: 'src/services/userService.ts', lineNumber: 42, lineContent: 'async function getUserById(userId: string): Promise<User | null> {' }`
* `{ id: 'uuid-result-2', searchQueryId: 'uuid-query-1', repositoryId: 'uuid-repo-1', filePath: 'src/routes/userRoutes.ts', lineNumber: 105, lineContent: ' const user = await getUserById(req.params.id);' }`
**9. TURKISH TRANSLATIONS:**
* **App Title:** CodeSearch Pro
* **Sign Up:** Kayıt Ol
* **Login:** Giriş Yap
* **Logout:** Çıkış Yap
* **Dashboard:** Kontrol Paneli
* **Repositories:** Depolarım
* **Add Repository:** Depo Ekle
* **Search:** Ara
* **Saved Searches:** Kayıtlı Aramalar
* **Settings:** Ayarlar
* **Search Query:** Arama Sorgusu
* **File Path:** Dosya Yolu
* **Case Sensitive:** Büyük/Küçük Harfe Duyarlı
* **Search Type:** Arama Türü
* **Text:** Metin
* **Regex:** Regex
* **Save Query:** Sorguyu Kaydet
* **Indexed:** İndekslendi
* **Indexing...:** İndeksleniyor...
* **Error:** Hata
* **No results found:** Sonuç bulunamadı.
* **Add New Repository:** Yeni Depo Ekle
* **Repository URL:** Depo URL'si
* **Connect:** Bağla
* **Remove:** Kaldır
* **Re-index:** Yeniden İndele
**10. ANIMATIONS:**
* Subtle fade-in/out transitions for page loads and component mounting/unmounting using Next.js `Suspense` and libraries like `Framer Motion` if needed.
* Hover effects on buttons and interactive elements (slight scale or background color change).
* Loading indicators (spinners, skeleton loaders) for asynchronous operations like search execution and data fetching.
* Smooth scrolling for search result navigation.
**11. EDGE CASES & VALIDATION (Reiteration & Detail):**
* **Authentication:** Implement robust error handling for OAuth failures, invalid credentials. Ensure session management is secure (e.g., using secure cookies, short expiry for access tokens).
* **Repository Connection:** Validate URLs. Handle different authentication methods per repo type (PAT for GitHub, SSH keys for SFTP, etc.). Provide clear error messages if connection or indexing fails.
* **Search Input:** Validate query length, regex syntax errors (using `zod` or similar). Prevent excessively long or complex regex that could degrade performance.
* **Empty States:** Design informative empty states for Dashboard (no repos added), Repositories (no repos connected), and Saved Searches (no queries saved).
* **Permissions:** Ensure users can only access/manage their own repositories and search history. For team features (future), implement proper RBAC.
* **Rate Limiting:** Implement rate limiting for external API calls (e.g., GitHub API) and potentially for search queries to prevent abuse.
* **Data Integrity:** Use database transactions where appropriate (e.g., when saving a query and its initial results).
* **Error Boundaries:** Implement React Error Boundaries to catch unexpected errors in UI components and display a user-friendly fallback.
This detailed prompt aims to guide the AI in generating a comprehensive, fully functional, multi-page Next.js MVP application for CodeSearch Pro, adhering to modern best practices and the specified tech stack.