Skip to content

Latest commit

 

History

History
1030 lines (815 loc) · 28.4 KB

File metadata and controls

1030 lines (815 loc) · 28.4 KB

GitProof 2

A sophisticated developer portfolio platform that transforms your GitHub activity into a shareable, AI-enhanced professional profile.

Next.js TypeScript Prisma Tailwind CSS

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.


📖 Table of Contents


🎯 Overview

GitProof 2 is a full-stack Next.js application that helps developers:

  1. Authenticate with GitHub - Secure OAuth integration
  2. Sync repository data - Fetch public repos, commits, stars, forks
  3. Calculate impact scores - Smart algorithm (0-50 scale) based on popularity, recency, and maturity
  4. Generate AI insights - Use Google Gemini to analyze strengths and growth areas
  5. Customize portfolio - Select featured projects, rewrite descriptions with AI
  6. Share public profiles - Beautiful, shareable profile pages at /u/[username]

Live Example: /u/yourname shows your curated portfolio to the world.


✨ Features

🔐 GitHub Authentication

  • 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

📊 Repository Analysis Dashboard

  • 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

✏️ Portfolio Editor

  • 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

🤖 AI-Powered Features

  • 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

🌐 Public Developer Profiles

  • 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

📈 Analytics & Insights

  • 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

⚙️ Settings & Account Management

  • 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

🛠 Tech Stack

Frontend

  • 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)

Backend

  • 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

External APIs

  • GitHub GraphQL API - Repository and user data
  • GitHub OAuth - Authentication provider
  • Google Gemini 2.5 Flash Lite - AI text generation

Data Visualization

  • Recharts 3.5.1 - React charting library
  • Victory Vendor - D3 components

Developer Experience

  • ESLint 9 - Code linting
  • PostCSS - CSS transformation
  • class-variance-authority - Component API builder

🚀 Getting Started

Prerequisites

  • 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

Installation

  1. Clone the repository

    git clone https://github.com/bgar324/gitproof-2
    cd gitproof-2
  2. Install dependencies

    npm install
  3. Set up environment variables

    Create a .env.local file in the root directory:

    # Database
    DATABASE_URL="postgresql://user:password@localhost:5432/gitproof"
    
    # NextAuth
    AUTH_SECRET="generate-with-openssl-rand-base64-32"
    NEXTAUTH_URL="http://localhost:3000"
    
    # GitHub OAuth
    AUTH_GITHUB_ID="your_github_client_id"
    AUTH_GITHUB_SECRET="your_github_client_secret"
    
    # Google AI
    GOOGLE_GENERATIVE_AI_API_KEY="your_gemini_api_key"
  4. Set up the database

    npx prisma generate
    npx prisma db push
  5. Run the development server

    npm run dev
  6. Open the app

    Navigate to http://localhost:3000

GitHub OAuth Setup

  1. Go to GitHub Settings > Developer Settings > OAuth Apps
  2. Click New OAuth App
  3. Fill in:
    • Application name: GitProof 2
    • Homepage URL: http://localhost:3000
    • Authorization callback URL: http://localhost:3000/api/auth/callback/github
  4. Click Register application
  5. Copy Client ID and Client Secret to .env.local

📁 Project Structure

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

🏗 Architecture

App Router Flow

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

Data Flow

GitHub OAuth → NextAuth → Prisma → PostgreSQL
                   ↓
              User Session
                   ↓
         Authenticated Routes
                   ↓
    Server Components (DB queries)
                   ↓
    Client Components (interactivity)
                   ↓
         Server Actions (mutations)
                   ↓
              Database Updates

Server vs Client Components

  • Server Components (default): Fetch data, render on server

    • app/(app)/dashboard/page.tsx
    • app/u/[username]/page.tsx
  • Client Components ("use client"): Interactive UI

    • app/(app)/dashboard/view.tsx
    • components/dashboard/*
    • components/editor/*

💾 Database Schema

User Model

model User {
  id                  String    @id @default(cuid())
  email               String    @unique
  username            String    @unique
  name                String?
  image               String?
  bio                 String?
  isPublic            Boolean   @default(false)
  emailNotifications  Boolean   @default(false)
  lastSyncedAt        DateTime?
  profileData         Json?     // Cached GitHub data
  createdAt           DateTime  @default(now())
  updatedAt           DateTime  @updatedAt

  accounts            Account[]
  sessions            Session[]
  projects            Project[]
}

Project Model

model Project {
  id              String   @id @default(cuid())
  userId          String
  githubId        Int
  name            String
  desc            String?
  url             String
  homepage        String?
  language        String?
  topics          String[]
  stars           Int      @default(0)
  forks           Int      @default(0)
  lastPush        DateTime
  impactScore     Int      @default(0)  // 0-50
  readme          String?               // Original GitHub README
  aiDescription   String?               // AI-rewritten description
  aiReadme        String?               // AI-generated README
  isHidden        Boolean  @default(false)
  createdAt       DateTime @default(now())
  updatedAt       DateTime @updatedAt

  user            User     @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@index([userId])
  @@index([impactScore])
  @@index([lastPush])
}

Account & Session Models (NextAuth)

model Account {
  id                  String  @id @default(cuid())
  userId              String
  provider            String  // "github"
  providerAccountId   String
  access_token        String? // GitHub OAuth token
  // ... other OAuth fields
}

model Session {
  id           String   @id @default(cuid())
  sessionToken String   @unique
  userId       String
  expires      DateTime
}

🔌 API & Server Actions

REST Endpoints

No standalone sync endpoint. Repository syncing is performed through authenticated server actions that fetch directly from GitHub on the server.

Server Actions

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

🧩 Component System

Component Categories

Dashboard Components (components/dashboard/)

  • activity-heatmap - Contribution calendar
  • dashboard-header - Top stats header
  • dashboard-repo-card - Repository card
  • focus-hours-card - Hourly activity chart
  • impact-tooltip - Score explanation
  • score-modal - Algorithm breakdown
  • stat-card - Metric display
  • tech-stack-card - Language bars
  • time-range-selector - Filter controls
  • top-repos-header - Section header

Editor Components (components/editor/)

  • editor-repo-card - Editable repo card with AI rewrite
  • featured-section - Featured projects manager
  • identity-section - Bio editor
  • library-section - All projects grid
  • save-button - Save changes button

Modal Components (components/modals/)

  • readme-generator-modal - AI README generation with preview/raw/diff views

Profile Components (components/profile/)

  • hero-section - Profile header
  • portfolio-section - Projects display
  • public-repo-card - Public repo card

UI Primitives (components/ui/)

shadcn/ui components: badge, button, card, dialog, dropdown-menu, input, label, separator, skeleton, switch, tabs, textarea, tooltip


📊 Impact Score Algorithm

The Impact Score (0-50) combines three weighted components:

Formula

Score = min(round(Popularity + Recency + Maturity), 50)

1. Popularity (0-40 points, ~40-45%)

Logarithmic scale with increased multiplier to better reward popular projects:

Popularity = log₂(stars + forks × 2 + 1) × 4.5
Popularity = 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)

2. Recency (0-15 points, ~25-30%)

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)

3. Maturity (0-15 points, ~25-30%)

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)

User Score Aggregation

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.

Example

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) ✨

🤖 AI Integration

Google Gemini 2.5 Flash Lite

Used for:

  1. Project description rewriting
  2. README generation
  3. User bio generation
  4. Insight analysis

Configuration

GOOGLE_GENERATIVE_AI_API_KEY="your_api_key"

README Generation

The README generator analyzes your repository to create comprehensive, professional documentation.

Architecture

lib/readme.ts          → Repository context fetching (GraphQL)
app/actions.ts         → Server actions (generateReadme, revertReadme)
components/modals/     → ReadmeGeneratorModal UI component

How It Works

  1. 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)
  2. 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 file
    
  3. Smart Entrypoint Detection

    • Language-aware file selection (e.g., src/index.ts for TypeScript, main.py for Python)
    • Excludes test files, mocks, and utility modules
    • Truncates source to 1000 chars per file
  4. 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

Supported Languages & Entrypoints

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

Package Manager Detection

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

UI Component

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

Server Actions

// Generate README for a project
generateReadme(projectId: string): Promise<{
  success: boolean;
  readme: string;
  confidenceScore: number;
}>

// Get original and generated READMEs
getProjectReadme(projectId: string): Promise<{
  original: string | null;
  generated: string | null;
}>

// Clear generated README
revertReadme(projectId: string): Promise<void>

// Alternative: generate by GitHub repo ID (for dashboard)
generateReadmeByGithubId(githubId: number): Promise<{...}>

Database Schema

model Project {
  // ... other fields
  readme      String?   // Original GitHub README
  aiReadme    String?   // AI-generated README
}

Prompt Examples

Project Description

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.

AI Safety

All AI content is sanitized:

// lib/sanitize.ts
export function sanitizeForPostgres(input: string | null): string {
  return input
    ?.replace(/\0/g, '') // Remove null bytes
    .replace(/[\x00-\x1F\x7F-\x9F]/g, (char) =>
      ['\n', '\t', '\r'].includes(char) ? char : ''
    ) || '';
}

🔐 Authentication Flow

Step-by-Step

  1. User clicks "Sign in with GitHub"

    <button onClick={() => signIn("github")}>
      Sign in with GitHub
    </button>
  2. GitHub OAuth prompts authorization

    • Scopes: read:user, user:email
  3. GitHub redirects with code

    /api/auth/callback/github?code=ABC123
    
  4. NextAuth exchanges code for token

    • Stores access token in Account table
    • Creates/updates User record
    • Issues JWT session
  5. Middleware protects routes

    // middleware.ts
    if (protectedPath && !session) {
      redirect('/');
    }
  6. Session available in components

    const session = await auth();
    console.log(session.user.username);

Session Structure

{
  user: {
    email: "user@example.com",
    name: "John Doe",
    image: "https://avatars.githubusercontent.com/...",
    username: "johndoe"
  },
  expires: "2025-01-18T12:00:00.000Z"
}

🔒 Security Features

1. Data Sanitization

All inputs sanitized before storage:

  • Remove null bytes (PostgreSQL errors)
  • Strip control characters
  • Keep safe whitespace (\n, \t, \r)

2. Access Control

  • Server-side session checks
  • Database queries filtered by userId
  • No cross-user data access

3. OAuth Token Security

  • 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

4. Route Protection

Middleware enforces auth:

const protectedRoutes = ['/dashboard', '/editor', '/settings'];
if (protectedPath && !session) redirect('/');

5. Rate Limiting

GitHub API rate limit handling:

  • In-memory cache per user
  • Exponential backoff
  • Custom error handling

6. SQL Injection Prevention

Prisma ORM provides parameterized queries:

// Safe - auto-escaped
await db.user.findUnique({
  where: { email: userInput }
});

⚙️ Configuration

Environment Variables

# Database
DATABASE_URL="postgresql://user:password@localhost:5432/gitproof"

# NextAuth
AUTH_SECRET="openssl-rand-base64-32"
NEXTAUTH_URL="http://localhost:3000"

# GitHub OAuth
AUTH_GITHUB_ID="github_client_id"
AUTH_GITHUB_SECRET="github_client_secret"

# Google AI
GOOGLE_GENERATIVE_AI_API_KEY="gemini_api_key"

Next.js Config

// next.config.ts
const nextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: "https",
        hostname: "avatars.githubusercontent.com",
      },
      {
        protocol: "https",
        hostname: "github.com",
      },
    ],
  },
};

💻 Development

Scripts

# 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

Code Style

  • ESLint: Next.js recommended config
  • TypeScript: Strict mode enabled
  • Naming: kebab-case for components

Component Patterns

Server Component:

// app/dashboard/page.tsx
export default async function DashboardPage() {
  const session = await auth();
  const user = await db.user.findUnique({
    where: { email: session.user.email },
  });
  return <DashboardView data={user} />;
}

Client Component:

// components/dashboard/view.tsx
"use client";

export function DashboardView({ data }) {
  const [filter, setFilter] = useState("all");
  return <div>{/* ... */}</div>;
}

Server Action:

// app/actions.ts
"use server";

export async function updateBio(bio: string) {
  const session = await auth();
  if (!session) throw new Error("Unauthorized");

  await db.user.update({
    where: { email: session.user.email },
    data: { bio },
  });
}

🚀 Deployment

Vercel (Recommended)

  1. Push to GitHub

    git push origin main
  2. Import to Vercel

    • Go to vercel.com
    • Click "New Project"
    • Import repository
  3. Set environment variables

    DATABASE_URL
    AUTH_SECRET
    NEXTAUTH_URL
    AUTH_GITHUB_ID
    AUTH_GITHUB_SECRET
    GOOGLE_GENERATIVE_AI_API_KEY
    
  4. Deploy

    • Auto-deploys on push to main

Database Options

Post-Deployment

  • Environment variables set
  • Database connected
  • Prisma schema pushed
  • GitHub OAuth callback URL updated
  • Test authentication
  • Monitor logs

🤝 Contributing

Contributions welcome! Please:

  1. Fork the repository
  2. Create a feature branch
    git checkout -b feature/amazing-feature
  3. Commit changes
    git commit -m "Add amazing feature"
  4. Push to branch
    git push origin feature/amazing-feature
  5. Open a Pull Request

Guidelines

  • Follow TypeScript/ESLint rules
  • Use kebab-case for files
  • Add tests if applicable
  • Update documentation

📄 License

MIT License - see LICENSE file


🙏 Acknowledgments

  • Next.js - React framework
  • Vercel - Hosting platform
  • shadcn/ui - Component library
  • Prisma - Database ORM
  • GitHub - OAuth & data source
  • Google Gemini - AI generation

📚 Additional Resources


Built by Benjamin Garcia.