A comprehensive, self-hosted dashboard that provides centralized visibility over GitHub Actions pipelines, performance metrics, and costs distributed across multiple repositories and organizations.
- Centralized Visibility: Single pane of glass for all workflow runs across repositories
- Repository Scoring: Grade repos with gold/silver/bronze tiers across Security, Testing, CI/CD, Documentation, Code Quality, Maintenance, and Community
- Real-time Updates: Live pipeline status via WebSocket
- GitHub OAuth: Sign in with GitHub; no GitHub App setup required
- Cost Tracking: Per-workflow and per-repository cost analysis
- Multi-repository Support: Monitor workflows across multiple repos and organizations
- Beautiful UI: Modern, responsive design with dark/light mode
- Two Storage Modes: Quick start with memory storage or persistent PostgreSQL database
No Database (Memory Mode):
# 1. Clone and install
git clone https://github.com/banshee86vr/snorlx.git && cd snorlx && pnpm install
# 2. Configure (edit .env with your GitHub credentials)
cp env.example .env
# 3. Set STORAGE_MODE=memory in .env (default)
# 4. Start both frontend and backend
pnpm run devWith PostgreSQL Database:
# 1. Clone and install
git clone https://github.com/banshee86vr/snorlx.git && cd snorlx && pnpm install
# 2. Start PostgreSQL (Docker)
docker run --name snorlx-postgres \
-e POSTGRES_DB=snorlx \
-e POSTGRES_USER=postgres \
-e POSTGRES_PASSWORD=postgres \
-p 5432:5432 -d timescale/timescaledb:latest-pg16
# 3. Configure (edit .env with your credentials and DATABASE_URL)
cp env.example .env
# 4. Set STORAGE_MODE=database and DATABASE_URL in .env
# 5. Start both frontend and backend
pnpm run devAccess at: http://localhost:5173
- Go 1.26+
- Node.js 20+
- pnpm or npm
- PostgreSQL 14+ with TimescaleDB (optional - only for database mode)
- GitHub OAuth App (see Setup Guide)
Perfect for testing and development! Start in minutes without setting up a database.
- Clone and install dependencies
git clone https://github.com/banshee86vr/snorlx.git
cd snorlx
pnpm install- Configure environment
# Copy example environment file
cp env.example .envEdit .env with your credentials:
# Development mode (skip GitHub OAuth validation)
DEV_MODE=true
# Storage Mode - Use memory for quick start (no database needed)
STORAGE_MODE=memory
# GitHub OAuth (create at: https://github.com/settings/developers)
GITHUB_CLIENT_ID=your_oauth_client_id
GITHUB_CLIENT_SECRET=your_oauth_client_secret
# Session Security (generate with: openssl rand -base64 32)
SESSION_SECRET=your_random_32_character_secret_string
# URLs
PORT=8080
FRONTEND_URL=http://localhost:5173- Start the application
# From project root - starts both frontend and backend concurrently
pnpm run devThe application will start:
- Frontend: http://localhost:5173
- Backend API: http://localhost:8080
Or start separately:
# Backend only
pnpm run dev:backend
# Frontend only (in another terminal)
pnpm run dev:frontendFor persistent data storage in production environments.
git clone https://github.com/banshee86vr/snorlx.git
cd snorlx
pnpm installUsing Docker (Recommended)
docker run --name snorlx-postgres \
-e POSTGRES_DB=snorlx \
-e POSTGRES_USER=postgres \
-e POSTGRES_PASSWORD=postgres \
-p 5432:5432 \
-d timescale/timescaledb:latest-pg16Using Local PostgreSQL (macOS with Homebrew)
# Install TimescaleDB
brew install postgresql@16 timescaledb
# Start PostgreSQL
brew services start postgresql@16
# Create database
psql postgres -c "CREATE DATABASE snorlx;"cp env.example .envEdit .env:
# Development mode
DEV_MODE=true
# Storage Mode - Use database for persistence
STORAGE_MODE=database
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/snorlx?sslmode=disable
# GitHub Configuration
GITHUB_CLIENT_ID=your_oauth_client_id
GITHUB_CLIENT_SECRET=your_oauth_client_secret
# Session Security
SESSION_SECRET=your_random_32_character_secret_string
# URLs
PORT=8080
FRONTEND_URL=http://localhost:5173# From project root - starts both frontend and backend concurrently
# Migrations run automatically on backend startup
pnpm run devAccess the dashboard at http://localhost:5173
For production deployments with all services containerized.
- Configure environment
cp env.example .env
# Edit .env with your production settings
# Make sure STORAGE_MODE=database for Docker- Start all services
docker compose up -dThe dashboard will be available at http://localhost:5174 (frontend) and http://localhost:3001 (backend API)
- View logs
docker compose logs -f- Stop services
docker compose downRepositories are graded with an overall percentage and a tier (gold / silver / bronze) based on checks in seven categories:
| Category | Weight | Examples |
|---|---|---|
| Security | 25% | Branch protection, Dependabot, code scanning |
| Testing | 20% | Test configs, coverage, CI test jobs |
| CI/CD | 15% | Workflows, deployment, status checks |
| Documentation | 15% | README, CONTRIBUTING, issue templates |
| Code Quality | 10% | Linters, code owners |
| Maintenance | 10% | Recent activity, description |
| Community | 5% | Community health files |
Sync a repository and use Refresh grade on its detail page to compute or update its score. The dashboard summary shows average score across repos.
This project uses GitHub OAuth App for user authentication (simpler than GitHub Apps).
-
Click OAuth Apps → New OAuth App
-
Fill in the details:
- Application name:
Snorlx Dashboard(or your preferred name) - Homepage URL:
http://localhost:5173(or your production URL) - Authorization callback URL:
http://localhost:8080/api/auth/callback
- Application name:
-
Click Register application
- Copy the Client ID
- Click Generate a new client secret and copy it
Add to your .env file:
GITHUB_CLIENT_ID=your_client_id_here
GITHUB_CLIENT_SECRET=your_client_secret_hereThe app requests these OAuth scopes:
read:user- Read user profile informationuser:email- Access user email addressesrepo- Access repositories (for workflow data)read:org- Read organization membership
For real-time updates via webhooks, configure a webhook in your repository/organization settings:
- Go to Repository → Settings → Webhooks → Add webhook
- Payload URL:
https://your-domain.com/api/webhooks/github - Content type:
application/json - Secret: Generate a secure secret and add to
.envasGITHUB_WEBHOOK_SECRET - Select events:
Workflow runs,Workflow jobs,Deployments
| Variable | Required | Default | Description |
|---|---|---|---|
STORAGE_MODE |
No | memory |
memory or database |
DATABASE_URL |
Only if database mode |
- | PostgreSQL connection string |
POSTGRES_PASSWORD |
Only if database mode |
- | PostgreSQL password (used by Docker Compose) |
| Variable | Description | Default |
|---|---|---|
PORT |
Server port | 8080 |
LOG_LEVEL |
Logging level (debug, info, warn, error) | info |
SESSION_SECRET |
Session encryption key | Required |
FRONTEND_URL |
Frontend URL for CORS | http://localhost:5173 |
VITE_API_URL |
Backend API URL for the frontend | http://localhost:8080 |
| Variable | Description | Required |
|---|---|---|
GITHUB_CLIENT_ID |
GitHub OAuth App Client ID | Yes |
GITHUB_CLIENT_SECRET |
GitHub OAuth App Client Secret | Yes |
GITHUB_WEBHOOK_SECRET |
Webhook signature secret | No (for webhooks only) |
DEV_MODE |
Skip GitHub OAuth validation | No |
| Variable | Required | Default | Description |
|---|---|---|---|
SYNC_LIMIT |
No | 0 (all) |
Limit number of repos to sync |
SYNC_REPOS |
No | - | Comma-separated list of specific repos to sync |
GET /health- Health check endpoint
GET /api/auth/login- Initiate GitHub OAuthGET /api/auth/callback- OAuth callbackPOST /api/auth/logout- LogoutGET /api/auth/status- Check auth status
GET /api/organizations- List all organizationsGET /api/organizations/:id- Get organization details
GET /api/repositories- List all repositoriesGET /api/repositories/:id- Get repository detailsGET /api/repositories/scores- List latest repository scores (all repos)GET /api/repositories/:id/score- Get latest score for a repositoryPOST /api/repositories/sync- Trigger repository sync
GET /api/workflows- List all workflowsGET /api/workflows/:id- Get workflow detailsPATCH /api/workflows/:id- Update workflowGET /api/workflows/:id/runs- Get workflow runs
GET /api/runs- List all runs (with filters)GET /api/runs/:id- Get run detailsGET /api/runs/:id/jobs- Get run jobsGET /api/runs/:id/logs- Get run logsGET /api/runs/:id/annotations- Get run annotationsGET /api/runs/:id/workflow-definition- Get workflow YAML definitionPOST /api/runs/:id/rerun- Rerun a workflowPOST /api/runs/:id/cancel- Cancel a running workflow
GET /api/jobs/:id/logs- Get job logs
GET /api/dashboard/summary- Get dashboard summaryGET /api/dashboard/trends- Get trend data
GET /ws- WebSocket endpoint for real-time updates
POST /api/webhooks/github- GitHub webhook receiver
├── .github/workflows/ # CI and Security GitHub Actions
├── frontend/ # React frontend
│ ├── src/
│ │ ├── components/ # UI components (layout, protected routes)
│ │ ├── context/ # React contexts (auth, theme, socket, sync, sidebar)
│ │ ├── lib/ # Utility functions
│ │ ├── pages/ # Page components
│ │ ├── services/ # API client
│ │ ├── styles/ # Global styles
│ │ ├── test/ # Test setup
│ │ └── types/ # TypeScript types
│ └── ...
├── backend/ # Go backend
│ ├── cmd/server/ # Main entry point
│ ├── internal/
│ │ ├── config/ # Configuration
│ │ ├── database/ # Database migrations and setup
│ │ ├── github/ # GitHub client
│ │ ├── handlers/ # HTTP handlers
│ │ ├── models/ # Data models
│ │ ├── scorer/ # Repository scoring (gold/silver/bronze)
│ │ ├── storage/ # Storage layer (memory/database)
│ │ └── websocket/ # WebSocket hub for real-time updates
│ └── ...
├── helm/ # Kubernetes Helm charts
└── docker-compose.yml # Docker configuration
Backend won't start: GitHub OAuth credentials required
- Set
DEV_MODE=truein your.envfile for local development (skips OAuth) - Or provide
GITHUB_CLIENT_IDandGITHUB_CLIENT_SECRETfrom a GitHub OAuth App
Database connection errors
- Verify PostgreSQL is running:
psql -U postgres -d snorlx - Check
DATABASE_URLin.envmatches your database credentials - Ensure TimescaleDB extension is installed
Port already in use (EADDRINUSE)
- Backend (8080) or Frontend (5173) port is already taken
- Find process:
lsof -i :8080orlsof -i :5173 - Kill process:
kill -9 <PID> - Or change port in
.env
Memory mode data is lost
- This is expected! Memory mode doesn't persist data between restarts
- Use
STORAGE_MODE=databasefor persistent storage
"Too many requests" error
- Rate limiting is active. Wait and retry
- In production, this prevents abuse
The project includes two GitHub Actions workflows:
Runs on push and pull requests to main:
- Backend: Go vet, tests with race detector and coverage, binary build
- Frontend: Lint, tests with coverage, production build
Runs on push, pull requests to main, and weekly (Monday 08:00 UTC):
- CodeQL Analysis: Static analysis for Go and JavaScript/TypeScript
- Trivy Scans: Filesystem vulnerability scan plus Docker image scans for both backend and frontend
- Dependency Review: Flags newly introduced vulnerable dependencies on PRs
- Go Security: govulncheck and gosec for Go-specific vulnerabilities
- npm Audit: Checks for known vulnerabilities in Node packages
This application follows the 12-Factor methodology:
- Codebase: Single repo tracked in Git
- Dependencies: Explicitly declared in
go.modandpackage.json - Config: Environment variables for all configuration
- Backing services: Database as attached resource via URL
- Build, release, run: Docker images with semantic versioning
- Processes: Stateless; sessions in storage
- Port binding: Self-contained HTTP server
- Concurrency: Horizontal scaling via replicas
- Disposability: Graceful shutdown on SIGTERM
- Dev/prod parity: Docker Compose mirrors production
- Logs: JSON to stdout, collected by platform
- Admin processes: Migrations as part of startup
MIT License - see LICENSE for details.

