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)
- Resend — for the contact form backend
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_secret
# Contact form email delivery
RESEND_API_KEY=re_xxx...
RESEND_FROM_EMAIL="DevTrack <contact@your-domain.com>"
CONTACT_TO_EMAIL=you@example.comGenerate 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. Generate one with:
# macOS / Linux
openssl rand -base64 32
# Windows PowerShell
[Convert]::ToBase64String((1..32 | ForEach-Object { Get-Random -Maximum 256 }))Symptom: After clicking "Sign in with GitHub" and completing the GitHub flow, the browser redirects back to /auth/signin?error=github instead of the dashboard.
Work through this checklist in order:
Open .env.local and confirm these four are set to real values (not your_... placeholders):
GITHUB_ID=Ov23... # from github.com/settings/developers
GITHUB_SECRET=ghp_... # generated in the same OAuth App
NEXTAUTH_SECRET=<32-byte> # run: openssl rand -base64 32
NEXTAUTH_URL=http://localhost:3000Also required for the database upsert on sign-in:
NEXT_PUBLIC_SUPABASE_URL=https://xxxx.supabase.co
SUPABASE_SERVICE_ROLE_KEY=eyJ...If NEXT_PUBLIC_SUPABASE_URL or SUPABASE_SERVICE_ROLE_KEY are missing, the server log will print:
signIn: supabaseAdmin is not configured; skipping DB upsert.
Authentication will still succeed, but no user record will be written to Supabase.
The Authorization callback URL in your GitHub OAuth App must be exactly:
http://localhost:3000/api/auth/callback/github
Any trailing slash, different port, or HTTPS vs HTTP mismatch will cause error=github. Verify at github.com/settings/developers → your OAuth App → Authorization callback URL.
The ENCRYPTION_KEY is required for OAuth token encryption:
ENCRYPTION_KEY=<64 hex chars> # run: openssl rand -hex 32On Windows PowerShell:
-join ((1..32) | ForEach-Object { "{0:x2}" -f (Get-Random -Maximum 256) })Next.js reads .env.local only at startup. After any change, stop and restart:
npm run devThe browser only shows error=github — the actual error is printed to the terminal running npm run dev. Look for lines starting with [next-auth] or signIn:.
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.
When you add a new Supabase migration under supabase/migrations/, you must also update supabase/schema.sql so that fresh local setups work without manually running every migration.
A simple rule: append the new migration SQL into supabase/schema.sql (including any new columns, tables, indexes, functions, and RLS policies).
Open a GitHub Discussion — not an issue.
- If prettier-check fails in sandboxed environments, run git commit with --no-verify.