Everything you need to run DevTrack locally from scratch in under 10 minutes.
| Tool | Version | Check |
|---|---|---|
| Node.js | >= 18 | node -v |
| npm | >= 9 | npm -v |
| Git | any | git --version |
You also need free accounts on:
- Supabase — for the database
- GitHub — for OAuth (you already have this)
git clone https://github.com/Priyanshu-byte-coder/devtrack.git
cd devtrack
npm install- Go to supabase.com → New Project
- Pick a name, region, and database password — save the password somewhere
- Wait ~1 minute for project to provision
- Go to SQL Editor → New Query
- Paste the full contents of
supabase/schema.sqland click Run - Go to Project Settings → API and copy three values:
- Project URL →
NEXT_PUBLIC_SUPABASE_URL - anon / public key →
NEXT_PUBLIC_SUPABASE_ANON_KEY - service_role secret →
SUPABASE_SERVICE_ROLE_KEY
- Project URL →
The
service_rolekey has admin access. Never expose it client-side. DevTrack uses it only in server-side API routes.
- Go to github.com/settings/applications/new
- Fill in:
- Application name:
DevTrack (local) - Homepage URL:
http://localhost:3000 - Authorization callback URL:
http://localhost:3000/api/auth/callback/github
- Application name:
- Click Register application
- Copy Client ID →
GITHUB_ID - Click Generate a new client secret → copy it →
GITHUB_SECRET
cp .env.example .env.localOpen .env.local and fill in all values:
# Supabase
NEXT_PUBLIC_SUPABASE_URL=https://xxxxxxxxxxxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJ...
SUPABASE_SERVICE_ROLE_KEY=eyJ...
# NextAuth
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=generate_with_openssl_rand_base64_32
# GitHub OAuth
GITHUB_ID=Ov23...
GITHUB_SECRET=your_github_client_secretGenerate NEXTAUTH_SECRET:
# macOS / Linux
openssl rand -base64 32
# Windows PowerShell
[Convert]::ToBase64String((1..32 | ForEach-Object { Get-Random -Maximum 256 }))npm run devOpen http://localhost:3000. Click Sign in with GitHub.
src/
├── app/
│ ├── api/
│ │ ├── auth/
│ │ │ ├── [...nextauth]/ # GitHub OAuth via NextAuth
│ │ │ └── link-github/ # Link additional GitHub accounts
│ │ │ └── callback/
│ │ ├── badge/
│ │ │ ├── badge-utils.ts # Shared badge helpers
│ │ │ ├── commits/ # GET commit-count badge
│ │ │ └── streak-shield/ # GET streak shield (shields.io)
│ │ ├── goals/
│ │ │ ├── route.ts # GET + POST /api/goals
│ │ │ └── [id]/route.ts # DELETE /api/goals/:id
│ │ ├── leaderboard/route.ts # GET public leaderboard data
│ │ ├── metrics/
│ │ │ ├── ci/ # GET CI build analytics
│ │ │ ├── compare/ # GET side-by-side user comparison
│ │ │ ├── contributions/ # GET /api/metrics/contributions?days=30
│ │ │ ├── issues/ # GET issue open/close metrics
│ │ │ ├── languages/ # GET language breakdown
│ │ │ ├── pinned-repos/ # GET pinned repositories
│ │ │ ├── pr-breakdown/ # GET PR open/merged/closed counts
│ │ │ ├── pr-review-time/ # GET PR review time trend
│ │ │ ├── prs/ # GET /api/metrics/prs
│ │ │ ├── repo-health/ # GET repository health score
│ │ │ ├── repos/ # GET /api/metrics/repos?days=30
│ │ │ ├── streak/ # GET /api/metrics/streak
│ │ │ └── weekly-summary/ # GET weekly activity digest
│ │ ├── public/[username]/ # GET public profile data
│ │ ├── streak/
│ │ │ └── freeze/route.ts # POST streak freeze
│ │ ├── user/
│ │ │ ├── github-accounts/ # GET + POST linked accounts
│ │ │ │ └── [githubId]/ # DELETE a linked account
│ │ │ └── settings/route.ts # GET + PATCH user settings
│ │ └── webhooks/github/route.ts # GitHub push webhook receiver
│ ├── dashboard/
│ │ ├── page.tsx # Dashboard layout — add new widgets here
│ │ └── settings/page.tsx # User settings page
│ ├── leaderboard/page.tsx # Public leaderboard page
│ ├── u/[username]/page.tsx # Public profile page
│ ├── error.tsx # Global error boundary
│ ├── layout.tsx # Root layout
│ ├── not-found.tsx # 404 page
│ ├── page.tsx # Landing page
│ └── providers.tsx # Session + theme providers
├── components/
│ ├── AccountContext.tsx # Multi-account state context
│ ├── AccountToggle.tsx # Switch between linked accounts
│ ├── BackToTopButton.tsx # Scroll-to-top button
│ ├── BadgeSection.tsx # Embeddable badge display
│ ├── CIAnalytics.tsx # CI build success/failure chart
│ ├── CommitTimeChart.tsx # Commits by hour-of-day bar chart
│ ├── ContributionGraph.tsx # Bar chart with time range selector
│ ├── ContributionHeatmap.tsx # GitHub-style activity heatmap
│ ├── CopyLinkButton.tsx # Copy-to-clipboard helper
│ ├── DashboardHeader.tsx # Top bar with user avatar + sign out
│ ├── ExportButton.tsx # Export metrics to PDF
│ ├── FriendComparison.tsx # Side-by-side user comparison
│ ├── GoalTracker.tsx # Weekly goals progress bars
│ ├── IssueMetrics.tsx # Issue open/close stats
│ ├── KeyboardShortcuts.tsx # Global keyboard shortcut handler
│ ├── LanguageBreakdown.tsx # Language usage breakdown chart
│ ├── PRBreakdownChart.tsx # PR status pie chart
│ ├── PRMetrics.tsx # PR stats card grid
│ ├── PRReviewTrendChart.tsx # PR review time trend line chart
│ ├── PRStatusDonutChart.tsx # PR open/merged/closed donut
│ ├── PersonalRecords.tsx # All-time personal bests widget
│ ├── PinnedRepos.tsx # User's pinned repositories list
│ ├── ShortcutsModal.tsx # Keyboard shortcuts reference modal
│ ├── SignOutButton.tsx # Sign-out button
│ ├── StatsCard.tsx # Shareable stats card (PNG export)
│ ├── StreakAtRiskBanner.tsx # Warning banner when streak is at risk
│ ├── StreakTracker.tsx # Current + longest commit streak
│ ├── ThemeContext.tsx # Light/dark theme context
│ ├── ThemeToggle.tsx # Light/dark mode toggle button
│ ├── TopRepos.tsx # Most active repos ranked list
│ ├── UserAvatar.tsx # User avatar image
│ └── WeeklySummaryCard.tsx # Weekly activity digest card
├── hooks/
│ ├── useCountUp.ts # Animated number count-up hook
│ └── useHeatmapTheme.ts # Heatmap colour theme hook
├── lib/
│ ├── auth.ts # NextAuth config, GitHub scopes, Supabase upsert
│ ├── crypto.ts # HMAC/signature utilities
│ ├── dateUtils.ts # Shared date helpers
│ ├── github-accounts.ts # Multi-account GitHub API helpers
│ ├── github.ts # GitHub REST API client
│ ├── metrics-cache.ts # Server-side metrics cache layer
│ ├── repo-health.ts # Repository health score logic
│ ├── resolve-user.ts # Resolve session to Supabase user
│ └── supabase.ts # Supabase admin client (server-only)
├── middleware.ts # Auth middleware (route protection)
└── types/
├── next-auth.d.ts # NextAuth session type extensions
└── repo-health.ts # RepoHealth type definitions
supabase/
└── schema.sql # DB schema — run once in Supabase SQL Editor
Browser → Next.js API route → GitHub API (with user's OAuth token)
→ Supabase (for goals, user records)
All GitHub API calls use the signed-in user's OAuth token — stored in the session via NextAuth. No shared API key.
| Command | What it does |
|---|---|
npm run dev |
Start dev server at localhost:3000 |
npm run build |
Production build |
npm run lint |
ESLint |
npm run type-check |
TypeScript compiler check (no emit) |
Run lint and type-check before pushing:
npm run lint && npm run type-check- Create
src/components/MyWidget.tsx— use"use client", fetch from your API route - Create
src/app/api/metrics/my-widget/route.ts— addexport const dynamic = "force-dynamic", guard withgetServerSession - Import and place in
src/app/dashboard/page.tsx
Pattern for an API route:
import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth";
export const dynamic = "force-dynamic";
export async function GET() {
const session = await getServerSession(authOptions);
if (!session?.accessToken) {
return Response.json({ error: "Unauthorized" }, { status: 401 });
}
// fetch from GitHub API using session.accessToken
// fetch from Supabase using session.githubId
}[next-auth][error][NO_SECRET]
Add NEXTAUTH_SECRET to .env.local.
The redirect_uri is not associated with this application
Ensure the Authorization callback URL in your GitHub OAuth App is exactly:
http://localhost:3000/api/auth/callback/github
relation "users" does not exist
You forgot to run supabase/schema.sql. Go to Supabase SQL Editor and run it.
{ "message": "API rate limit exceeded" }
You hit the 30 requests/minute search API limit. Wait 1 minute. In production this won't happen for normal usage.
Open a GitHub Discussion — not an issue.