Skip to main content
The MergeWatch dashboard is a Next.js application that provides a web UI for managing reviews, repositories, and settings. It authenticates users with GitHub OAuth and connects to the MergeWatch backend API.
MergeWatch landing page

Deployment

In self-hosted mode, the dashboard ships as a second service in your docker-compose.yml alongside the MergeWatch server and Postgres.

Docker Compose configuration

The dashboard service is already included in the default docker-compose.yml. Here is the relevant section:
docker-compose.yml
dashboard:
  image: ghcr.io/santthosh/mergewatch-dashboard:0.1.0
  restart: unless-stopped
  environment:
    DEPLOYMENT_MODE: self-hosted
    DATABASE_URL: postgres://postgres:postgres@db:5432/mergewatch
    NEXTAUTH_URL: ${DASHBOARD_URL:-http://localhost:3001}
    NEXTAUTH_SECRET: ${NEXTAUTH_SECRET}
    GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID}
    GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET}
    PORT: "3001"
  ports:
    - "3001:3001"
  depends_on:
    mergewatch:
      condition: service_healthy

Environment variables

Add these to your .env file:
VariableRequiredDescription
GITHUB_CLIENT_IDYesOAuth client ID from your GitHub App’s OAuth Credentials section (same App, not a separate OAuth App)
GITHUB_CLIENT_SECRETYesOAuth client secret from your GitHub App
NEXTAUTH_SECRETYesRandom secret for NextAuth session signing. Generate with openssl rand -base64 32
DASHBOARD_URLNoPublic URL of the dashboard. Docker Compose wires this into NEXTAUTH_URL. Defaults to http://localhost:3001.
The dashboard reads from the MergeWatch Postgres database directly via DATABASE_URL — there is no HTTP call from the dashboard to the Express server, so no NEXT_PUBLIC_API_URL is required.

Start the dashboard

The dashboard starts automatically with the rest of the stack:
docker compose up -d
Access the dashboard at http://localhost:3001.

Upgrade

docker compose pull dashboard
docker compose up -d dashboard

GitHub authentication

MergeWatch sign-in page
The dashboard uses NextAuth.js with the GitHub provider. The same GitHub App that handles webhooks also authenticates users — there is no separate OAuth app.

GitHub scopes requested

MergeWatch requests the minimum scopes needed:
ScopeWhy
read:userGet authenticated user’s profile and username
user:emailDisplay user identity in the dashboard header
The GitHub App installation permissions (not OAuth scopes) handle repository access — the OAuth login is purely for identity, not code access.

Organization support

  • Org installation — when a GitHub App is installed on an org, any org member with admin rights can access the dashboard for that installation
  • Access check — the dashboard calls GET /orgs/{org}/members/{username} with role=admin to verify the user is an org admin before showing settings controls
  • Multiple installations — a single user can have multiple installations (personal + multiple orgs). The dashboard shows all installations and lets them switch between them
  • No separate org concept — GitHub’s own org membership model is the source of truth for access control

Session model

Sessions are stored as encrypted JWT cookies (default NextAuth behavior). No session database is needed. The JWT contains:
  • GitHub user ID and username
  • OAuth access token (for GitHub API calls from the frontend)
  • Installation IDs the user has access to
Session expiry defaults to 30 days.

Connecting dashboard to backend

The dashboard’s Next.js API routes read from the same data store the webhook pipeline writes to — Postgres in self-hosted mode and DynamoDB in SaaS mode. There is no HTTP call from the dashboard to the Express/Lambda webhook server, so no public API URL environment variable is required. Access control lives in each /api/* route: it validates the NextAuth session, calls the GitHub API with the user’s OAuth token to confirm installation access, then reads/writes the store.

Troubleshooting

Run npm ci locally and confirm the build passes before pushing. Check that package-lock.json is committed.
The NEXTAUTH_SECRET or NEXTAUTH_URL environment variables are missing or incorrect. Confirm NEXTAUTH_URL exactly matches your dashboard URL (no trailing slash).
The dashboard cannot reach its data store. For self-hosted, verify DATABASE_URL resolves inside the container (the db service must be healthy — docker compose ps should show it as healthy). For SaaS, confirm the dashboard’s IAM role can read the MergeWatch DynamoDB tables.
Add your dashboard URL to your GitHub App’s Callback URLs in GitHub App settings (Settings > Developer settings > GitHub Apps > your app > General > Callback URL).
Confirm the GITHUB_APP_ID matches your deployed GitHub App. Mismatches cause installation lookups to return empty results.

Dashboard Overview

Learn about the dashboard pages and access control model.

Self-Hosting Install

Deploy the full stack with Docker Compose.