Documentation

v2.3.0

Everything you need to deploy, configure, and use GitDash.

Getting Started

Prerequisites

  • Node.js 20+
  • npm
  • A GitHub Personal Access Token (standalone mode) or a GitHub OAuth App (organization mode)

Quick Start — Standalone Mode

The fastest way to get running. No OAuth App needed.

git clone https://github.com/dinhdobathi1992/gitdash.git
cd gitdash
cp .env.local.example .env.local

# Edit .env.local:
#   MODE=standalone
#   SESSION_SECRET=$(openssl rand -hex 32)

npm install
npm run dev

Open http://localhost:3000 — you will be redirected to /setup to enter your PAT.

Quick Start — Organization Mode

For teams sharing a single deployment. Requires a GitHub OAuth App.

# 1. Create a GitHub OAuth App:
#    Settings → Developer settings → OAuth Apps → New OAuth App
#    Callback URL: http://localhost:3000/api/auth/callback

# 2. Configure .env.local
MODE=organization
GITHUB_CLIENT_ID=your_client_id
GITHUB_CLIENT_SECRET=your_client_secret
SESSION_SECRET=$(openssl rand -hex 32)

# 3. Run
npm install && npm run dev
Generate a strong SESSION_SECRET with: openssl rand -hex 32

Required GitHub PAT Scopes

ScopePurpose
repoRepository list + workflow data (private repos)
workflowWorkflow runs and job details
read:orgOrganization membership + org repo list
read:userUser identity (avatar, name, login)
For reduced permissions, use a fine-grained PAT with Actions: read and Contents: read scoped to specific repos.

Deployment

Docker — Standalone

docker run -d \
  --name gitdash \
  -p 3000:3000 \
  -e MODE=standalone \
  -e SESSION_SECRET=your_32_char_secret_here \
  --restart unless-stopped \
  dinhdobathi1992/gitdash:latest

Docker — Organization Mode

docker run -d \
  --name gitdash \
  -p 3000:3000 \
  -e MODE=organization \
  -e GITHUB_CLIENT_ID=your_client_id \
  -e GITHUB_CLIENT_SECRET=your_client_secret \
  -e SESSION_SECRET=your_32_char_secret_here \
  -e NEXT_PUBLIC_APP_URL=https://gitdash.example.com \
  --restart unless-stopped \
  dinhdobathi1992/gitdash:latest

Docker Compose

Create a docker-compose.yml alongside your .env.local:

services:
  gitdash:
    image: dinhdobathi1992/gitdash:latest
    ports:
      - "3000:3000"
    env_file:
      - .env.local
    restart: unless-stopped
docker compose up -d      # start
docker compose down       # stop
docker compose logs -f    # view logs

Vercel (One-click)

GitDash deploys to Vercel automatically on push to main. To deploy your own fork:

  1. Fork the repository on GitHub
  2. Import the fork in Vercel (New Project → Import Git Repository)
  3. Add all required environment variables in Vercel's project settings
  4. Set the Authorization callback URL in your GitHub OAuth App to https://your-vercel-url/api/auth/callback
DATABASE_URL must be added manually in Vercel's project settings → Environment Variables → Production. It is not included in the repository.

Reverse Proxy / Custom Domain

  1. Set NEXT_PUBLIC_APP_URL to your public URL (e.g. https://gitdash.example.com)
  2. Update the OAuth App callback URL to match
  3. Ensure your proxy forwards the x-forwarded-proto header — the app uses this to enforce HTTPS redirects

Configuration

Environment Variables

VariableRequiredDescriptionExample
SESSION_SECRETRequiredRandom string ≥ 32 characters. Encrypts session cookies with AES-256-GCM. App refuses to start in production if missing or too short.openssl rand -hex 32
MODEOptionalDefault: standalone. Set to organization, org, or team to enable org mode.organization
GITHUB_CLIENT_IDOrg mode onlyGitHub OAuth App Client ID.Ov23liXXXXXXXX
GITHUB_CLIENT_SECRETOrg mode onlyGitHub OAuth App Client Secret. Never commit this value.a1b2c3d4e5...
DATABASE_URLOrg mode onlyPostgreSQL connection string (Neon or any Postgres). Required for alert rules, reports, and sync features.postgresql://user:pass@host/db
NEXT_PUBLIC_APP_URLOptionalPublic URL of the deployment. Used to build OAuth callback URLs and enforce HTTPS redirects.https://gitdash.example.com
NEXT_PUBLIC_APP_VERSIONOptionalApp version shown in the sidebar version badge. Set automatically by the release workflow.2.3.0

Example .env.local — Standalone

MODE=standalone
SESSION_SECRET=replace_with_openssl_rand_hex_32_output
NEXT_PUBLIC_APP_URL=http://localhost:3000

Example .env.local — Organization

MODE=organization
GITHUB_CLIENT_ID=your_oauth_app_client_id
GITHUB_CLIENT_SECRET=your_oauth_app_client_secret
SESSION_SECRET=replace_with_openssl_rand_hex_32_output
DATABASE_URL=postgresql://user:pass@host/db?sslmode=require
NEXT_PUBLIC_APP_URL=https://gitdash.example.com

Creating a GitHub OAuth App

  1. Go to GitHub → Settings → Developer settings → OAuth Apps → New OAuth App
  2. Fill in the fields:
FieldValue
Application nameGitDash
Homepage URLhttps://your-domain.com
Authorization callback URLhttps://your-domain.com/api/auth/callback
  1. Click Register application, then copy the Client ID
  2. Click Generate a new client secret and copy it immediately — it is shown only once

Modes

Standalone vs. Organization

StandaloneOrganization
Auth methodPersonal Access Token (PAT)GitHub OAuth App
Login page/setup/login
Best forPersonal use, local dashboardsTeams sharing one deployment
OAuth App requiredNoYes
Database featuresNot availableAvailable
Alert rulesNot availableAvailable
Reports / syncNot availableAvailable
Cost AnalyticsOwn repos onlyAll org repos (Enhanced Billing Plan required)
Multi-userNo — single sessionYes — isolated sessions per user
standalone

When to use Standalone

  • You're the only user
  • You don't want to create a GitHub OAuth App
  • You're running locally on your laptop
  • You want the simplest possible setup
organization

When to use Organization

  • Multiple team members share one deployment
  • You want each person to use their own GitHub account
  • You need alert rules, reports, or DB-backed features
  • You want to restrict access to a specific GitHub org

Switching Modes

Change the MODE environment variable and restart the server. All session data is invalidated automatically — users will be redirected to the appropriate login page.

# Switch to org mode
MODE=organization

# Switch back to standalone
MODE=standalone   # or unset MODE entirely

Features

Repositories

/

Browse all your personal and organization repositories. Fuzzy search with keyboard navigation. Switch between personal repos and any org you belong to via the sidebar.

Fuzzy searchOrg switcherWorkflow status chips

Workflow Dashboard

/repos/[owner]/[repo]/workflows/[id]

5-tab deep-dive into any workflow. Auto-refreshes every 30 seconds while runs are in progress.

OverviewPerformanceReliabilityTriggersRuns

Cost Analytics

/cost-analytics

GitHub Actions minutes and cost breakdown. Requires org mode with the Enhanced Billing Platform (Team/Enterprise). Shows per-repo, per-workflow spend.

Org modeEnhanced Billing Plan required

Reports

/reports

Scheduled and historical reports backed by the database. Available in organization mode only.

Org mode onlyDatabase required

Alerts

/alerts

Define alert rules triggered by workflow outcomes, duration thresholds, or failure streaks. Available in organization mode only.

Org mode onlyDatabase required

Settings

/settings

Manage your PAT (standalone) or view your OAuth session (org mode). Includes a GitHub Actions billing widget showing remaining free minutes.

PAT managementBilling widget

Workflow Dashboard Tabs

TabWhat you see
OverviewRolling success rate, duration trend, outcome pie chart, run frequency heatmap
PerformancePer-job avg/p95 bar chart, stacked job waterfall per run, slowest steps table
ReliabilityMTTR, failure streaks, flaky branch detection, re-run rate, pass/fail timeline
TriggersEvent breakdown, top branches, hour-of-day heatmap, day-of-week chart, actor leaderboard
RunsSortable table with commit message, PR link, run attempt count, CSV export

Other Capabilities

  • Job & step drill-down — expand any run row to see per-job and per-step timings
  • Per-chart PNG download — export any chart as an image
  • Auto-refresh — polls every 30 seconds while any run is in progress
  • Browser notifications for new workflow failures (opt-in)
  • CSV export from the Runs tab
  • Multi-arch Docker image (amd64 + arm64)

Security

GitDash is designed so your PAT or OAuth token never touches the browser. All credentials live in an encrypted, HTTP-only session cookie on the server.

Request Flow

Browser ──── request ────► Middleware (decrypt session cookie)
                                    │
                                    ├─ No token? ──► Redirect to /setup or /login
                                    │
                                    ▼ Valid session
                         /api/github/* routes
                                    │
                            Retrieve encrypted token
                            from session (server-side)
                                    │
                                    ▼
                          GitHub REST API
                         (Bearer token auth)
                                    │
                                    ▼
                           JSON response
                     (token never sent to browser)

Protection Layers

LayerMechanism
EncryptionAES-256-GCM via iron-session v8 — industry-standard authenticated encryption
Cookie flagsHttpOnly (no JS access), Secure (HTTPS only in production), SameSite=Lax (CSRF protection)
Session secret32+ character minimum enforced at startup in production. Generates with openssl rand -hex 32.
Rate limiting/api/auth/setup: 5 attempts/min/IP (standalone). /api/auth/login: 10 attempts/min/IP (org mode)
Input validationAll owner, repo, org params validated against [a-zA-Z0-9_.-]{1,100}
HTTP headersCSP, HSTS, X-Frame-Options: DENY, X-Content-Type-Options: nosniff, Referrer-Policy
DockerRuns as non-root user nextjs (uid 1001). Built from node:20-alpine.
Logoutsession.destroy() deletes the cookie immediately. POST method prevents CSRF.

What Is Never Stored

  • PAT in localStorage or sessionStorage — verified: 0 matches in src/
  • PAT in API responses returned to the client — verified: 0 matches in src/app/api/
  • PAT in server logs — only IP + timestamp logged on security events
  • PAT as a URL query parameter — always POST body, HTTPS encrypted in transit
  • OAuth token in the database — session-only, lives in the encrypted cookie

Self-Audit Commands

Run these in the project root to verify security claims yourself:

# PAT never in browser storage
grep -r "localStorage|sessionStorage" src/ --include="*.tsx" --include="*.ts"
# Expected: 0 matches ✓

# PAT never returned in API responses
grep -rn "return.*pat|json.*pat" src/app/api --include="*.ts"
# Expected: 0 matches ✓

# PAT never logged
grep -rn "console.*${.*pat|console.*pat)" src/ --include="*.ts" --include="*.tsx"
# Expected: 0 matches ✓

# XSS: dangerouslySetInnerHTML not used
grep -r "dangerouslySetInnerHTML" src/
# Expected: 0 matches ✓

# Check dependency vulnerabilities
npm audit --production
# Expected: 0 high/critical vulnerabilities ✓

FAQ & Troubleshooting

I see a blank screen or 500 error after deploying.

Check that SESSION_SECRET is set and is at least 32 characters. The app throws at startup in production if it is missing or too short. Check server logs for [startup] errors.

Cost Analytics shows a 404 error about billing.

In org mode, Cost Analytics requires the GitHub Enhanced Billing Platform (Team or Enterprise). Your org may not be on this plan. In standalone mode, only your personal billing data is available — org billing is not accessible via a PAT.

OAuth callback fails with 'state mismatch' or 'expired state'.

OAuth state tokens expire after 5 minutes. If the user takes longer to authorize, they will need to click "Sign in with GitHub" again. Also verify that NEXT_PUBLIC_APP_URL exactly matches the callback URL registered in your GitHub OAuth App.

DATABASE_URL is set but reports/alerts still don't work.

Confirm you are in MODE=organization. These features are disabled in standalone mode regardless of whether DATABASE_URL is set. Also check that the database is reachable from your deployment (Neon requires the correct SSL mode: ?sslmode=require).

SESSION_SECRET must be at least 32 characters — but I'm running locally.

This check only applies when NODE_ENV=production. In development (npm run dev) any value is accepted. For local testing you can use any string; for production, generate one with openssl rand -hex 32.

The sidebar shows 'standalone' but I set MODE=organization.

Restart the server after changing environment variables — Next.js reads env vars at startup. Also confirm the variable is set in the correct file (.env.local for local; Vercel/Docker env for production) and that there is no trailing whitespace.

How do I update to a new version?

Pull the latest Docker image: docker pull dinhdobathi1992/gitdash:latest then restart your container. For self-built deployments, pull the latest commit and rebuild.

Can I use a fine-grained PAT instead of a classic PAT?

Yes. Use a fine-grained PAT with Actions: read and Contents: read scoped to specific repositories. This gives least-privilege access. Note that fine-grained PATs cannot access organization data (read:org scope), so org-level features will not work.

Release Notes

v2.3.0latest2026-03-01
Added
  • In-app /docs page with 7 sections, sticky table of contents, and version badge
  • GitHub webhook receiver at /api/webhooks/github — workflow_run events now auto-sync into Neon DB without manual triggers
  • Alert rule evaluation wired into POST /api/db/sync — rules are checked after every sync
  • Slack webhook delivery for alert rules (channel=slack)
  • alerts_fired count shown in Reports page sync result banner
  • /docs publicly accessible before authentication (no login required)
  • Documentation link added to /login and /setup footers
Fixed
  • Sidebar no longer renders on /docs for unauthenticated visitors
  • SWR global 401 handler no longer redirects away from /docs
Improved
  • upsertRuns() replaced N+1 per-row SQL loop with a single Neon HTTP transaction — up to 500× fewer round-trips per sync
v2.2.02026-02-20
Added
  • Reports page — DB-backed historical reporting with daily area chart and quarterly breakdown
  • Alert rules CRUD UI at /alerts with per-repo and per-org scopes
  • Neon PostgreSQL integration with idempotent schema migration (ensureSchema)
  • POST /api/db/sync — incremental GitHub → DB sync with cursor tracking
  • GET /api/db/runs and /api/db/trends endpoints for historical queries
  • Quarterly summary SQL aggregation (getQuarterlySummary)
  • Org daily trend aggregation across all repos (getOrgDailyTrends)
Improved
  • Sync cursor prevents re-fetching already-stored runs on repeated syncs
v2.1.02026-02-10
Added
  • Cost Analytics page at /cost-analytics — GitHub Actions billing breakdown by SKU/runner type
  • Monthly burn rate progress bar with warning/critical thresholds
  • Projected end-of-month minutes calculation
  • Org dashboard at /org/[orgName] — reliability heatmap and sortable repo table
  • Audit tab at /repos/[owner]/[repo]/audit — workflow file commit history
  • Security tab at /repos/[owner]/[repo]/security
  • Team stats tab at /repos/[owner]/[repo]/team — per-contributor heatmaps and leaderboard
Fixed
  • OAuth state now expires after 5 minutes to prevent stale CSRF tokens
Improved
  • Repo overview fetches up to 10 workflows in parallel batches of 5
v2.0.02026-01-15
Added
  • Organization mode — GitHub OAuth App login with isolated per-user sessions
  • Multi-arch Docker image (linux/amd64 + linux/arm64)
  • Automated CI pipeline: lint → typecheck → build on every push to main
  • Vercel deployment pipeline with automatic preview and production deploys
  • Middleware-based auth gate (proxy.ts) with ALWAYS_PUBLIC path list
  • iron-session v8 with AES-256-GCM cookie encryption
  • HTTP security headers: CSP, HSTS, X-Frame-Options, X-Content-Type-Options
  • Rate limiting on /api/auth/setup (5 req/min) and /api/auth/login (10 req/min)
  • Input validation for all owner/repo/org path parameters
  • HTTP → HTTPS redirect via x-forwarded-proto in production
  • Non-root Docker user (nextjs uid 1001)
Improved
  • SESSION_SECRET minimum length enforced at startup in production
  • Lazy Neon DB singleton — no build-time crash when DATABASE_URL is absent
v1.0.02025-12-01
Added
  • Initial release — standalone mode with PAT-based authentication
  • Repositories list with fuzzy search and keyboard navigation
  • Workflow dashboard with 5 tabs: Overview, Performance, Reliability, Triggers, Runs
  • Per-job and per-step drill-down with timing waterfall
  • Auto-refresh every 30 seconds while runs are in-progress
  • Browser notifications for new workflow failures (opt-in)
  • CSV export from the Runs tab
  • Per-chart PNG download
  • Success rate, MTTR, failure streaks, and flaky branch detection
  • Trigger analytics: event breakdown, actor leaderboard, hour/day heatmaps