A community-driven Q&A platform for developers — ask questions, share knowledge, and grow together.
- Overview
- Features
- Tech Stack
- Project Structure
- Database Schema
- API Routes
- Getting Started
- Key Implementation Details
- Screenshots
CodeVerse is a full-stack developer Q&A web application inspired by Stack Overflow. It was built as a hands-on project to explore and deeply understand modern Next.js patterns — including the App Router, Server Actions, Server Components, and API Routes — alongside tools like NextAuth.js, MongoDB/Mongoose, and the Vercel AI SDK.
Users can ask and answer programming questions, vote on content, bookmark questions, follow tags, and discover developer jobs. An integrated AI assistant powered by Groq (Llama 3.1) can generate markdown-formatted answers to help get the conversation started.
- Credential-based sign-up/sign-in with bcrypt password hashing
- OAuth via Google and GitHub (NextAuth.js v5)
- Secure session management with JWT; middleware-protected routes
- Create, edit, and delete questions with a rich MDX editor
- Tag questions with up to 3 relevant tags (auto-created if new)
- Question-level filtering: Newest, Popular, Unanswered, Recommended
- Paginated listing with server-side search
- Post and edit answers using the full-featured MDX editor
- Sort answers by Newest, Oldest, or Most Popular
- Each answer contributes to the author's reputation score
- One-click AI answer generation using Groq (Llama 3.1 8B Instant)
- Takes the question title, content, and the user's draft answer as context
- Returns a well-structured markdown response with code blocks, headings, and lists
- Upvote and downvote both questions and answers
- Toggle votes: clicking the same vote again removes it; switching vote type is handled atomically via MongoDB transactions
- Vote counts are reflected in real-time across the UI
- Save any question to a personal collection
- Filter saved questions by Oldest, Most Voted, Most Viewed, Most Recent, Most Answered
- Browse all tags with question counts
- Filter by A-Z, Recent, Oldest, or Popular
- Clicking a tag shows all associated questions
- Unified search bar in the navbar searches across Questions, Answers, Users, and Tags simultaneously
- Results are filtered by type via quick-select chips
- Browse all registered users with search and filter support
- View any user's public profile
- Displays bio, location, portfolio link, and join date
- Shows reputation score and earned badges (Gold, Silver, Bronze)
- Tabbed view of the user's Questions and Answers
- Top tags derived from the user's question activity
| Action | Performer | Content Author |
|---|---|---|
| Upvote a post | +2 | +10 |
| Downvote a post | -1 | -2 |
| Post a question | — | +5 |
| Post an answer | — | +10 |
| Delete a question | — | -5 |
| Delete an answer | — | -10 |
- The "Recommended" feed analyzes a logged-in user's recent interaction history (views, upvotes, bookmarks, posts) to surface questions matching their interests
- Searches developer jobs via the JSearch API (RapidAPI)
- Auto-detects the user's country via IP geolocation
- Jobs display employment type, company, location, and a direct apply link
- Dark / Light / System theme switching (next-themes)
- Top-progress-bar for navigation feedback (nextjs-toploader)
- Toast notifications (Sonner)
- Responsive layout with Left and Right sidebars
- Skeleton loading states and graceful empty-state renderers
| Category | Technology |
|---|---|
| Framework | Next.js 15 (App Router) |
| Language | TypeScript 5 |
| UI Library | React 19 |
| Styling | Tailwind CSS 4, tailwind-merge, tailwindcss-animate |
| Component Primitives | Radix UI (Alert Dialog, Avatar, Dialog, Dropdown, Label, Select, Slot, Tabs) |
| Component Library | shadcn/ui |
| Icons | Lucide React, Radix Icons, Devicon (CDN) |
| Rich Text Editor | @mdxeditor/editor, next-mdx-remote, Bright (syntax highlighting) |
| Database | MongoDB (Atlas) |
| ODM | Mongoose 8 |
| Authentication | NextAuth.js v5 (Credentials + OAuth) |
| Password Hashing | bcryptjs |
| AI / LLM | Vercel AI SDK (ai, @ai-sdk/groq) — Llama 3.1 8B Instant via Groq |
| Form Handling | react-hook-form, @hookform/resolvers |
| Validation | Zod |
| Date Formatting | Day.js |
| URL State | query-string |
| Slug Generation | slugify |
| Logging | Pino, pino-pretty |
| Linting / Formatting | ESLint 9, Prettier |
| Deployment | Vercel |
CodeVerse-app/
├── app/
│ ├── (auth)/ # Authentication route group
│ │ ├── layout.tsx # Centered card layout with brand imagery
│ │ ├── sign-in/page.tsx
│ │ └── sign-up/page.tsx
│ ├── (root)/ # Main application route group
│ │ ├── layout.tsx # Navbar + LeftSidebar + RightSidebar shell
│ │ ├── page.tsx # Home — all questions feed
│ │ ├── ask-question/page.tsx
│ │ ├── questions/[id]/
│ │ │ ├── page.tsx # Question detail with answers
│ │ │ └── edit/page.tsx
│ │ ├── collection/page.tsx # Saved questions (auth-gated)
│ │ ├── community/page.tsx # All users
│ │ ├── tags/
│ │ │ ├── page.tsx # All tags
│ │ │ └── [id]/page.tsx # Questions by tag
│ │ ├── profile/
│ │ │ ├── [id]/page.tsx # Public profile
│ │ │ └── edit/page.tsx # Edit own profile (auth-gated)
│ │ └── jobs/page.tsx # Developer job listings
│ ├── api/
│ │ ├── auth/[...nextauth]/route.ts # NextAuth handler
│ │ ├── auth/signin-with-oauth/route.ts
│ │ ├── ai/answers/route.ts # Groq AI answer generation
│ │ ├── accounts/route.ts
│ │ ├── accounts/[id]/route.ts
│ │ ├── accounts/provider/route.ts
│ │ ├── users/route.ts
│ │ ├── users/[id]/route.ts
│ │ └── users/email/route.ts
│ ├── fonts/ # Local Inter & Space Grotesk variable fonts
│ ├── globals.css # Tailwind base + CSS custom properties
│ ├── layout.tsx # Root layout (SessionProvider, ThemeProvider)
│ └── not-found.tsx
│
├── components/
│ ├── cards/ # QuestionCard, AnswerCard, TagCard, UserCard, JobCard
│ ├── filters/ # CommonFilter, HomeFilter
│ ├── forms/ # AuthForm, QuestionForm, ProfileForm, SocialAuthForm, AnswerForm
│ ├── navigation/
│ │ ├── navbar/ # Top navigation bar + GlobalSearch
│ │ ├── LeftSidebar.tsx # Main nav links
│ │ └── RightSidebar.tsx # Hot questions + Popular tags
│ ├── search/ # LocalSearch, GlobalSearch, GlobalResult
│ ├── answers/ # AllAnswers component
│ ├── questions/ # SaveQuestion, HotQuestions
│ ├── votes/ # Votes (upvote/downvote UI)
│ ├── user/ # Stats, ProfileLink
│ ├── editor/ # MDXEditor wrapper
│ ├── ui/ # shadcn/ui primitives
│ ├── DataRenderer.tsx # Generic success/error/empty state renderer
│ ├── Pagination.tsx
│ ├── Metric.tsx
│ └── UserAvatar.tsx
│
├── database/
│ ├── index.ts # Barrel export for all models
│ ├── user.model.ts
│ ├── account.model.ts
│ ├── question.model.ts
│ ├── answer.model.ts
│ ├── tag.model.ts
│ ├── tag-question.model.ts # Many-to-many junction
│ ├── vote.model.ts
│ ├── collection.model.ts # Bookmarks
│ └── interaction.model.ts # Drives recommendations & reputation
│
├── lib/
│ ├── actions/ # Next.js Server Actions
│ │ ├── auth.action.ts
│ │ ├── question.action.ts
│ │ ├── answer.action.ts
│ │ ├── vote.action.ts
│ │ ├── collection.action.ts
│ │ ├── tag.action.ts
│ │ ├── user.action.ts
│ │ ├── general.action.ts # Global search
│ │ ├── interaction.action.ts # Reputation updates
│ │ └── job.action.ts # RapidAPI JSearch
│ ├── handlers/
│ │ ├── action.ts # Auth + validation middleware for Server Actions
│ │ ├── error.ts # Unified error formatter (API & server)
│ │ └── fetch.ts # Typed fetch wrapper
│ ├── http-errors.ts # Custom error classes
│ ├── mongoose.ts # Singleton MongoDB connection
│ ├── validations.ts # Zod schemas
│ ├── utils.ts # Helpers (cn, formatNumber, getTimestamp, etc.)
│ ├── url.ts # URL query string helpers
│ ├── api.ts # Client-side API helpers
│ └── logger.ts # Pino logger setup
│
├── constants/
│ ├── routes.ts # Typed route map
│ ├── filters.ts # Filter option arrays per page
│ ├── states.ts # Empty-state configs
│ ├── techMap.ts # Technology → Devicon class mapping
│ └── notFound.ts
│
├── context/
│ └── Theme.tsx # next-themes ThemeProvider wrapper
│
├── types/
│ ├── global.d.ts # Shared interfaces (Question, Answer, User, Job, etc.)
│ └── action.d.ts # Server Action parameter types
│
├── public/
│ ├── icons/ # SVG icon set
│ └── images/ # Logos, auth background, illustrations
│
├── auth.ts # NextAuth.js configuration
├── middleware.ts # Route protection via NextAuth middleware
├── next.config.ts
├── tailwind.config.ts
└── tsconfig.json
CodeVerse uses MongoDB with Mongoose ODM. All models use timestamps (createdAt, updatedAt).
┌─────────────────────────────────────────────────────────────────────┐
│ User │ Account │
│────────────────────── │────────────────────────────────────── │
│ name: String │ userId: ObjectId → User │
│ username: String (uniq) │ name: String │
│ email: String (uniq) │ image: String? │
│ bio: String? │ password: String? (hashed) │
│ image: String? │ provider: String (credentials/google/ │
│ location: String? │ github) │
│ portfolio: String? │ providerAccountId: String │
│ reputation: Number = 0 └────────────────────────────────────── │
└─────────────────────────────────────────────────────────────────────┘
┌───────────────────────────────────────────────────────────────────────────┐
│ Question │ Tag │
│────────────────────────────── │────────────────────────────── │
│ title: String │ name: String (unique) │
│ content: String (MDX) │ questions: Number = 0 │
│ tags: ObjectId[] → Tag └────────────────────────────── │
│ author: ObjectId → User │
│ views: Number = 0 TagQuestion (junction) │
│ upvotes: Number = 0 ───────────────────────── │
│ downvotes: Number = 0 tag: ObjectId → Tag │
│ answers: Number = 0 question: ObjectId → Question │
└───────────────────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────────────────────┐
│ Answer │ Vote │
│──────────────────────────── │──────────────────────────────────────── │
│ author: ObjectId → User │ author: ObjectId → User │
│ question: ObjectId → Question │ actionId: ObjectId (question or answer) │
│ content: String (MDX) │ actionType: "question" | "answer" │
│ upvotes: Number = 0 │ voteType: "upvote" | "downvote" │
│ downvotes: Number = 0 └──────────────────────────────────────── │
└────────────────────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────────────────────┐
│ Collection (Bookmark) │ Interaction │
│──────────────────────────── │──────────────────────────────────────── │
│ author: ObjectId → User │ user: ObjectId → User │
│ question: ObjectId → Question │ action: "view"|"upvote"|"downvote"| │
│ │ "bookmark"|"post"|"edit"| │
│ │ "delete"|"search" │
│ │ actionId: ObjectId │
│ │ actionType: "question" | "answer" │
└────────────────────────────────────────────────────────────────────────────┘
All REST endpoints live under app/api/. Server Actions in lib/actions/ handle the majority of mutations.
| Method | Endpoint | Description |
|---|---|---|
GET/POST |
/api/auth/[...nextauth] |
NextAuth.js authentication handler |
POST |
/api/auth/signin-with-oauth |
OAuth sign-in — create or link account |
POST |
/api/ai/answers |
Generate an AI answer via Groq (Llama 3.1) |
GET/POST |
/api/accounts |
List / create accounts |
GET/PUT/DELETE |
/api/accounts/[id] |
Get / update / delete a specific account |
GET |
/api/accounts/provider |
Look up an account by provider + providerAccountId |
GET/POST |
/api/users |
List / create users |
GET/PUT/DELETE |
/api/users/[id] |
Get / update / delete a specific user |
GET |
/api/users/email |
Look up a user by email address |
- Node.js 18.17 or later
- npm 10+ (specified as
packageManagerinpackage.json) - A MongoDB Atlas cluster (or a local MongoDB instance)
- A Groq API key (for AI answer generation) — console.groq.com
- A RapidAPI key with access to the JSearch API (for the jobs page)
- (Optional) Google and GitHub OAuth credentials for social login
-
Clone the repository
git clone https://github.com/theShihamAhamed/CodeVerse-app.git cd CodeVerse-app -
Install dependencies
npm install
Create a .env.local file in the root of the project and populate it with the following:
# ─── MongoDB ──────────────────────────────────────────────────────────────────
MONGODB_URI=mongodb+srv://<username>:<password>@<cluster>.mongodb.net/?retryWrites=true&w=majority
# ─── NextAuth ─────────────────────────────────────────────────────────────────
# Generate with: openssl rand -base64 32
AUTH_SECRET=your_nextauth_secret
# ─── OAuth Providers ──────────────────────────────────────────────────────────
# Google: https://console.developers.google.com/
AUTH_GOOGLE_ID=your_google_client_id
AUTH_GOOGLE_SECRET=your_google_client_secret
# GitHub: https://github.com/settings/developers
AUTH_GITHUB_ID=your_github_client_id
AUTH_GITHUB_SECRET=your_github_client_secret
# ─── Groq (AI Answer Generation) ──────────────────────────────────────────────
# https://console.groq.com/
GROQ_API_KEY=your_groq_api_key
# ─── RapidAPI (Job Listings) ──────────────────────────────────────────────────
# https://rapidapi.com/letscrape-6bRBa3QguO5/api/jsearch
NEXT_PUBLIC_RAPID_API_KEY=your_rapidapi_key
# ─── App URL ──────────────────────────────────────────────────────────────────
NEXTAUTH_URL=http://localhost:3000Note: The
NEXT_PUBLIC_prefix onRAPID_API_KEYmakes it accessible in the browser. All other secrets stay server-side only.
npm run devOpen http://localhost:3000 in your browser. The app uses Turbopack (next dev --turbo) for fast refresh.
Other scripts:
npm run build # Production build
npm run start # Start production server
npm run lint # Run ESLintAll data mutations (creating questions, voting, bookmarking) are implemented as Next.js Server Actions in lib/actions/. Each action goes through a central action() handler in lib/handlers/action.ts that validates the payload against a Zod schema and optionally checks for an authenticated session before executing.
Operations that touch multiple collections atomically — such as creating a question (which also creates/upserts tags and TagQuestion junction records), deleting a question (which cascades to answers, votes, and collections), and voting (which updates the Vote document and the counter on the Question/Answer) — all use Mongoose transactions to guarantee consistency.
The "Recommended" feed works by:
- Fetching the logged-in user's last 50 interactions of type
view,upvote,bookmark, orpost. - Collecting all tags from those interacted questions.
- Querying for unread questions (excluding already-interacted ones and the user's own) that share those tags, sorted by upvotes and views.
Every meaningful user action triggers createInteraction(), which records an Interaction document and calls updateReputation(). This uses User.bulkWrite() to atomically update both the performer's and the content author's reputation in a single database round-trip.
The /api/ai/answers route receives the question title, MDX content, and an optional user draft. It uses the Vercel AI SDK (generateText with @ai-sdk/groq) to call the Llama 3.1 8B Instant model on Groq, instructing it to produce a concise, markdown-formatted response that incorporates the user's draft if it is correct.
A unified handleError() function in lib/handlers/error.ts normalises any error — whether a custom RequestError subclass (Validation, NotFound, Forbidden, Unauthorized), a ZodError, or an unknown runtime error — into a consistent { success: false, error: { message, details } } shape for both API responses (NextResponse.json) and Server Action returns.
NextAuth.js v5 is configured in auth.ts with a credentials provider (email + bcrypt) and google/github OAuth providers. The middleware.ts file re-exports the NextAuth auth function directly as the middleware, protecting routes transparently. An Account model separates auth-provider details from the User model, allowing one user to have multiple linked providers.