Campus prediction markets for college students
Hunch is a prediction market platform built for college communities. Students can create markets, trade on outcomes, and compete on leaderboards—all using virtual karma points.
- Prediction Markets — Create Yes/No or multi-outcome markets
- Pari-mutuel Trading — Odds adjust based on pool distribution
- Karma Points — Virtual currency for risk-free trading
- College Scoping — Markets filtered by campus
- Live Countdown Timers — Real-time countdown to market resolution
- Price History Charts — Track odds changes over time
- Personal Stats Dashboard — Win rate, ROI, streaks, monthly performance
- Trending Markets — Surface hot markets based on 24h activity
Markets are organized by category:
- ⚽ Sports
- 📚 Academics
- 🏫 Campus Life
- 🎬 Entertainment
- 🗳️ Politics
- 🌤️ Weather
- 💡 Other
- Rate limiting on all endpoints
- Content moderation (profanity filter, spam detection)
- Audit logging for sensitive actions
- Input validation with length limits
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router) |
| Language | TypeScript |
| Database | PostgreSQL (Supabase) |
| ORM | Prisma |
| Auth | Better-Auth (Google OAuth) |
| Styling | Tailwind CSS |
| UI Components | Radix UI |
| Charts | Recharts |
| Analytics | Vercel Analytics |
- Node.js 18+
- PostgreSQL database (we recommend Supabase)
- Google OAuth credentials
-
Clone the repository
git clone https://github.com/yourusername/hunch.git cd hunch -
Install dependencies
npm install
-
Set up environment variables
cp .env.example .env.local
Fill in your values (see Environment Variables)
-
Run database migrations
npx prisma migrate dev
-
Start the development server
npm run dev
Create a .env.local file with:
# Database (Supabase PostgreSQL)
DATABASE_URL="postgresql://postgres.[project-ref]:[password]@aws-0-[region].pooler.supabase.com:6543/postgres?pgbouncer=true"
# Google OAuth
GOOGLE_CLIENT_ID="your-google-client-id"
GOOGLE_CLIENT_SECRET="your-google-client-secret"
# Better-Auth
BETTER_AUTH_SECRET="your-random-secret-min-32-chars"
BETTER_AUTH_URL="http://localhost:3000"
# App URL
NEXT_PUBLIC_APP_URL="http://localhost:3000"Supabase Database:
- Create a project at supabase.com
- Go to Settings → Database → Connection string
- Use the "Session pooler" connection string (port 6543)
- Add
?pgbouncer=trueto the end
Google OAuth:
- Go to Google Cloud Console
- Create a new project
- Enable Google+ API
- Create OAuth 2.0 credentials
- Add authorized redirect URI:
http://localhost:3000/api/auth/callback/google
├── prisma/
│ ├── schema.prisma # Database schema
│ └── migrations/ # Migration history
├── public/ # Static assets
├── src/
│ ├── app/
│ │ ├── api/ # API routes
│ │ │ ├── auth/ # Authentication endpoints
│ │ │ ├── leaderboard/
│ │ │ ├── markets/ # Market CRUD + resolve/cancel
│ │ │ ├── me/ # Current user endpoints
│ │ │ ├── trades/ # Place trades
│ │ │ ├── users/ # User profiles
│ │ │ └── wallet/ # Wallet data
│ │ ├── markets/[id]/ # Market detail page
│ │ ├── profile/[id]/ # User profile page
│ │ ├── wallet/ # Wallet page
│ │ └── page.tsx # Homepage
│ ├── components/
│ │ ├── ui/ # Base UI components
│ │ └── *.tsx # Feature components
│ └── lib/
│ ├── auth.ts # Better-Auth config
│ ├── prisma.ts # Prisma client
│ ├── categories.ts # Market categories
│ ├── colleges.ts # College definitions
│ ├── rate-limit.ts # Rate limiting
│ ├── content-moderation.ts
│ └── audit-log.ts # Audit logging
└── package.json
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/markets |
List markets (filterable) |
| POST | /api/markets |
Create market |
| GET | /api/markets/[id] |
Get market details |
| GET | /api/markets/[id]/stats |
Get market statistics |
| GET | /api/markets/[id]/history |
Get price history |
| POST | /api/markets/[id]/resolve |
Resolve market (creator only) |
| POST | /api/markets/[id]/cancel |
Cancel & refund (creator only) |
| GET | /api/markets/trending |
Get trending markets |
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/trades |
Place a trade |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/me |
Get current user |
| GET | /api/me/stats |
Get personal statistics |
| PUT | /api/me/campus |
Update campus |
| GET | /api/users/[id] |
Get user profile |
| GET | /api/wallet |
Get wallet & positions |
| GET | /api/leaderboard |
Get leaderboard |
- All trades go into a shared pool
- Odds are determined by pool distribution
- Winners split the pool proportionally to their stake
- No house edge—100% of karma is redistributed
- Created — Market is open for trading
- Resolution Time — Trading closes
- Resolved — Creator picks winning outcome
- Settled — Karma distributed to winners
- New users start with 1,000 karma
- Karma is virtual (no real money)
- Win karma by making correct predictions
- Compete on leaderboards
# Run migrations
npx prisma migrate dev
# Open Prisma Studio
npx prisma studio
# Generate client after schema changes
npx prisma generate
# Reset database
npx prisma migrate resetnpm run lintnpm run build- Push to GitHub
- Import project in Vercel
- Add environment variables
- Deploy
Important: For production, update:
BETTER_AUTH_URL→ your production URLNEXT_PUBLIC_APP_URL→ your production URL- Google OAuth redirect URIs
MIT
Contributions welcome! Please read our contributing guidelines first.
- Fork the repository
- Create a feature branch
- Make your changes
- Submit a pull request
Built with ❤️ for college students