Thanks for your interest in contributing! InternHack is a full-stack career platform and we welcome contributions of all kinds, bug fixes, new features, docs, and design improvements.
This guide walks you through everything from setting up the project to submitting your first PR.
💬 Join our WhatsApp community: Contributors Group
Hop in to discuss ideas, ask for guidance on a PR, get unstuck, share what you're working on, or just get to know the other contributors. Whether you're picking up your first
good first issueor shipping a major feature, it's the fastest way to get a response and meet the people building InternHack with you.
- Before You Start
- Development Setup
- Understanding the Codebase
- Making Changes
- Code Style Guide
- Submitting a Pull Request
- What to Contribute
- Need Help?
- Read the README, Understand what InternHack does and the tech stack
- Browse existing issues, Look for
good first issueorhelp wantedlabels - Check open PRs, Make sure no one else is already working on the same thing
- Use the app, Visit internhack.xyz to understand user flows before touching code
| Tool | Version | Purpose |
|---|---|---|
| Node.js | 18+ | Runtime |
| npm | 9+ | Package manager |
| PostgreSQL | 14+ | Database |
| Git | 2.30+ | Version control |
Docker Compose shortcut: You can run Postgres + API + client with only Docker by following the README “Docker Compose (alternative)” section (root .env.example plus docker compose up). That path does not use Redis — the app stack is PostgreSQL only.
You'll also need:
- A Google Cloud Console project for OAuth (client ID)
- A Gemini API key (free at aistudio.google.com)
# Fork the repo on GitHub, then:
git clone https://github.com/Sachinchaurasiya360/InternHack
cd InternHackDocker Compose: copy the template at the repo root:
cp .env.example .envClassic setup: separate client and server copies:
cp server/.env.example server/.env
cp client/.env.example client/.envOpen server/.env and fill in the required values:
DATABASE_URL=postgresql://user:password@localhost:5432/internhack
JWT_SECRET=any-random-string-at-least-64-chars-long
GOOGLE_CLIENT_ID=your-google-oauth-client-id
GEMINI_API_KEY=your-gemini-api-key
ALLOWED_ORIGINS=http://localhost:5173Open client/.env and fill in:
VITE_GOOGLE_CLIENT_ID=your-google-oauth-client-idNote: Only the variables above are required. Features like S3 uploads, payments, email, and code execution will degrade gracefully without their keys.
# Install server dependencies
cd server && npm install
# Install client dependencies (in a new terminal)
cd client && npm installPrisma config lives at server/src/database/prisma.config.ts, so run all Prisma commands from server/src/database/:
cd server/src/database
# Generate the Prisma client
npx prisma generate
# Push the schema to your database (creates all tables)
npx prisma db pushcd server
# Seed everything, users, DSA, aptitude, companies, badges, skill tests,
# hackathons, open-source repos, gov internships, and blog posts
npm run seed
# Or seed only an admin + recruiter account
# (set ADMIN_EMAIL and ADMIN_PASSWORD in .env first)
npm run seed:adminThe unified seed script lives at
server/src/database/seeds/seed.ts. It is idempotent, you can run it multiple times without creating duplicates. Default login for all seeded users isTest@1234.Seeded accounts:
Role admin@internhack.xyzAdmin recruiter@internhack.xyzRecruiter aarav@example.comStudent priya@example.comStudent rohan@example.comStudent sneha@example.comStudent arjun@example.comStudent
# Terminal 1, Backend (port 3000)
cd server && npm run dev
# Terminal 2, Frontend (port 5173)
cd client && npm run devOpen http://localhost:5173, you're ready to develop!
User (Browser)
│
├── React Frontend (Vite, port 5173)
│ └── Zustand stores, React Query, React Router
│
└── Express API (port 3000)
├── Middleware (auth, role, rate-limit, validation)
├── Modules (routes → controller → service)
├── Prisma ORM → PostgreSQL
└── External APIs (Gemini, S3, Resend, etc.)
Every backend feature follows the same structure:
server/src/module/<name>/
├── <name>.routes.ts # Route definitions + middleware
├── <name>.controller.ts # Request handling, calls service
├── <name>.service.ts # Business logic, DB queries
└── <name>.validation.ts # Zod schemas for input validation
To trace a feature: Start at the route file, follow the controller method, then the service method. Validation schemas show you exactly what inputs are expected.
client/src/module/<area>/
├── <PageName>.tsx # Page components
└── components/ # Page-specific sub-components
Shared components live in client/src/components/. State management uses Zustand (lib/*.store.ts) and data fetching uses React Query.
| File | What it tells you |
|---|---|
server/src/index.ts |
All API routes, middleware order, CORS setup |
client/src/App.tsx |
All frontend routes and lazy-loaded pages |
server/src/database/prisma/schema/base.prisma |
Core database models |
client/src/lib/types.ts |
Client-side TypeScript interfaces |
.claude/REPO_MAP.md |
Detailed map of every module and file |
Let's say you want to understand how "Apply to Job" works:
- Client route, Find the page in
App.tsx→JobDetailPage - API call, In the page component, look for
api.post("/student/jobs/:id/apply") - Server route,
server/src/module/student/student.routes.ts→ find the POST route - Controller,
student.controller.ts→applyToJob()method - Service,
student.service.ts→applyToJob(), the actual business logic - Database, Check
applicationmodel inbase.prisma
This pattern works for every feature.
feat/short-description # New features
fix/short-description # Bug fixes
docs/short-description # Documentation
refactor/short-description # Code improvements
# Create a branch from main
git checkout main
git pull origin main
git checkout -b feat/your-feature-name
# Make your changes, then:
git add <specific-files>
git commit -m "feat: short description of what and why"
# Push and open a PR
git push origin feat/your-feature-name- Create or update
<name>.routes.ts, define the route with middleware - Create or update
<name>.controller.ts, handle request/response - Create or update
<name>.service.ts, write the business logic - Create or update
<name>.validation.ts, add Zod schemas - Register routes in
server/src/index.tsif it's a new module
- Create the page component in
client/src/module/<area>/<PageName>.tsx - Add a lazy import in
client/src/App.tsx - Add the route in the appropriate route group (public / student / recruiter / admin)
- Edit the schema in
server/src/database/prisma/schema/ - Run
npx prisma generatefromserver/src/database/ - Run
npx prisma db pushto apply changes - Do not create migrations without discussing first, we use
db pushfor development
- Strict mode is enabled on both client and server
- Use Zod for all server-side input validation
- Use proper types, avoid
anywhere possible
- Use canonical TailwindCSS v4 class names
- Use
bg-linear-to-*instead ofbg-gradient-* - Don't use arbitrary values like
text-[17px], use the standard scale - No gradient backgrounds on icons, use flat colors
- Company avatars: first-letter initial in a neutral box, not a generic icon
- No pill badges (
rounded-full) above page headings - Dark mode support on all new components
Use conventional commits:
feat: add external job pagination
fix: theme toggle not persisting on route change
docs: update contributing guide
refactor: extract email templates to utils
Keep messages short (under 72 chars), focused on what and why.
Before opening a PR, verify:
- Your code compiles without new TypeScript errors
- You tested the feature manually in the browser
- You didn't commit
.envfiles, credentials, ornode_modules - You added dark mode support if your change includes UI
- Database changes use
db push, not migrations (for now)
## Summary
- Brief description of what changed and why
## Changes
- List of specific changes
## How to test
- Steps to test this PR locally
## Screenshots (if UI changes)
- Before/after screenshots- Open a PR against
main - Fill in the PR template
- A maintainer will review within a few hour
- Address feedback, push updates to the same branch
- Once approved, a maintainer will merge
Look for issues labeled good first issue, these are scoped, well-defined tasks suitable for newcomers.
- Bug fixes, Found something broken? Fix it!
- UI improvements, Better responsive behavior, accessibility, animations
- New learning content, DSA problems, aptitude questions, skill test questions
- Documentation, Improve code comments, API docs, or this guide
- Performance, Optimize slow queries, reduce bundle size, add caching
- Testing, Add unit or integration tests (we currently have minimal coverage)
- Accessibility, Improve keyboard navigation, screen reader support, ARIA labels
- i18n, Help internationalize the platform for non-English speakers
| Area | Description |
|---|---|
| Testing | Unit tests for services, integration tests for API routes |
| Accessibility | ARIA labels, keyboard navigation, contrast ratios |
| Mobile UX | Improve experience on smaller screens |
| Documentation | API docs, inline code comments |
| SEO | Meta tags, structured data, sitemap improvements |
- Read the codebase guide, internhack.xyz/student/opensource/read-codebase has a step-by-step approach to understanding unfamiliar codebases
- Check
.claude/REPO_MAP.md, Detailed map of every module, route, and component - Open a discussion, Ask questions in GitHub Discussions
- Open an issue, If you're unsure about something, ask before building
Thank you for contributing to InternHack! Every contribution, no matter how small, helps students find better career opportunities.