A self-hosted dashboard that shows open pull requests for a GitHub team. It surfaces PRs that need review, PRs that have been reviewed but have new commits since, and stale PRs — filtered to repos where the team has admin ownership.
- Needs re-review — PRs that were reviewed but have new commits pushed since
- Team PRs — open PRs authored by team members awaiting first review
- All PRs — every open PR across team-owned repos
- Stale PRs — PRs with no activity in the last 14 days
- Needs merging — approved PRs that are ready to land
- Dependency drift — tracks whether key packages are on their latest version across all team repos
- Grouped by Jira ticket — optionally links back to your Jira instance
- Slack summary — post a formatted PR digest to a Slack channel on demand
- Background cache warming every 20 minutes (configurable)
- Node.js 22+
- A GitHub Personal Access Token with
read:organdreposcopes, authorised for SSO if your org uses it
cp .env.example .env
# edit .env with your values
npm install
npm startThe app will be available at http://localhost:3000.
All configuration is via environment variables. Copy .env.example to .env and fill in the values.
| Variable | Required | Description |
|---|---|---|
GITHUB_TOKEN |
Yes | Personal access token with read:org and repo scopes |
GITHUB_ORG |
Yes | GitHub organisation name |
GITHUB_TEAM |
Yes | Team slug within the org |
JIRA_TICKET_PATTERN |
No | Regex pattern to extract ticket refs from PR titles/branches (e.g. ABC-\d+). Must be set together with JIRA_BASE_URL |
JIRA_BASE_URL |
No | Base URL for Jira links, no trailing slash (e.g. https://yourorg.atlassian.net/browse). Must be set together with JIRA_TICKET_PATTERN |
APP_URL |
No | Public URL of this app. Used in Slack message footers |
PORT |
No | Server port. Default: 3000 |
CACHE_TTL_MS |
No | Cache TTL in milliseconds. Default: 1200000 (20 minutes) |
SLACK_BOT_TOKEN |
No | Slack bot token (xoxb-…) to enable Slack summaries |
SLACK_CHANNEL_ID |
No | Slack channel ID to post summaries to |
TRACKED_DEPENDENCIES |
No | Comma-separated list of ecosystem:package pairs to track on the Dependencies page (e.g. npm:express,npm:lodash,pypi:requests) |
REQUIRED_TEAM_ROLE |
No | Minimum GitHub team role a repo must have to appear in any view. One of pull, triage, push, maintain, admin. Default: admin |
The /dependencies page shows whether each tracked package is on its latest published version across all team repos. It supports npm (package.json) and PyPI (requirements.txt).
Set TRACKED_DEPENDENCIES to a comma-separated list of ecosystem:package pairs:
TRACKED_DEPENDENCIES=npm:express,npm:lodash,pypi:requests,pypi:boto3Each cell in the matrix shows the pinned version in that repo. Cells highlighted in amber are behind the latest version; a — means the package isn't present in that repo at all.
Results are cached alongside the PR data and cleared when you hit Refresh.
Only repositories where the configured team has the required role are included. The role is controlled by REQUIRED_TEAM_ROLE (default: admin). Valid values mirror GitHub's team permission levels: pull, triage, push, maintain, admin. Repos below the configured threshold are excluded from all views.
docker build -t pr-viewer .
docker run -p 3000:3000 --env-file .env pr-viewerA pre-built image is published to GitHub Container Registry on every push to main:
docker pull ghcr.io/nodepoint-solutions/github-team-pr-viewer:latestThis was originally built for a development team within @defra, so it reflects their standard stack:
- Hapi — Node.js web framework
- Nunjucks — server-side HTML templating
- hapi-pino — structured request logging
npm run dev # starts with file watching
npm test # run tests