π GitHub Network Explorer β Implementation Plan
Overview
A stateless web application that extends the GitHub Repository Network Graph, providing an interactive, data-rich visualization of the relationships between branches, commits, tags, and pull requests. All data is fetched on-demand from the GitHub API via a GitHub App, with no persistent database.
Stitch Design Reference: GitGraph - GitHub Network Graph Explorer
Design System: "GitGraph Obsidian" β dark mode, glassmorphism, Inter + JetBrains Mono
ποΈ Architecture
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β CLIENT (React) β
β ββββββββββββ ββββββββββββββββ βββββββββββββββββββββ β
β β Auth Flow β β DAG Rendererβ β Detail Panels β β
β β (OAuth) β β (d3-dag) β β (Branches/PRs) β β
β ββββββ¬ββββββ ββββββββ¬ββββββββ ββββββββββ¬βββββββββββ β
β β β β β
β βββββββββββββββββΌβββββββββββββββββββββ β
β β β
β ββββββββββΌβββββββββ β
β β API Client β β
β β (GraphQL + β β
β β REST hybrid) β β
β ββββββββββ¬βββββββββ β
βββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββββ
β HTTPS
βββββββββββΌββββββββββ
β API GATEWAY β
β (Express/Node) β
β β
β βββββββββββββββ β
β β GitHub App β β
β β Auth Layer β β
β ββββββββ¬βββββββ β
β β β
β ββββββββΌβββββββ β
β β Cache Layer β β
β β (In-memory β β
β β + TTL) β β
β ββββββββ¬βββββββ β
β β β
β ββββββββΌβββββββ β
β β GraphQL + β β
β β REST Client β β
β ββββββββ¬βββββββ β
βββββββββββΌββββββββββ
β
βββββββββββΌββββββββββ
β GitHub API v4 β
β (GraphQL) + β
β GitHub API v3 β
β (REST fallback) β
βββββββββββββββββββββ
π Screens (from Stitch Design)
Screen 1: Dashboard β Network Graph Explorer
- Main DAG visualization (60% viewport) β interactive commit graph
- Right sidebar (30%) β selected commit/node detail panel
- Bottom stats bar β repo health metrics (commits, branches, PRs, releases)
- Left nav β collapsed icon sidebar (Dashboard, Branches, Tags, PRs, Settings)
- Top nav β repo selector, branch filter pills, time range, user avatar
Screen 2: Branches Management
- Branch list table with status, ahead/behind, linked PRs
- Search/filter bar, branch comparison panel
- Create/delete/archive actions
Screen 3: Pull Requests Feed
- PR cards in vertical feed with status badges, CI/CD indicators
- Filter tabs (Open/Closed/All), search, sort
- PR detail preview panel
π Authentication & Authorization
GitHub App Setup
- Create GitHub App with the following permissions:
- Repository:
contents: read, metadata: read, pull_requests: read, commit_statuses: read
- Organization:
members: read (optional, for org repos)
- OAuth flow for user authentication:
- User clicks "Connect with GitHub" β OAuth redirect
- Exchange code for user access token
- Store token in session (httpOnly cookie, no DB)
- Installation token for API access:
- GitHub App installation provides higher rate limits (5,000 β 15,000 req/hr)
- Use installation token for data fetching, user token for user-specific operations
Auth Flow
User β "Connect with GitHub" β GitHub OAuth β Callback with code
β Exchange code for token β Set httpOnly session cookie
β Redirect to dashboard β Fetch repos user has access to
π‘ Data Fetching Strategy
Primary: GitHub GraphQL API (v4)
GraphQL is the primary data source β it reduces roundtrips dramatically compared to REST.
Key Queries
1. Repository Overview + Refs (branches, tags)
query RepoOverview($owner: String!, $name: String!) {
repository(owner: $owner, name: $name) {
defaultBranchRef { name target { oid } }
refs(refPrefix: "refs/heads/", first: 100, orderBy: {field: TAG_COMMIT_DATE, direction: DESC}) {
nodes {
name
target { oid ... on Commit { committedDate author { name avatarUrl } message } }
}
}
tags: refs(refPrefix: "refs/tags/", first: 50, orderBy: {field: TAG_COMMIT_DATE, direction: DESC}) {
nodes {
name
target { oid ... on Tag { target { oid } tagger { date } message } }
}
}
pullRequests(first: 50, states: [OPEN, MERGED], orderBy: {field: UPDATED_AT, direction: DESC}) {
nodes {
number title state author { login avatarUrl }
headRefName baseRefName
mergeCommit { oid }
commits(last: 1) { nodes { commit { oid } } }
reviews(first: 5) { nodes { state author { login } } }
labels(first: 5) { nodes { name color } }
}
}
}
}
2. Commit History (per branch, paginated)
query BranchHistory($owner: String!, $name: String!, $branch: String!, $cursor: String) {
repository(owner: $owner, name: $name) {
ref(qualifiedName: $branch) {
target {
... on Commit {
history(first: 100, after: $cursor) {
pageInfo { hasNextPage endCursor }
nodes {
oid
message
committedDate
author { name email avatarUrl user { login } }
parents(first: 5) { nodes { oid } }
additions
deletions
changedFilesIfAvailable
associatedPullRequests(first: 1) { nodes { number title state } }
status { state contexts { context state targetUrl } }
}
}
}
}
}
}
}
3. Commit Detail (on-demand, when user clicks a node)
query CommitDetail($owner: String!, $name: String!, $oid: GitObjectID!) {
repository(owner: $owner, name: $name) {
object(oid: $oid) {
... on Commit {
oid message committedDate
author { name email avatarUrl user { login } }
parents(first: 5) { nodes { oid abbreviatedOid message } }
additions deletions changedFilesIfAvailable
associatedPullRequests(first: 3) { nodes { number title state url } }
tree { entries { name type } }
}
}
}
}
Fallback: REST API (v3)
Used only when GraphQL doesn't expose what we need:
- Compare API (
GET /repos/{owner}/{repo}/compare/{base}...{head}) β for ahead/behind counts between branches
- Commit diff files (
GET /repos/{owner}/{repo}/commits/{sha}) β for file-level diff stats (if GraphQL tree isn't sufficient)
ποΈ DAG Construction Algorithm
This is the core logic β transforming flat commit lists into a renderable graph.
Step 1: Fetch & Merge Commit Histories
For each visible branch:
1. Fetch last N commits (paginated via GraphQL)
2. Collect into a Map<SHA, CommitNode>
3. Deduplicate (same commit may appear in multiple branches)
Step 2: Build the DAG
interface CommitNode {
sha: string;
message: string;
author: { name: string; avatar: string };
timestamp: Date;
parents: string[]; // parent SHAs
children: string[]; // computed
branches: string[]; // which branches contain this commit
tags: string[]; // associated tags
prs: PRReference[]; // associated PRs
isMerge: boolean; // parents.length > 1
lane: number; // computed β which visual column
}
// Build adjacency:
commits.forEach(c => {
c.parents.forEach(parentSha => {
const parent = commitMap.get(parentSha);
if (parent) parent.children.push(c.sha);
});
c.isMerge = c.parents.length > 1;
});
Step 3: Lane Assignment (visual layout)
1. Topological sort commits by timestamp (newest first)
2. Assign "lanes" (columns) to branches:
- main/master β lane 0 (leftmost)
- develop β lane 1
- feature branches β lanes 2+
3. When branches merge, collapse lanes
4. When branches fork, expand lanes
Step 4: Render with d3-dag
- Use d3-dag library for DAG layout computation
- Each CommitNode β SVG circle (or diamond for merges)
- Each parentβchild relationship β SVG path (curved BΓ©zier)
- Color-code by branch assignment
- Add interactive layers: hover tooltips, click β detail panel
πΎ Caching Strategy (Stateless, No Database)
Server-Side Cache (In-Memory with TTL)
// Using node-cache or Map with TTL wrapper
const cache = new NodeCache({ stdTTL: 300, checkperiod: 60 }); // 5 min default
// Cache keys:
// `repo:${owner}/${repo}:overview` β branches, tags, PRs summary
// `repo:${owner}/${repo}:branch:${name}:commits` β commit history per branch
// `repo:${owner}/${repo}:commit:${sha}` β individual commit detail
// Conditional requests (ETag/If-Modified-Since):
// GitHub returns 304 Not Modified β doesn't count against rate limit
Client-Side Cache
// React Query / TanStack Query with stale-while-revalidate
const { data } = useQuery({
queryKey: ['repo', owner, repo, 'commits', branch],
queryFn: () => fetchBranchCommits(owner, repo, branch),
staleTime: 2 * 60 * 1000, // 2 min stale
gcTime: 10 * 60 * 1000, // 10 min garbage collect
refetchOnWindowFocus: true,
});
Webhook-Based Invalidation (via GitHub App)
GitHub App webhooks β API Gateway:
- `push` event β invalidate branch commit cache
- `create`/`delete` event β invalidate refs cache
- `pull_request` event β invalidate PR cache
Notify connected clients via Server-Sent Events (SSE):
Client subscribes: GET /api/events?repo=owner/repo
Server pushes: { type: "cache_invalidated", scope: "branch:main" }
Client refetches affected queries
π¦ Tech Stack
| Layer |
Technology |
Rationale |
| Frontend |
React 19 + Vite |
Fast builds, modern React features |
| State Management |
TanStack Query v5 |
Built-in caching, deduplication, stale-while-revalidate |
| Graph Rendering |
d3-dag + d3.js |
Purpose-built DAG layout + SVG rendering |
| UI Components |
Tailwind CSS + shadcn/ui |
Matches Obsidian dark theme, utility-first |
| Backend |
Express.js (Node 22) |
Lightweight, pairs well with GitHub SDKs |
| GitHub SDK |
@octokit/graphql + @octokit/rest |
Official GitHub client libraries |
| Cache |
node-cache (in-memory) |
No DB dependency, TTL-based eviction |
| Real-time |
Server-Sent Events (SSE) |
Simpler than WebSockets for one-way push |
| Auth |
GitHub App OAuth + JWT sessions |
Stateless sessions, no DB needed |
| Deployment |
Docker + Docker Compose |
Single container, easy self-hosting |
| CI/CD |
GitHub Actions |
Dogfooding β running CI on the platform we visualize |
π Rate Limit Budget
| Operation |
API Calls |
Frequency |
Notes |
| Repo overview (branches, tags, PRs) |
1 GraphQL |
Per repo load |
Single query, cached 5min |
| Branch commit history (100 commits) |
1 GraphQL per branch |
On-demand |
Paginate if needed |
| Full graph (5 branches Γ 100 commits) |
~5 GraphQL |
Initial load |
Parallelized |
| Commit detail |
1 GraphQL |
On click |
Cached per SHA |
| Branch comparison (ahead/behind) |
1 REST per pair |
On-demand |
REST Compare API |
| Total initial load |
~7 requests |
Per repo |
Well within 5,000/hr |
With GitHub App installation tokens: 15,000 req/hr β supports ~2,000 full repo loads per hour.
ποΈ Implementation Phases
Phase 1: Foundation (MVP)
Phase 2: Core Features
Phase 3: Views & Navigation
Phase 4: Real-Time & Polish
Phase 5: Advanced Features
π Project Structure
github-network-explorer/
βββ client/ # React frontend
β βββ src/
β β βββ components/
β β β βββ graph/ # DAG renderer, nodes, edges, minimap
β β β βββ layout/ # TopNav, Sidebar, BottomStats
β β β βββ panels/ # CommitDetail, BranchComparison
β β β βββ ui/ # shadcn components
β β βββ features/
β β β βββ dashboard/ # Main graph dashboard
β β β βββ branches/ # Branches management
β β β βββ pullrequests/ # PR feed
β β βββ hooks/ # useCommitHistory, useBranches, etc.
β β βββ lib/ # API client, DAG algorithms
β β βββ styles/ # Tailwind config, Obsidian theme
β βββ vite.config.ts
βββ server/ # Express API gateway
β βββ src/
β β βββ routes/ # /api/repos, /api/graph, /api/events
β β βββ services/ # GitHubService, CacheService
β β βββ middleware/ # auth, rateLimit, errorHandler
β β βββ utils/ # graphql queries, helpers
β βββ package.json
βββ docker-compose.yml
βββ Dockerfile
βββ README.md
π¨ Design Assets
- Stitch Project: https://stitch.withgoogle.com/projects/17186966880677404423
- Design System: GitGraph Obsidian (dark mode, glassmorphism)
- Color Palette:
- Background:
#0d1117 (deep slate)
- Primary:
#58a6ff (electric blue)
- Success/Merged:
#3fb950 (green)
- PR/Secondary:
#bc8cff (purple)
- Warning:
#d29922 (orange)
- Error:
#f85149 (red)
- Muted text:
#8b949e (gray)
- Typography: Inter (UI), JetBrains Mono (code/SHAs)
- Key Patterns: Glassmorphism panels, tonal layering (no hard borders), gradient CTAs
πΌοΈ Design Screenshots (from Stitch)
Full interactive designs: GitGraph Stitch Project
1. Repository Network Dashboard

2. Dashboard Graph Explorer

3. Branches Management

4. Pull Requests Feed

π GitHub Network Explorer β Implementation Plan
Overview
A stateless web application that extends the GitHub Repository Network Graph, providing an interactive, data-rich visualization of the relationships between branches, commits, tags, and pull requests. All data is fetched on-demand from the GitHub API via a GitHub App, with no persistent database.
Stitch Design Reference: GitGraph - GitHub Network Graph Explorer
Design System: "GitGraph Obsidian" β dark mode, glassmorphism, Inter + JetBrains Mono
ποΈ Architecture
π Screens (from Stitch Design)
Screen 1: Dashboard β Network Graph Explorer
Screen 2: Branches Management
Screen 3: Pull Requests Feed
π Authentication & Authorization
GitHub App Setup
contents: read,metadata: read,pull_requests: read,commit_statuses: readmembers: read(optional, for org repos)Auth Flow
π‘ Data Fetching Strategy
Primary: GitHub GraphQL API (v4)
GraphQL is the primary data source β it reduces roundtrips dramatically compared to REST.
Key Queries
1. Repository Overview + Refs (branches, tags)
2. Commit History (per branch, paginated)
3. Commit Detail (on-demand, when user clicks a node)
Fallback: REST API (v3)
Used only when GraphQL doesn't expose what we need:
GET /repos/{owner}/{repo}/compare/{base}...{head}) β for ahead/behind counts between branchesGET /repos/{owner}/{repo}/commits/{sha}) β for file-level diff stats (if GraphQLtreeisn't sufficient)ποΈ DAG Construction Algorithm
This is the core logic β transforming flat commit lists into a renderable graph.
Step 1: Fetch & Merge Commit Histories
Step 2: Build the DAG
Step 3: Lane Assignment (visual layout)
Step 4: Render with d3-dag
πΎ Caching Strategy (Stateless, No Database)
Server-Side Cache (In-Memory with TTL)
Client-Side Cache
Webhook-Based Invalidation (via GitHub App)
π¦ Tech Stack
π Rate Limit Budget
With GitHub App installation tokens: 15,000 req/hr β supports ~2,000 full repo loads per hour.
ποΈ Implementation Phases
Phase 1: Foundation (MVP)
Phase 2: Core Features
Phase 3: Views & Navigation
Phase 4: Real-Time & Polish
Phase 5: Advanced Features
π Project Structure
π¨ Design Assets
#0d1117(deep slate)#58a6ff(electric blue)#3fb950(green)#bc8cff(purple)#d29922(orange)#f85149(red)#8b949e(gray)πΌοΈ Design Screenshots (from Stitch)
1. Repository Network Dashboard
2. Dashboard Graph Explorer
3. Branches Management
4. Pull Requests Feed