This guide walks through the full setup: create a GitHub App, configure Supabase, apply migrations, and get the dev server running.
Prerequisites
- Node.js 20+
- pnpm (
npm install -g pnpm) - A GitHub Account with admin access to at least one organization
- A Supabase Project (free tier works fine)
- Supabase CLI (
npm install -g supabase) for runningdb push
Step 1: Create a GitHub App
This project requires a GitHub App (not a GitHub OAuth App). The distinction matters — GitHub Apps support installation-level permissions and webhooks.
- Go to GitHub Settings → Developer settings → GitHub Apps → New GitHub App
- App Name: something unique like
my-org-tools-dev - Homepage URL:
http://localhost:3000 - Callback URL:
http://localhost:3000/api/auth - Webhook URL:
http://localhost:3000/api/install/webhook(or your ngrok URL) - Webhook secret: generate a random string — save it for
GITHUB_WEBHOOK_SECRET - Permissions:
- Organization:
members(read),teams(read) - Repository:
metadata(read),contents(read),pull_requests(read),issues(read) - Account:
email(read)
- Organization:
- Subscribe to events:
installation,installation_repositories - Save, then generate a Private Key — download the
.pemfile - Install the app on your target organization
For the webhook URL, GitHub requires HTTPS. If you’re developing locally, use ngrok to create a tunnel — more on that in the troubleshooting section below.
Step 2: Configure environment variables
cp example.env .env.localRequired variables
| Variable | Source | Description |
|---|---|---|
GITHUB_APP_ID | GitHub App Settings | Numeric app ID |
GITHUB_PRIVATE_KEY | GitHub App → Private keys | Full PEM text (with -----BEGIN... lines) |
GITHUB_CLIENT_ID | GitHub App Settings | OAuth client ID |
GITHUB_CLIENT_SECRET | GitHub App Settings | OAuth client secret |
GITHUB_APP_NAME | Your choice | App slug used in install URLs |
NEXT_PUBLIC_APP_URL | Your setup | http://localhost:3000 |
NEXT_PUBLIC_SUPABASE_URL | Supabase Project Settings | Project URL |
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_DEFAULT_KEY | Supabase Project Settings | Anon/public key |
SUPABASE_SERVICE_ROLE_KEY | Supabase Project Settings | Service role key (server-side only) |
Security variables (strongly recommended)
| Variable | How to generate | Description |
|---|---|---|
AUTH_SESSION_SECRET | node -e "console.log(require('crypto').randomBytes(32).toString('hex'))" | JWT signing key for state tokens |
TOKEN_ENCRYPTION_KEY | node -e "console.log(require('crypto').randomBytes(32).toString('hex'))" | AES-256-GCM key for encrypting GitHub tokens |
GITHUB_WEBHOOK_SECRET | Any random string | Must match the webhook secret in GitHub App settings |
If you skip AUTH_SESSION_SECRET or TOKEN_ENCRYPTION_KEY, the app falls back to derived values from GITHUB_CLIENT_SECRET and GITHUB_APP_ID. Fine for local development, but not recommended for production.
Step 3: Apply Supabase migrations
The app uses 13 migration files in supabase/migrations/.
Link your Supabase project (first time)
npx supabase login
npx supabase link --project-ref <your-project-ref>Your project ref is the random string in your Supabase URL: https://<project-ref>.supabase.co
Push migrations
npx supabase db pushThis applies all 11 migrations in order:
001_enums_and_utilities.sql— custom ENUMs, helper functions and trigger utilities002_users_and_organizations.sql— normalizedusers,organizations, and membership tables003_repositories_and_teams.sql— repository and team scaffolding used by the ingest pipeline004_relationships.sql— relationship tables and FK constraints between repos, teams and orgs005_github_installations.sql— cache for GitHub App installation metadata006_auth_sessions.sql— encrypted session storage and session management helpers007_scoring_presets.sql— scoring preset definitions and metadata008_signals.sql— contributor action signals table (the raw events/signals used by scoring)009_sync_state.sql— ingest/sync tracking and state tables (ingest cooldowns)010_leaderboard_materializations.sql— leaderboard snapshot / materialization tables and indexes011_computed_scores.sql— pre-computed score storage for presets and time windows
Verify
npx supabase migration listAll local and remote versions should match 001 through 011.
Manual application (no CLI)
If you’d rather not use the Supabase CLI:
- Open the Supabase SQL Editor in the dashboard
- Run each migration file in numeric order —
001first, then002, etc.
Step 4: Install dependencies and run
pnpm install
pnpm devThe app will be available at http://localhost:3000.
Available commands
| Command | Description |
|---|---|
pnpm dev | Start Next.js dev server (Turbopack, port 3000) |
pnpm build | Production build |
pnpm start | Start production server |
pnpm lint | ESLint (flat config) |
pnpm format | Prettier write all files |
Step 5: Verify the setup
- Open
http://localhost:3000 - Click Sign in with GitHub
- Authorize your GitHub App
- You should be redirected back with a session cookie (
gh_session) - Check the Account page — your organizations should appear
- Install the GitHub App on an organization if it’s not already installed
Troubleshooting
redirect_uri mismatch
The GitHub App callback URL must match exactly — http://localhost:3000/api/auth (no trailing slash, no typos).
session not found after sign-in
- Check that
SUPABASE_SERVICE_ROLE_KEYis correct - Verify migrations were applied:
npx supabase migration list - Check browser cookies:
gh_sessionshould be present
Database errors on first run
If you see table-not-found errors, migrations weren’t applied. Run npx supabase db push again.
Webhook events not received locally
GitHub requires HTTPS for webhook URLs. Use ngrok to create a tunnel:
ngrok http 3000Then update the Webhook URL in your GitHub App settings to https://your-ngrok-url.ngrok.io/api/install/webhook.
Related
- Supabase Configuration — migration strategy and schema design
- Database Schema — complete table reference
- Authentication — how auth flows work