A full-stack internship management platform built with Next.js, Clerk (authentication), and Supabase (database). Students can browse and apply for internships, mentors can post and review applications, and admins can manage the entire platform.
- Prerequisites
- Tech Stack
- Getting Started
- Environment Variables (.env.local)
- Database Setup
- Clerk Webhook Setup
- Running the App
- User Roles & Routes
- Project Structure
- Troubleshooting
Make sure you have the following installed before you begin:
| Tool | Version | Download |
|---|---|---|
| Node.js | v18 or higher | https://nodejs.org |
| npm | v8 or higher | npm i |
| Git | Latest | https://git-scm.com |
You also need free accounts on:
- Clerk — https://clerk.com (authentication)
- Supabase — https://supabase.com (database)
- Framework: Next.js 16 (App Router)
- Language: TypeScript
- Styling: Tailwind CSS + shadcn/ui
- Auth: Clerk
- Database: Supabase (PostgreSQL)
- Package Manager: pnpm
git clone <repo-url>
cd Intern2Earnnpm installIf you run into peer dependency issues, try:
pnpm install --legacy-peer-deps
Create a file named .env.local in the root of the project:
touch .env.localThen paste the following template and fill in your own keys:
# ─── Clerk Authentication ─────────────────────────────────────────────────────
# Get these from https://dashboard.clerk.com → Your App → API Keys
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
CLERK_SECRET_KEY=sk_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# Clerk redirect URLs (leave these as-is)
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/auth/login
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/auth/sign-up
NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/dashboard/student
NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/onboarding
# ─── Supabase ─────────────────────────────────────────────────────────────────
# Get these from https://app.supabase.com → Your Project → Settings → API
NEXT_PUBLIC_SUPABASE_URL=https://xxxxxxxxxxxxxxxxxxxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.xxxxxx
SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.xxxxxx
# ─── Clerk Webhook ────────────────────────────────────────────────────────────
# Get this from https://dashboard.clerk.com → Webhooks → your endpoint → Signing Secret
CLERK_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx- Go to https://dashboard.clerk.com
- Select your application (create one if you haven't)
- Click API Keys in the left sidebar
- Copy Publishable key →
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY - Copy Secret key →
CLERK_SECRET_KEY
- Go to https://app.supabase.com
- Select your project (create one if you haven't — choose a region close to you)
- Go to Settings → API
- Copy Project URL →
NEXT_PUBLIC_SUPABASE_URL - Copy anon / public key →
NEXT_PUBLIC_SUPABASE_ANON_KEY - Copy service_role / secret key →
SUPABASE_SERVICE_ROLE_KEY
Important: Never commit
.env.localto Git. It is already in.gitignore.
You need to run SQL migration scripts in Supabase SQL Editor to create all the tables.
- Go to https://app.supabase.com → your project
- Click SQL Editor in the left sidebar
- Click New Query
Copy and paste the contents of each file below into the SQL editor and click Run:
| Order | File | Description |
|---|---|---|
| 1 | scripts/001_create_tables.sql |
Creates all tables (profiles, internships, applications, submissions, progress, messages, certificates) |
| 2 | scripts/002_create_profile_trigger.sql |
Adds a trigger to auto-create a profile on user signup |
| 3 | scripts/003_add_certificate_constraint.sql |
Adds constraints to the certificates table |
Run them one by one in order. Do not skip any.
After running the migrations, go to Authentication → Policies in Supabase and enable RLS on all tables to restrict access appropriately.
The webhook sends user data from Clerk to Supabase automatically when someone signs up.
- Install ngrok to expose your local server:
npm install -g ngrok ngrok http 3000
- Copy the ngrok HTTPS URL (e.g.
https://abc123.ngrok.io)
- Go to https://dashboard.clerk.com → Webhooks
- Click Add Endpoint
- Set the URL to:
https://<your-ngrok-or-domain>/api/webhooks/clerk - Under Subscribe to events, check:
user.created - Click Create
- Copy the Signing Secret (starts with
whsec_) - Add it to
.env.localasCLERK_WEBHOOK_SECRET
Use your live domain instead of ngrok: https://yourdomain.vercel.app/api/webhooks/clerk
# Development mode (with hot reload)
pnpm devOpen your browser at http://localhost:3000
# Build for production
pnpm build
# Start production server
pnpm startAfter signing up, users complete an onboarding flow to choose their role.
| Route | Description |
|---|---|
/dashboard/student |
Overview, stats, recent activity |
/internships |
Browse available internships |
/applications |
Track your applications |
/submissions |
Submit project work |
/progress |
Weekly progress logs |
/certificates |
Download earned certificates |
| Route | Description |
|---|---|
/dashboard/mentor |
Overview of your internships |
/internships/manage |
Create and manage internships |
/applicants |
Review student applications |
/submissions/review |
Review student submissions |
| Route | Description |
|---|---|
/dashboard/admin |
Platform statistics |
/admin/users |
Manage all users |
/admin/internships |
Manage all internships |
/admin/applications |
Review all applications |
/admin/reports |
Generate reports |
Intern2Earn/
├── app/ # Next.js App Router pages
│ ├── api/ # API routes (webhooks, certificates)
│ ├── auth/ # Login & sign-up pages
│ ├── dashboard/ # Role-specific dashboards
│ ├── admin/ # Admin pages
│ └── ... # Other feature pages
├── components/ # Reusable React components
│ └── ui/ # shadcn/ui component library
├── hooks/ # Custom React hooks
├── lib/ # Utility functions
│ ├── auth/ # Auth helpers
│ ├── clerk/ # Clerk client helpers
│ └── supabase/ # Supabase client helpers
├── scripts/ # SQL migration files
├── types/ # TypeScript type definitions
├── middleware.ts # Route protection middleware
└── .env.local # Your environment variables (not committed)
Try clearing the cache and reinstalling:
pnpm store prune
pnpm install- Make sure
.env.localexists in the project root - Make sure
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEYis set correctly - Restart the dev server after editing
.env.local
- Verify the webhook is configured in Clerk Dashboard
- Check that
CLERK_WEBHOOK_SECRETmatches the signing secret in Clerk - For local dev, make sure ngrok is running and the URL is up to date in Clerk
- Run the scripts in order:
001→002→003 - If a table already exists and causes an error, the scripts use
IF NOT EXISTSso re-running is safe - Check the Supabase Logs tab for detailed error messages
# Run on a different port
pnpm dev -- -p 3001