A PR-management dashboard for the mozilla-mobile/firefox-ios
team, built to expand to mozilla-central / Phabricator later.
It helps developers keep track of their own PRs, PRs assigned to them, and mentions — and surfaces repository-wide statistics and trends. It can optionally push live updates to a developer's Slack DM.
The whole system is built around a provider abstraction so the same dashboard, stats, and notification logic run over any code-review source. GitHub ships first; Phabricator plugs in later without touching the UI or the stats engine.
Personal dashboard (per logged-in developer)
- Open PRs where they are a requested reviewer ("assigned").
- Open PRs that @-mention them (body + comments).
- Their own PRs, split into:
- Waiting for review — no human
CHANGES_REQUESTED/ human response since last commit. - Changes requested — a human requested changes since the last commit.
- Waiting for review — no human
- Stale PRs: open >
Xhours (default 48, configurable) with no human response. - PRs open > 1 week.
Slack integration (opt-in, per developer)
- Bot opens a DM with the developer and posts updates for events tied to their username: their PRs, review-requests, and @-mentions. Each notification type is toggleable.
Stats (repo-wide, filterable by contributor; bots excluded)
- Average time to merge · time to first human comment · average PR size (LOC).
- Closed / rejected PR counts.
- PRs tagged with the "ignore code coverage" label.
- Code-coverage reported by Danger over time.
- All metrics are trended over a configurable time range.
| Layer | Choice |
|---|---|
| Frontend | React + TypeScript + Vite, @primer/react (GitHub's design system), TanStack Query, Recharts |
| Backend | Python 3.12, FastAPI (async), Pydantic v2, SQLAlchemy 2.0 + Alembic |
| GitHub | githubkit — async, GitHub App auth, REST + GraphQL + webhooks |
| Slack | Slack Bolt for Python |
| Data | Cloud SQL (Postgres). Stat snapshots are BigQuery-export-ready. |
| Runtime | Cloud Run (API) + Cloud Run Jobs (polling) + Cloud Tasks (async fan-out) + Cloud Scheduler |
| Secrets | Secret Manager |
| IaC | Terraform |
See ARCHITECTURE.md for the module layout and the provider model.
pr-radar/
├── backend/ FastAPI app, providers, services, jobs
├── frontend/ React + Primer dashboard
├── infra/ Terraform for GCP
├── docker-compose.yml Local dev (postgres + backend + frontend)
└── .env.example
Prereqs: Docker + Docker Compose, Python 3.12, Node 20+.
cp .env.example .env # fill in the GitHub App + Slack creds
docker compose up --build # postgres + backend (:8000) + frontend (:5173)Backend only (against a local postgres):
cd backend
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
alembic upgrade head
uvicorn app.main:app --reloadFrontend only:
cd frontend
npm install
npm run devFor quickly running and reviewing the UI — and as the basis for UI tests — the
frontend has a mock mode powered by MSW. It intercepts every
/api/* call and serves fixtures from src/mocks/fixtures.ts, and the mock
/api/auth/me bypasses login so you land straight on the dashboard.
cd frontend
npm install
npm run msw:init # once: writes public/mockServiceWorker.js (committed)
npm run dev:mock # http://localhost:5173 with fake data, no backendnpm run build:mock produces a static, fully-mocked bundle (handy for design review
or hosting a preview).
UI tests (Playwright) run against the same mock mode — no services required:
cd frontend
npx playwright install chromium # once
npm run test:e2e # boots dev:mock automatically, runs specs
npm run test:e2e:ui # interactive runnerMock layout:
src/mocks/fixtures.ts— the fake data (edit to change what the UI shows).src/mocks/handlers.ts— MSW route handlers (shared by dev mock + tests).src/mocks/browser.ts— the browser worker, started frommain.tsxwhenVITE_MOCK=1.tests/e2e/— Playwright specs;playwright.config.tsbootsdev:mock.
All config is environment-driven (see .env.example and backend/app/config.py).
Key knobs:
STALE_PR_HOURS— default staleness threshold (default48).GITHUB_APP_ID,GITHUB_APP_PRIVATE_KEY,GITHUB_WEBHOOK_SECRET— GitHub App.GITHUB_OAUTH_CLIENT_ID/_SECRET— developer login.ALLOWED_GITHUB_ORG— org whose members may log in (defaultmozilla-mobile).SLACK_BOT_TOKEN,SLACK_SIGNING_SECRET— Slack app.
This is a scaffold. Core domain logic (PR status classification, staleness, stats)
is implemented against the normalized model. Anything requiring live credentials
(GitHub App calls, Slack posting, OAuth) is wired but marked # TODO(cred) where a
real secret / installation is needed. See ARCHITECTURE.md → "Build plan".