A sophisticated developer portfolio platform that transforms your GitHub activity into a shareable, AI-enhanced professional profile.
GitProof 2 analyzes your public GitHub repositories, calculates impact metrics, generates AI-powered insights, and creates a beautiful public profile page to showcase your best work to recruiters and collaborators.
- Overview
- Features
- Tech Stack
- Getting Started
- Project Structure
- Architecture
- Database Schema
- API & Server Actions
- Component System
- Impact Score Algorithm
- AI Integration
- Authentication
- Security
- Configuration
- Development
- Deployment
- Contributing
GitProof 2 is a full-stack Next.js application that helps developers:
- Authenticate with GitHub - Secure OAuth integration
- Sync repository data - Fetch public repos, commits, stars, forks
- Calculate impact scores - Smart algorithm (0-50 scale) based on popularity, recency, and maturity
- Generate AI insights - Use Google Gemini to analyze strengths and growth areas
- Customize portfolio - Select featured projects, rewrite descriptions with AI
- Share public profiles - Beautiful, shareable profile pages at
/u/[username]
Live Example: /u/yourname shows your curated portfolio to the world.
- OAuth 2.0 integration with GitHub
- Identity-only OAuth scopes (
read:user,user:email) - Public-repo-only sync with no private-repository access
- Encrypted server-side token storage via Prisma and NextAuth
- Session persistence with JWT strategy
- Contribution heatmap - GitHub-style activity visualization
- Hourly activity chart - Discover your most productive hours
- Impact scores - Algorithmic ranking (0-50) for each repository
- Tech stack breakdown - Visual percentage bars for languages
- Top 6 repositories - Auto-selected by impact score
- Real-time sync - Manual refresh button with rate limit handling
- Featured project selection - Choose up to 6 projects to showcase
- AI description rewriting - Use Gemini to make descriptions recruiter-friendly
- Bio editor - Manual or AI-generated professional summary
- Visibility controls - Hide/show projects from public profile
- Live preview - See changes before publishing
- Bulk actions - Save all changes at once
- Project description rewriting - Context-aware using README, topics, and stats
- README generation - Analyzes repo structure, dependencies, and source code to generate comprehensive READMEs
- Bio generation - Summarizes your top projects into a professional bio
- Insight analysis - Detects strengths (consistency, expertise) and growth areas
- Powered by Gemini 2.5 Flash Lite - Fast, cost-effective LLM
- Shareable URLs -
/u/[username]for public access - Privacy controls - Toggle profile visibility on/off
- Featured projects showcase - Masonry grid layout
- Impact metrics display - Report card with scores
- Professional presentation - Clean, modern design with light/dark themes
- Impact Score - Weighted algorithm combining popularity, recency, maturity
- Consistency Metric - Percentage of active days in last year
- Developer Archetype - Classification (e.g., "The Architect", "10x Engineer")
- Growth Recommendations - AI-generated areas for improvement
- Top Technologies - Language and topic analysis
- Profile visibility - Public/private toggle
- Theme switching - Light, dark, or system preference
- Email notifications - Opt-in for product updates
- Account deletion - Complete data removal + GitHub OAuth revocation
- Session management - Sign out all devices
- Next.js 16.0.10 - React framework with App Router
- React 19.2.1 - UI library with Server Components
- TypeScript 5 - Type-safe JavaScript
- Tailwind CSS 4 - Utility-first styling
- shadcn/ui - Accessible component library (Radix UI)
- Framer Motion 12.23.26 - Animation library
- Lucide React 0.561.0 - Icon system (561+ icons)
- Next.js API Routes - RESTful endpoints
- Server Actions - Type-safe mutations with
"use server" - Prisma 5.22.0 - ORM for PostgreSQL
- PostgreSQL - Primary database
- NextAuth 5.0.0-beta.30 - Authentication
- GitHub GraphQL API - Repository and user data
- GitHub OAuth - Authentication provider
- Google Gemini 2.5 Flash Lite - AI text generation
- Recharts 3.5.1 - React charting library
- Victory Vendor - D3 components
- ESLint 9 - Code linting
- PostCSS - CSS transformation
- class-variance-authority - Component API builder
- Node.js 18+ - JavaScript runtime
- npm/yarn/pnpm - Package manager
- PostgreSQL - Database (local or hosted)
- GitHub OAuth App - Create one here
- Google AI API Key - Get one here
Clone the repository
git clone https://github.com/bgar324/gitproof-2 cd gitproof-2Install dependencies
npm install
Set up environment variables
Create a
.env.localfile in the root directory:# DatabaseDATABASE_URL="postgresql://user:password@localhost:5432/gitproof"# NextAuthAUTH_SECRET="generate-with-openssl-rand-base64-32"NEXTAUTH_URL="http://localhost:3000"# GitHub OAuthAUTH_GITHUB_ID="your_github_client_id"AUTH_GITHUB_SECRET="your_github_client_secret"# Google AIGOOGLE_GENERATIVE_AI_API_KEY="your_gemini_api_key"
Set up the database
npx prisma generate npx prisma db push
Run the development server
npm run dev
Open the app
Navigate to http://localhost:3000
- Go to GitHub Settings > Developer Settings > OAuth Apps
- Click New OAuth App
- Fill in:
- Application name: GitProof 2
- Homepage URL:
http://localhost:3000 - Authorization callback URL:
http://localhost:3000/api/auth/callback/github
- Click Register application
- Copy Client ID and Client Secret to
.env.local
gitproof-2/
├── app/ # Next.js App Router
│ ├── (app)/ # Protected routes (auth required)
│ │ ├── dashboard/ # Analytics & overview
│ │ ├── editor/ # Portfolio editor
│ │ ├── settings/ # Account settings
│ │ └── layout.tsx # App-wide navbar
│ ├── (marketing)/ # Public marketing pages
│ ├── api/ # API routes
│ │ ├── auth/ # NextAuth handlers
│ │ └── sync/ # Data sync endpoint
│ ├── u/[username]/ # Public profile pages
│ ├── manifesto/ # Info pages
│ ├── methodology/
│ ├── privacy/
│ ├── actions.ts # Server actions
│ ├── layout.tsx # Root layout
│ └── globals.css # Global styles
├── components/ # React components
│ ├── ui/ # shadcn/ui primitives
│ ├── dashboard/ # Dashboard components
│ ├── editor/ # Editor components
│ ├── profile/ # Profile components
│ ├── marketing/ # Landing page sections
│ ├── layout/ # Navbar, footer, wrappers
│ ├── settings/ # Settings sections
│ ├── shared/ # Reusable utilities
│ ├── report-card.tsx # Main report card
│ └── repo-modal.tsx # Repository modal
├── lib/ # Utilities & business logic
│ ├── github.ts # GitHub GraphQL client
│ ├── sync.ts # Repository sync logic
│ ├── stats.ts # Analytics calculations
│ ├── rate-limit.ts # GitHub API rate limiting
│ ├── sanitize.ts # Data sanitization
│ ├── utils.ts # Helper functions
│ ├── language-colors.ts # Language colors
│ ├── db.ts # Prisma client
│ └── data/ # Static data
├── prisma/
│ └── schema.prisma # Database schema
├── types/
│ └── next-auth.d.ts # NextAuth types
├── auth.ts # NextAuth config
├── middleware.ts # Route protection
├── next.config.ts # Next.js config
├── tailwind.config.ts # Tailwind config
└── package.json # Dependencies
Public Routes (no authentication)
├── / → Landing page
├── /methodology → How it works
├── /privacy → Privacy policy
├── /manifesto → Mission statement
├── /u/[username] → Public profile (if isPublic = true)
└── /api/auth/* → NextAuth OAuth callbacks
Protected Routes (requires authentication)
├── /dashboard → Analytics overview
├── /dashboard/repos → All repositories
├── /editor → Portfolio editor
└── /settings → Account settings
GitHub OAuth → NextAuth → Prisma → PostgreSQL
↓
User Session
↓
Authenticated Routes
↓
Server Components (DB queries)
↓
Client Components (interactivity)
↓
Server Actions (mutations)
↓
Database Updates
Server Components (default): Fetch data, render on server
app/(app)/dashboard/page.tsxapp/u/[username]/page.tsx
Client Components (
"use client"): Interactive UIapp/(app)/dashboard/view.tsxcomponents/dashboard/*components/editor/*
modelUser {idString@id@default(cuid())emailString@uniqueusernameString@uniquenameString?imageString?bioString?isPublicBoolean@default(false)emailNotificationsBoolean@default(false)lastSyncedAtDateTime?profileDataJson?// Cached GitHub datacreatedAtDateTime@default(now())updatedAtDateTime@updatedAtaccountsAccount[]sessionsSession[]projectsProject[]}modelProject {idString@id@default(cuid())userIdStringgithubIdIntnameStringdescString?urlStringhomepageString?languageString?topicsString[]starsInt@default(0)forksInt@default(0)lastPushDateTimeimpactScoreInt@default(0)// 0-50readmeString?// Original GitHub READMEaiDescriptionString?// AI-rewritten descriptionaiReadmeString?// AI-generated READMEisHiddenBoolean@default(false)createdAtDateTime@default(now())updatedAtDateTime@updatedAtuserUser@relation(fields: [userId], references: [id], onDelete: Cascade)@@index([userId])@@index([impactScore])@@index([lastPush])}modelAccount {idString@id@default(cuid())userIdStringproviderString// "github"providerAccountIdStringaccess_tokenString?// GitHub OAuth token// ... other OAuth fields}modelSession {idString@id@default(cuid())sessionTokenString@uniqueuserIdStringexpiresDateTime}No standalone sync endpoint. Repository syncing is performed through authenticated server actions that fetch directly from GitHub on the server.
Located in app/actions.ts:
| Action | Description |
|---|---|
triggerSync() | Force sync GitHub repos |
generateAIDescription(projectId) | Generate AI description |
generateReadme(projectId) | Generate AI README |
getProjectReadme(projectId) | Get original + generated README |
revertReadme(projectId) | Clear generated README |
toggleProfilePublic(isPublic) | Toggle profile visibility |
updateUserBio(bio) | Save user bio |
generateUserBio() | AI generate bio |
batchUpdateProjectVisibility() | Bulk update visibility |
updateProjectDescription() | Edit project desc |
deleteUserAccount() | Delete account + revoke OAuth |
activity-heatmap- Contribution calendardashboard-header- Top stats headerdashboard-repo-card- Repository cardfocus-hours-card- Hourly activity chartimpact-tooltip- Score explanationscore-modal- Algorithm breakdownstat-card- Metric displaytech-stack-card- Language barstime-range-selector- Filter controlstop-repos-header- Section header
editor-repo-card- Editable repo card with AI rewritefeatured-section- Featured projects manageridentity-section- Bio editorlibrary-section- All projects gridsave-button- Save changes button
readme-generator-modal- AI README generation with preview/raw/diff views
hero-section- Profile headerportfolio-section- Projects displaypublic-repo-card- Public repo card
shadcn/ui components: badge, button, card, dialog, dropdown-menu, input, label, separator, skeleton, switch, tabs, textarea, tooltip
The Impact Score (0-50) combines three weighted components:
Score = min(round(Popularity + Recency + Maturity), 50)
Logarithmic scale with increased multiplier to better reward popular projects:
Popularity=log₂(stars+forks×2+1)×4.5Popularity=min(Popularity,40)Examples:
- 100 stars, 10 forks → ~30 points
- 1,000 stars, 100 forks → ~45 points (capped at 40)
- 10,000 stars, 1,000 forks → ~60 points (capped at 40)
Graceful decay that rewards maintained projects, not just recently pushed:
< 7 days ago: +15 points (S-tier: Last week)
< 30 days ago: +12 points (A-tier: Last month)
< 90 days ago: +8 points (B-tier: Last quarter)
< 180 days ago: +5 points (C-tier: Last 6 months)
< 365 days ago: +2 points (D-tier: Last year)
else: +0 points (Abandoned)
Multi-factor assessment of project quality:
Description:
> 100 chars: +5 points (Detailed)
> 20 chars: +3 points (Basic)
README:
> 2000 chars: +5 points (Comprehensive)
> 500 chars: +3 points (Good)
> 100 chars: +1 point (Minimal)
Homepage: +3 points
Topics:
≥ 3 tags: +3 points (Well-tagged)
≥ 1 tag: +1 point (Basic)
Max: 15 points from maturity (capped)
Instead of a simple average, we use a weighted average of top 6 projects:
UserScore = top1×50% + top2×12.5% + top3×12.5% + top4×8.33% + top5×8.33% + top6×8.33%
This emphasizes quality over quantity - your best project carries 50% of the weight.
Repository: "awesome-react-hooks"
- Stars: 250, Forks: 30
- Last Push: 10 days ago
- Description: "Production-ready React hooks library"
- Homepage: https://awesome-hooks.dev
- Topics:
['react', 'hooks', 'typescript'] - README: 1,500 chars
Calculation:
Popularity = log₂(250 + 30×2 + 1) × 4.5 = 37 points (was ~25 with old formula)
Recency = 12 points (< 30 days, A-tier)
Maturity:
- Description (42 chars): +3
- README (1500 chars): +3
- Homepage: +3
- Topics (3 tags): +3
= 12 points
Total = 37 + 12 + 12 = 50 points (capped) ✨
Used for:
- Project description rewriting
- README generation
- User bio generation
- Insight analysis
GOOGLE_GENERATIVE_AI_API_KEY="your_api_key"The README generator analyzes your repository to create comprehensive, professional documentation.
lib/readme.ts → Repository context fetching (GraphQL)
app/actions.ts → Server actions (generateReadme, revertReadme)
components/modals/ → ReadmeGeneratorModal UI component
Context Fetching (
lib/readme.ts)- Fetches repository metadata via GitHub GraphQL API
- Retrieves README variants (README.md, README.MD, readme.md)
- Extracts config files (package.json, pyproject.toml, Cargo.toml, go.mod, etc.)
- Builds file tree (2 levels deep)
- Selects language-specific entrypoint files (up to 3)
Confidence Scoring (0-3 scale)
+1 point: Has config file (package.json, Cargo.toml, etc.) +1 point: Has recognized primary language +1 point: Has identifiable entrypoint fileSmart Entrypoint Detection
- Language-aware file selection (e.g.,
src/index.tsfor TypeScript,main.pyfor Python) - Excludes test files, mocks, and utility modules
- Truncates source to 1000 chars per file
- Language-aware file selection (e.g.,
Generation (
app/actions.ts)- Builds context-aware prompt with repo structure, dependencies, and code samples
- Sends to Gemini 2.5 Flash Lite
- Sanitizes output and saves to
Project.aiReadme
| Language | Entrypoint Patterns |
|---|---|
| TypeScript | src/index.ts, src/main.ts, src/App.tsx, app/page.tsx |
| JavaScript | src/index.js, server.js, app.js, pages/index.jsx |
| Python | main.py, app.py, src/main.py, __main__.py |
| Rust | src/main.rs, src/lib.rs |
| Go | main.go, cmd/main.go |
| Ruby | lib/main.rb, app.rb |
| PHP | index.php, public/index.php |
| Java | src/main/java/Main.java, App.java |
| C# | Program.cs, src/Program.cs |
| Swift | Sources/main.swift, App.swift |
| Kotlin | src/main/kotlin/Main.kt |
Automatically detects and includes correct install/run commands:
| Config File | Manager | Install Command |
|---|---|---|
package.json | npm/yarn/pnpm/bun | npm install |
pyproject.toml | poetry/pip | poetry install |
requirements.txt | pip | pip install -r requirements.txt |
Cargo.toml | cargo | cargo build |
go.mod | go | go mod download |
composer.json | composer | composer install |
Gemfile | bundler | bundle install |
The ReadmeGeneratorModal provides:
- Preview mode: Rendered markdown with syntax highlighting
- Raw mode: Plain text for copying
- Diff mode: Side-by-side comparison with original README
- Actions: Copy to clipboard, download as file, revert to original
// Generate README for a projectgenerateReadme(projectId: string): Promise<{success: boolean;readme: string;confidenceScore: number;}>// Get original and generated READMEsgetProjectReadme(projectId: string): Promise<{original: string|null;generated: string|null;}>// Clear generated READMErevertReadme(projectId: string): Promise<void>// Alternative: generate by GitHub repo ID (for dashboard)generateReadmeByGithubId(githubId: number): Promise<{...}>modelProject {// ... other fieldsreadmeString?// Original GitHub READMEaiReadmeString?// AI-generated README}You are a professional technical recruiter. Rewrite this GitHub
project description to be compelling for recruiters.
Project: awesome-api
Description: REST API with Node.js
Topics: nodejs, express, postgresql
README: Built a scalable REST API...
Make it:
- 1-2 sentences max
- Highlight technical skills
- Emphasize impact/value
- Professional tone
- No emojis
Output:
Built a high-performance REST API using Node.js and PostgreSQL,
serving 10K+ daily requests with 99.9% uptime. Implemented JWT
authentication, caching strategies, and comprehensive API docs.
All AI content is sanitized:
// lib/sanitize.tsexportfunctionsanitizeForPostgres(input: string|null): string{returninput?.replace(/\0/g,'')// Remove null bytes.replace(/[\x00-\x1F\x7F-\x9F]/g,(char)=>['\n','\t','\r'].includes(char) ? char : '')||'';}User clicks "Sign in with GitHub"
<buttononClick={()=>signIn("github")}>SigninwithGitHub</button>
GitHub OAuth prompts authorization
- Scopes:
read:user,user:email
- Scopes:
GitHub redirects with code
/api/auth/callback/github?code=ABC123NextAuth exchanges code for token
- Stores access token in
Accounttable - Creates/updates
Userrecord - Issues JWT session
- Stores access token in
Middleware protects routes
// middleware.tsif(protectedPath&&!session){redirect('/');}
Session available in components
constsession=awaitauth();console.log(session.user.username);
{user: {email: "user@example.com",name: "John Doe",image: "https://avatars.githubusercontent.com/...",username: "johndoe"},expires: "2025-01-18T12:00:00.000Z"}All inputs sanitized before storage:
- Remove null bytes (PostgreSQL errors)
- Strip control characters
- Keep safe whitespace (
\n,\t,\r)
- Server-side session checks
- Database queries filtered by
userId - No cross-user data access
- Tokens stored encrypted server-side only (Prisma)
- Never exposed to client
- OAuth scopes limited to GitHub identity
- Private repositories are never requested or synced
- Revocation is attempted on account deletion
Middleware enforces auth:
constprotectedRoutes=['/dashboard','/editor','/settings'];if(protectedPath&&!session)redirect('/');GitHub API rate limit handling:
- In-memory cache per user
- Exponential backoff
- Custom error handling
Prisma ORM provides parameterized queries:
// Safe - auto-escapedawaitdb.user.findUnique({where: {email: userInput}});# DatabaseDATABASE_URL="postgresql://user:password@localhost:5432/gitproof"# NextAuthAUTH_SECRET="openssl-rand-base64-32"NEXTAUTH_URL="http://localhost:3000"# GitHub OAuthAUTH_GITHUB_ID="github_client_id"AUTH_GITHUB_SECRET="github_client_secret"# Google AIGOOGLE_GENERATIVE_AI_API_KEY="gemini_api_key"// next.config.tsconstnextConfig={images: {remotePatterns: [{protocol: "https",hostname: "avatars.githubusercontent.com",},{protocol: "https",hostname: "github.com",},],},};# Development server (hot reload)
npm run dev
# Production build
npm run build
# Start production server
npm start
# Run linter
npm run lint
# Prisma commands
npx prisma generate # Generate client
npx prisma db push # Push schema to DB
npx prisma studio # Open GUI- ESLint: Next.js recommended config
- TypeScript: Strict mode enabled
- Naming: kebab-case for components
Server Component:
// app/dashboard/page.tsxexportdefaultasyncfunctionDashboardPage(){constsession=awaitauth();constuser=awaitdb.user.findUnique({where: {email: session.user.email},});return<DashboardViewdata={user}/>;}Client Component:
// components/dashboard/view.tsx"use client";exportfunctionDashboardView({ data }){const[filter,setFilter]=useState("all");return<div>{/* ... */}</div>;}Server Action:
// app/actions.ts"use server";exportasyncfunctionupdateBio(bio: string){constsession=awaitauth();if(!session)thrownewError("Unauthorized");awaitdb.user.update({where: {email: session.user.email},data: { bio },});}Push to GitHub
git push origin main
Import to Vercel
- Go to vercel.com
- Click "New Project"
- Import repository
Set environment variables
DATABASE_URL AUTH_SECRET NEXTAUTH_URL AUTH_GITHUB_ID AUTH_GITHUB_SECRET GOOGLE_GENERATIVE_AI_API_KEYDeploy
- Auto-deploys on push to
main
- Auto-deploys on push to
- Vercel Postgres:
vercel postgres create - Supabase: supabase.com
- Railway: railway.app
- Environment variables set
- Database connected
- Prisma schema pushed
- GitHub OAuth callback URL updated
- Test authentication
- Monitor logs
Contributions welcome! Please:
- Fork the repository
- Create a feature branch
git checkout -b feature/amazing-feature
- Commit changes
git commit -m "Add amazing feature" - Push to branch
git push origin feature/amazing-feature
- Open a Pull Request
- Follow TypeScript/ESLint rules
- Use kebab-case for files
- Add tests if applicable
- Update documentation
MIT License - see LICENSE file
- Next.js - React framework
- Vercel - Hosting platform
- shadcn/ui - Component library
- Prisma - Database ORM
- GitHub - OAuth & data source
- Google Gemini - AI generation
Built by Benjamin Garcia.