You are tasked with building a fully functional, multi-page MVP web application using Next.js (App Router), Tailwind CSS, and Drizzle ORM. The application, named 'Idea Weaver', is a collaborative knowledge base and discovery platform for Large Language Models (LLMs), inspired by Andrej Karpathy's 'LLM Wiki' concept. It aims to help AI researchers, developers, and enthusiasts organize, share, and discover information about LLMs, research papers, tools, and concepts through user-created 'idea files'.
**1. PROJECT OVERVIEW:**
Idea Weaver aims to solve the problem of information fragmentation and discoverability within the rapidly evolving LLM ecosystem. It provides a centralized, community-driven platform where users can create, share, and explore structured 'idea files' related to LLMs. The core value proposition is to make it easier for individuals and teams to stay updated, find relevant resources, and collaborate on understanding the latest advancements in LLM technology.
**2. TECH STACK:**
- **Framework:** Next.js (App Router)
- **Styling:** Tailwind CSS
- **ORM:** Drizzle ORM (with PostgreSQL via Vercel Postgres or a similar provider)
- **UI Components:** shadcn/ui (for pre-built, accessible components like buttons, forms, dialogs, cards, input, etc.)
- **Authentication:** NextAuth.js (for OAuth providers like Google, GitHub)
- **State Management:** React Context API or Zustand (for global state, if needed)
- **Database:** PostgreSQL (via Vercel Postgres, Supabase, or self-hosted)
- **Form Handling:** React Hook Form
- **Validation:** Zod
- **Deployment:** Vercel (recommended)
**3. DATABASE SCHEMA (Drizzle ORM - PostgreSQL):**
```typescript
// schema.ts
import { pgTable, serial, text, timestamp, integer, varchar, boolean, primaryKey, uuid }
from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm';
import { createId } from '@paralleldrive/cuid2';
// Users Table
export const users = pgTable('users', {
id: uuid('id').primaryKey().default(cuid()), // Using cuid for unique IDs
name: text('name'),
email: text('email').notNull().unique(),
emailVerified: timestamp('emailVerified', { mode: 'date' }),
image: text('image'),
});
// User relations
export const userRelations = relations(users, ({ many }) => ({
ideaFiles: many(ideaFiles),
comments: many(comments),
votes: many(votes),
}));
// Accounts Table (for NextAuth.js)
export const accounts = pgTable(
'accounts',
{
acc_id: cuid('id'), // Changed name to avoid conflict with users.id
userId: uuid('userId').notNull().references(() => users.id, { onDelete: 'cascade' }),
type: varchar('type', { length: 256 }).notNull(),
provider: varchar('provider', { length: 256 }).notNull(),
providerAccountId: varchar('providerAccountId', { length: 256 }).notNull(),
refresh_token: text('refresh_token'),
access_token: text('access_token'),
expires_at: integer('expires_at'),
token_type: varchar('token_type', { length: 256 }),
scope: text('scope'),
id_token: text('id_token'),
session_state: varchar('session_state', { length: 256 })
},
(account) => ({
pk: primaryKey(account.provider, account.providerAccountId),
})
);
// Session Table (for NextAuth.js)
export const sessions = pgTable('sessions', {
sessionToken: varchar('sessionToken', { length: 256 }).primaryKey(),
userId: uuid('userId').notNull().references(() => users.id, { onDelete: 'cascade' }),
expires: timestamp('expires', { mode: 'date' }).notNull()
});
// Verification Token Table (for NextAuth.js)
export const verificationTokens = pgTable('verification_tokens', {
identifier: text('identifier').notNull(),
token: text('token').notNull(),
expires: timestamp('expires', { mode: 'date' }).notNull(),
}, (
verificationToken
) => ({
pk: primaryKey(verificationToken.identifier, verificationToken.token)
}));
// Idea Files Table
export const ideaFiles = pgTable('idea_files', {
id: uuid('id').primaryKey().default(cuid()),
userId: uuid('userId').notNull().references(() => users.id, { onDelete: 'cascade' }),
title: varchar('title', { length: 255 }).notNull(),
content: text('content').notNull(), // Markdown content
tags: text('tags').array(), // Array of tags
createdAt: timestamp('createdAt', { mode: 'date', withTimezone: true }).defaultNow(),
updatedAt: timestamp('updatedAt', { mode: 'date', withTimezone: true }).defaultNow(),
});
// IdeaFiles relations
export const ideaFileRelations = relations(ideaFiles, ({ one, many }) => ({
user: one(users, { fields: [ideaFiles.userId], aliases: ['ideaFiles'] }),
comments: many(comments),
votes: many(votes),
}));
// Comments Table
export const comments = pgTable('comments', {
id: uuid('id').primaryKey().default(cuid()),
ideaFileId: uuid('ideaFileId').notNull().references(() => ideaFiles.id, { onDelete: 'cascade' }),
userId: uuid('userId').notNull().references(() => users.id, { onDelete: 'cascade' }),
content: text('content').notNull(),
createdAt: timestamp('createdAt', { mode: 'date', withTimezone: true }).defaultNow(),
});
// Comments relations
export const commentRelations = relations(comments, ({ one }) => ({
ideaFile: one(ideaFiles, { fields: [comments.ideaFileId], aliases: ['comments'] }),
user: one(users, { fields: [comments.userId], aliases: ['comments'] }),
}));
// Votes Table (for upvotes/downvotes on idea files)
export const votes = pgTable('votes', {
id: uuid('id').primaryKey().default(cuid()),
ideaFileId: uuid('ideaFileId').notNull().references(() => ideaFiles.id, { onDelete: 'cascade' }),
userId: uuid('userId').notNull().references(() => users.id, { onDelete: 'cascade' }),
voteType: integer('voteType').notNull(), // 1 for upvote, -1 for downvote
createdAt: timestamp('createdAt', { mode: 'date', withTimezone: true }).defaultNow(),
}, (
vote
) => {
return {
uniqueVote: primaryKey(vote.ideaFileId, vote.userId)
}
});
// Votes relations
export const voteRelations = relations(votes, ({ one }) => ({
ideaFile: one(ideaFiles, { fields: [votes.ideaFileId], aliases: ['votes'] }),
user: one(users, { fields: [votes.userId], aliases: ['votes'] }),
}));
// Helper function for cuid generation within Drizzle
function cuid(name?: string): import('drizzle-orm/pg-core').PgColumn<any, any, any> {
// This is a placeholder. In a real setup, you'd import and use the actual cuid generator.
// For simplicity in schema definition, we'll assume it works. The actual implementation
// will be in the insert/update logic or use a default factory.
// Example using a generic uuid if cuid is not directly supported as a default factory
// For production, ensure a proper cuid implementation or use uuid
// return uuid(name).default(sql`uuid_generate_v4()`); // For PostgreSQL UUID generation
// Or use a server-side generation like: `import { createId } from '@paralleldrive/cuid2'; ... id: uuid('id').primaryKey().default(createId())`
return text(name || 'id') as any; // Placeholder, replace with actual cuid or uuid
}
// Add necessary imports for relations and helper functions.
// Ensure 'cuid' function or equivalent is properly implemented and imported.
```
**4. CORE FEATURES & USER FLOW:**
**a. Authentication (NextAuth.js):**
- **Flow:** User lands on the homepage. Clicks 'Sign In'. Redirected to a sign-in page with options (Google, GitHub). Selects a provider. Redirected to provider's auth page. Upon success, redirected back to the app. User session is maintained via cookies.
- **Edge Cases:** Provider errors, network issues during redirect, session expiry.
**b. Create Idea File:**
- **Flow:** Authenticated user navigates to '/new-idea'. Clicks 'Create Idea File'. A form appears with fields: Title (input, required, max 255 chars), Content (textarea, supports Markdown, required), Tags (input, comma-separated, optional). User fills the form. Clicks 'Save'. Data is validated using Zod. Upon success, a POST request is made to the `/api/idea-files` endpoint. User is redirected to the newly created idea file's page (`/idea-files/[id]`).
- **Edge Cases:** Empty title/content, invalid tag format, exceeding character limits, network error during save.
**c. View Idea File:**
- **Flow:** User clicks on an idea file title from the list or search results. Navigates to `/idea-files/[id]`. The system fetches the idea file data (title, content, author, tags, comments, votes) from the API (`/api/idea-files/[id]`). The content is rendered as Markdown. Comments are displayed below, with an input for authenticated users to add new comments. Vote buttons (+/-) are visible for logged-in users.
- **Edge Cases:** Idea file not found (404), unauthorized access to private content (if implemented later), rendering issues with complex Markdown.
**d. List & Search Idea Files:**
- **Flow:** User lands on the 'Explore' page (`/explore`). The system fetches a paginated list of idea files via `/api/idea-files`. Results are displayed as cards (title, snippet, author, tags, vote count). A search bar is present at the top. User types keywords. As they type (or after hitting Enter), the list filters dynamically (or after a search request to `/api/idea-files?search=query`). Filtering by tags is also available via UI elements (e.g., clickable tags).
- **Edge Cases:** No results found, slow search performance, handling large numbers of idea files (pagination).
**e. Commenting & Voting:**
- **Flow (Commenting):** On an idea file page, an authenticated user types a comment in the input field and clicks 'Submit'. A POST request is sent to `/api/idea-files/[id]/comments`. On success, the new comment appears instantly in the comment list (optimistic UI update or re-fetch).
- **Flow (Voting):** Authenticated user clicks the upvote or downvote button. A POST request is sent to `/api/idea-files/[id]/votes` with the vote type. The vote count updates immediately. If the user already voted, clicking the same button un-votes, and clicking the opposite button changes their vote.
- **Edge Cases:** Non-authenticated user attempting to comment/vote, network errors during submission, duplicate votes (handled by backend logic).
**5. API & DATA FETCHING:**
- **Architecture:** Next.js App Router (Server Components for initial data fetching, Client Components for interactivity).
- **API Routes (App Router Handlers):**
- `POST /api/idea-files`: Create a new idea file. (Requires authentication)
- `GET /api/idea-files`: List idea files (supports pagination, search, tag filtering).
- `GET /api/idea-files/[id]`: Get a single idea file and its comments/votes.
- `PUT /api/idea-files/[id]`: Update an existing idea file. (Requires authentication & ownership)
- `DELETE /api/idea-files/[id]`: Delete an idea file. (Requires authentication & ownership)
- `POST /api/idea-files/[id]/comments`: Add a comment to an idea file. (Requires authentication)
- `POST /api/idea-files/[id]/votes`: Add or update a vote for an idea file. (Requires authentication)
- **Data Fetching:** Primarily use Server Components to fetch data directly from the database within the component (e.g., `page.tsx`, `layout.tsx`). Use Client Components (`'use client'`) for interactive elements like forms, buttons, and where client-side state management is necessary, fetching data via API routes or directly from the server using route handlers that return JSON.
- **Example Request/Response (Create Idea File):
- **Request:** `POST /api/idea-files` with JSON body `{ title: '...', content: '...', tags: [...] }`
- **Response (Success):** `201 Created` with `{ id: 'cuid_...', ... }`
- **Response (Error):** `400 Bad Request` or `500 Internal Server Error` with error details.
**6. COMPONENT BREAKDOWN (Next.js App Router Structure):**
- **`app/`**
- **`layout.tsx`:** Root layout (includes header, footer, global styles, AuthProvider).
- **`page.tsx`:** Homepage / Landing Page (brief intro, featured idea files, call to action).
- **`explore/page.tsx`:** Explore page (lists all idea files, search bar, tag filters, pagination).
- **`new-idea/page.tsx`:** Create new idea file form page (requires auth).
- **`idea-files/[id]/page.tsx`:** Individual idea file view page (displays title, content, comments, votes).
- **`auth/signin/page.tsx`:** Sign-in page (using NextAuth.js components).
- **`profile/[userId]/page.tsx`:** User profile page (displays user info, list of their idea files).
- **`_error.tsx`:** Custom error page.
- **`loading.tsx`:** Global loading indicator.
- **`components/`**
- **`ui/`:** Re-exported shadcn/ui components (Button, Input, Card, Dialog, Label, Textarea, etc.).
- **`auth/`:** SignIn/SignOut buttons, UserAvatar component.
- **`idea-files/`:**
- `IdeaFileCard.tsx`: Component to display a summary of an idea file in lists.
- `IdeaFileForm.tsx`: Form for creating/editing idea files (uses `react-hook-form`, `zod`).
- `MarkdownRenderer.tsx`: Component to render markdown content safely (e.g., using `react-markdown` with `remark-gfm`).
- `CommentSection.tsx`: Displays comments and the comment input form.
- `VoteButtons.tsx`: Renders upvote/downvote buttons.
- **`layout/`:**
- `Header.tsx`: Navigation, logo, user auth status.
- `Footer.tsx`: Copyright, links.
- **`common/`:**
- `SearchInput.tsx`
- `TagBadge.tsx`
- `Pagination.tsx`
- `Spinner.tsx`
- **`lib/`:** Utility functions, database connection setup (Drizzle), API client functions (if using client-side fetching).
- **`styles/`:** Global CSS or Tailwind config extensions.
- **`schemas/`:** Zod validation schemas for forms and API payloads.
**7. UI/UX DESIGN & VISUAL IDENTITY:**
- **Design Style:** Minimalist Clean with subtle modern touches. Focus on readability and clarity.
- **Color Palette:**
- Primary: Deep Navy (`#0A192F`)
- Secondary: Light Gray (`#CCD6F6`)
- Accent: Electric Blue (`#64FFDA`)
- Background: Off-White (`#F8F9FA`)
- Card/Surface: White (`#FFFFFF`)
- Text: Dark Gray (`#333333`) on light backgrounds, Secondary on dark.
- **Typography:** A clean sans-serif font like Inter or SF Pro for body text and headings. (e.g., `font-family: 'Inter', sans-serif;`)
- **Layout:** Generous whitespace. Content centered within max-width containers. Sidebar for navigation (if complexity increases) or top navigation bar. Clear visual hierarchy.
- **Components:** Utilize shadcn/ui components for consistency and accessibility. Subtle hover effects on interactive elements.
- **Responsiveness:** Mobile-first approach. Layouts should adapt seamlessly to various screen sizes (phones, tablets, desktops). Use Tailwind's responsive modifiers (`sm:`, `md:`, `lg:`, `xl:`).
- **Visual Elements:** Use clean icons, subtle gradients in the accent color for buttons or highlights. Avoid clutter.
**8. SAMPLE/MOCK DATA:**
1. **Idea File 1:**
* `id`: `clxabc123`
* `userId`: `user_xyz789`
* `title`: "GPT-4o: A New Era for Multimodal AI"
* `content`: "OpenAI's latest model, GPT-4o, brings unprecedented speed and multimodality, integrating text, audio, and vision processing seamlessly. Key advancements include real-time voice conversation capabilities and enhanced emotional intelligence."
* `tags`: `["LLM", "OpenAI", "Multimodal", "GPT-4o"]`
* `createdAt`: `2024-05-15T10:00:00Z`
2. **Idea File 2:**
* `id`: `clydef456`
* `userId`: `user_pqr123`
* `title`: "Llama 3 Performance Benchmarks"
* `content`: "Meta's Llama 3 models show significant improvements over Llama 2, achieving state-of-the-art performance on several key benchmarks, particularly the larger 70B parameter version."
* `tags`: `["LLM", "Meta", "Open Source", "Benchmarks", "Llama 3"]`
* `createdAt`: `2024-04-28T14:30:00Z`
3. **Comment 1 (on Idea File 1):**
* `id`: `cmtaaa789`
* `ideaFileId`: `clxabc123`
* `userId`: `user_pqr123`
* `content`: "The real-time aspect is truly impressive. I wonder how latency is managed."
* `createdAt`: `2024-05-15T11:05:00Z`
4. **Comment 2 (on Idea File 1):**
* `id`: `cmtbbb012`
* `ideaFileId`: `clxabc123`
* `userId`: `user_uvw456`
* `content`: "Agree, the potential for accessibility tools is huge."
* `createdAt`: `2024-05-15T11:15:00Z`
5. **Vote 1 (on Idea File 2):**
* `id`: `votexyz987`
* `ideaFileId`: `clydef456`
* `userId`: `user_abc123`
* `voteType`: `1` (Upvote)
* `createdAt`: `2024-04-29T09:00:00Z`
6. **User 1:**
* `id`: `user_xyz789`
* `name`: "Alex"
* `email`: "alex@example.com"
* `image`: "/images/avatars/alex.png"
7. **User 2:**
* `id`: `user_pqr123`
* `name`: "Dr. Evelyn Reed"
* `email`: "evelyn.reed@research.ai"
* `image`: "/images/avatars/evelyn.png"
**9. TURKISH TRANSLATIONS:**
- **App Title:** Fikir Dokumacı (Idea Weaver)
- **General:**
- 'Sign In' / 'Sign Up': 'Giriş Yap' / 'Kayıt Ol'
- 'Explore': 'Keşfet'
- 'New Idea File': 'Yeni Fikir Dosyası'
- 'Create': 'Oluştur'
- 'Save': 'Kaydet'
- 'Cancel': 'İptal'
- 'Search': 'Ara'
- 'Tags': 'Etiketler'
- 'Comments': 'Yorumlar'
- 'Add Comment': 'Yorum Ekle'
- 'Submit': 'Gönder'
- 'Upvote': 'Beğen'
- 'Downvote': 'Beğenme'
- 'No results found.': 'Sonuç bulunamadı.'
- 'Loading...': 'Yükleniyor...'
- 'Error': 'Hata'
- 'Something went wrong.': 'Bir şeyler ters gitti.'
- 'Go back home': 'Ana sayfaya dön'
- **Idea File:**
- 'Title': 'Başlık'
- 'Content': 'İçerik'
- 'by [User Name]': '[Kullanıcı Adı] tarafından'
- 'Edited': 'Düzenlendi'
- 'Published': 'Yayınlandı'
- **Profile:**
- 'My Ideas': 'Benim Fikirlerim'
- 'Settings': 'Ayarlar'
**10. ANIMATIONS:**
- **Page Transitions:** Use Next.js's built-in features or libraries like `Framer Motion` for subtle fade/slide transitions between pages.
- **Button Hovers:** Slight scale-up or background color change on hover (e.g., Accent color background on primary buttons).
- **Loading States:** Implement skeleton loaders for content cards and placeholders for images/text during data fetching. Use spinners (`Spinner.tsx`) for form submissions and critical operations.
- **Hover Effects:** Subtle lift/shadow effect on `IdeaFileCard.tsx` components when hovered.
- **Input Focus:** Tailwind's `focus:` variants for borders or box shadows on input fields.
**11. EDGE CASES:**
- **Authentication:** Handle users trying to access protected routes (`/new-idea`, `/profile/*`) without being logged in (redirect to `/auth/signin`). Display appropriate messages.
- **Empty States:** Design informative empty state UIs for when there are no idea files, no search results, no comments, or no user-created content. (e.g., "No idea files yet. Be the first to create one!")
- **Error Handling:** Implement robust error handling for API requests (display user-friendly messages). Use `try...catch` blocks and provide specific feedback for different error types (validation, server errors, network errors).
- **Form Validation:** Implement client-side (Zod) and server-side validation for all user inputs to ensure data integrity. Provide clear inline error messages.
- **Database Constraints:** Ensure uniqueness constraints (e.g., user email) and foreign key relationships are correctly defined and handled.
- **Rate Limiting:** Consider implementing rate limiting for API endpoints to prevent abuse.
- **Markdown Rendering:** Sanitize markdown input to prevent XSS attacks. Use libraries like `DOMPurify` if necessary, in addition to safe rendering practices.
- **Responsiveness:** Test thoroughly on different devices and screen sizes.
- **Accessibility (a11y):** Ensure all interactive elements have proper ARIA attributes, keyboard navigation is supported, and color contrast meets WCAG guidelines (partially handled by shadcn/ui).