Skip to content

feat: add project admin scoring and dashboard#7

Closed
Ixotic27 wants to merge 9 commits into
PRODHOSH:mainfrom
Ixotic27:feat/project-admin-page
Closed

feat: add project admin scoring and dashboard#7
Ixotic27 wants to merge 9 commits into
PRODHOSH:mainfrom
Ixotic27:feat/project-admin-page

Conversation

@Ixotic27

Copy link
Copy Markdown

Adds a Project Admin tracking dashboard under /project-admin/[username], dynamic scoring engine for merge, label, open issue events, and resolution time boost. Also resolves Next.js dynamic path collision and adds dual-role cross-navigation notices.

Copilot AI review requested due to automatic review settings June 26, 2026 04:40
@vercel

vercel Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

@Ixotic27 is attempting to deploy a commit to the prodhoshvs2025-8980's projects Team on Vercel.

A member of the Team first needs to authorize it.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new “Project Admin” role and dashboard to track admin activity across registered GSSoC repositories, backed by a new GitHub-driven scoring engine and surfaced via cross-navigation notices from the contributor dashboard and home role selector.

Changes:

  • Introduces a server-side admin scoring builder (buildAdminScore) that pulls PR/issue data from the GitHub Search API and computes a per-repo breakdown + totals.
  • Adds a new /project-admin/[username] aggregate dashboard and updates /project-admin/[username]/[repo] to display admin points + a scoring guide.
  • Updates UI entry points (Home role selector, points guide modal, contributor dashboard) to include the Project Admin role and dual-role navigation.

Reviewed changes

Copilot reviewed 6 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/lib/admin-scoring.ts New scoring engine that fetches repo PRs/issues from GitHub and computes admin points.
src/components/HomePointsGuide.tsx Adds a “Project Admin” tab explaining the new scoring rules.
src/app/project-admin/[username]/page.tsx New aggregate admin dashboard for a user across registered repos.
src/app/project-admin/[username]/[repo]/page.tsx Enhances repo-level admin page to show admin scoring stats + guide.
src/app/pr-tracker/[username]/page.tsx Adds “dual-role” notice + link to admin dashboard when applicable.
src/app/page.tsx Adds “Project Admin” as a selectable role and routes search accordingly.
package-lock.json Lockfile updates from dependency resolution changes.
Comments suppressed due to low confidence (1)

src/app/project-admin/[username]/[repo]/page.tsx:169

  • This sub text is a literal string ("by @owner ...") so the UI will render @owner instead of the actual username.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/lib/admin-scoring.ts
Comment on lines +98 to +101
// 1. Merged PRs with gssoc:approved
// Note: search issues item has `pull_request` and `pull_request.merged_at` check
const mergedPRsCount = prs.filter((pr) => !!pr.pull_request?.merged_at || pr.state === "closed").length;
const mergedPRsPoints = mergedPRsCount * 15;
Comment thread src/lib/admin-scoring.ts
Comment on lines +37 to +38
const q = `label:"gssoc:approved" repo:${owner}/${repo} type:pr`;
const url = `https://api.github.com/search/issues?q=${encodeURIComponent(q)}&per_page=100&sort=created&order=desc`;
Comment thread src/lib/admin-scoring.ts
Comment on lines +118 to +127
// Check difficulty: starts with level:
const hasDifficulty = labelNames.some((name: string) => name.startsWith("level:"));
// Check type: starts with type:
const hasType = labelNames.some((name: string) => name.startsWith("type:"));

if (hasDifficulty && hasType) {
labeledIssuesFullCount++;
} else if (hasDifficulty) {
labeledIssuesDiffCount++;
}
@Ixotic27

Copy link
Copy Markdown
Author

Hello! I have updated the branch to resolve the feedback:

  1. Merged PR Query: Updated the GitHub Search API query for PRs to include \is:merged. This ensures we retrieve only successfully merged PRs, resolving the issue where \pull_request.merged_at\ is not included in search issues results.
  2. Simplified Counting: Simplified \mergedPRsCount\ to use \prs.length\ now that the search query filters for merged PRs directly.
  3. Labeled Issues Documentation: Added a technical comment in admin-scoring.ts explaining the design trade-off for labeled issues. Repository-wide check acts as a highly efficient proxy to prevent triggering GitHub's rate limits (which (N)$ Issue Events API calls would cause on large repositories).

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 7 changed files in this pull request and generated 5 comments.

Comment thread src/lib/admin-scoring.ts Outdated
Comment on lines +92 to +100
async function _buildAdminScore(owner: string, repo: string, adminUsername: string): Promise<AdminScoreBreakdown> {
const [prs, issues] = await Promise.all([
fetchRepoPRs(owner, repo),
fetchRepoIssues(owner, repo),
]);

// 1. Merged PRs with gssoc:approved (the search query already filters to is:merged)
const mergedPRsCount = prs.length;
const mergedPRsPoints = mergedPRsCount * 15;
Comment thread src/lib/admin-scoring.ts Outdated
Comment on lines +53 to +55
if (!r.ok) return [];
const d = await r.json() as { items: any[] };
return d.items;
Comment thread src/lib/admin-scoring.ts Outdated
Comment on lines +81 to +83
if (!r.ok) return [];
const d = await r.json() as { items: any[] };
return d.items;
Comment on lines +51 to +54
// Find user's repositories registered in GSSoC 2026
const userRepos = Array.from(GSSOC_REPO_SET).filter((repoKey) => {
return repoKey.split("/")[0] === decoded.toLowerCase();
});
Comment on lines +267 to +270
<Link
href={`/project-admin/${repoKey}`}
style={{
fontSize: 12,
…nonicalize login matching, and encode URL components
@Ixotic27

Copy link
Copy Markdown
Author

Hello! I have updated the branch to address the remaining feedback:

  1. Tie Merged PRs to Admin: Threaded \�dminUsername\ into \ etchRepoPRs\ and updated the search query to include \merged-by:\ so it scores only PRs merged by the specific project admin.
  2. Robust Pagination Error Propagation: Propagated status codes (\403/429\ => \RATE_LIMITED, general non-2xx => \API_ERROR) on subsequent pages (page 2+) in both PRs and issues fetches to prevent silent undercounts or hidden API errors.
  3. Casing-Insensitive Caching: Filtered GSSoC project registries using the canonical \user.login.toLowerCase()\ instead of the raw decoded URL parameter to prevent casing differences from missing matches.
  4. URL Component Encoding: Separately destructured and URL-encoded the \owner\ and
    epo\ segments in project detail link \href\s.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 7 changed files in this pull request and generated 4 comments.

Comments suppressed due to low confidence (2)

src/app/project-admin/[username]/[repo]/page.tsx:11

  • There are now unused imports (ProjectStatsGrid, ScoringGuide) and a duplicate lucide-react import. This adds noise and can trip unused-import lint rules. Consider removing the unused imports and consolidating the icon imports into a single lucide-react import.
    src/app/project-admin/[username]/[repo]/page.tsx:197
  • The Project Admin scoring guide markup is duplicated here and in src/app/project-admin/[username]/page.tsx (AdminScoringGuide). Duplicated copy/layout makes future point-rule changes easy to miss. Consider extracting a shared component (e.g. components/project-admin/AdminScoringGuide) and reusing it in both pages.

Comment thread src/lib/admin-scoring.ts Outdated
Comment on lines +47 to +48
if (data.total_count > 100) {
const pages = Math.min(Math.ceil((data.total_count - 100) / 100), 4); // fetch up to 500 PRs
Comment thread src/lib/admin-scoring.ts Outdated
Comment on lines +77 to +78
if (data.total_count > 100) {
const pages = Math.min(Math.ceil((data.total_count - 100) / 100), 4); // fetch up to 500 issues
Comment thread src/lib/admin-scoring.ts
Comment on lines +131 to +135
if (hasDifficulty && hasType) {
labeledIssuesFullCount++;
} else if (hasDifficulty) {
labeledIssuesDiffCount++;
}
@@ -0,0 +1,493 @@
import { notFound } from "next/navigation";
import Link from "next/link";
import { ArrowLeft, Clock, AlertTriangle, Star, RefreshCw, FolderGit2, GitMerge, Tag, HelpCircle, Trophy, BookOpen, ExternalLink } from "lucide-react";
@vercel

vercel Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
gssoc-tracker Ready Ready Preview, Comment Jun 26, 2026 8:27am

@PRODHOSH

Copy link
Copy Markdown
Owner

Hey @Ixotic27 Thanks for the pr
So i tested with someone from leaderboard, for project admin
First, It doesnt match the scores with gssoc
Second, For project admin instead of username ur supposed to ask the project repo for tracking instead of the profile username
So, Ive alrdy tried with the project repo and used the same formula gssoc gave, but it doesnt seem to match the actual score.
And i think they have a lot of constraints still not disclosed.
image
image

@Ixotic27

Copy link
Copy Markdown
Author

Hey @Ixotic27 Thanks for the pr So i tested with someone from leaderboard, for project admin First, It doesnt match the scores with gssoc Second, For project admin instead of username ur supposed to ask the project repo for tracking instead of the profile username So, Ive alrdy tried with the project repo and used the same formula gssoc gave, but it doesnt seem to match the actual score. And i think they have a lot of constraints still not disclosed. image image

ok i'll check because for me it was giving approx scores
image

@Ixotic27

Copy link
Copy Markdown
Author

Hey @PRODHOSH, thanks a lot for testing this and providing the detailed feedback with the actual score breakdown screenshot! 🙏

You're absolutely right — the scoring formula I used was reverse-engineered from assumptions, and as you pointed out, GSSoC's actual scoring includes a lot of undisclosed factors like:

  • PA ongoing (merged PRs) scoring at a completely different scale (+22,650 in the screenshot vs. our flat +15/PR)
  • Project admin streak bonuses (+11,840)
  • Community bounty tasks (+350)
  • Form-based data (Discord linked, LinkedIn profile, prior experience, etc.)

Since these constraints aren't publicly available and can't be tracked via GitHub API, I've rebranded the feature in the latest commit:

Changes made:

  • ✅ Renamed from "Project Admin Tracker" → "PA Activity Tracker"
  • ✅ Added a prominent "Estimated Points — Not Official" disclaimer banner on every page
  • ✅ All point values now prefixed with ~ (tilde) to clearly indicate they're approximations
  • ✅ Updated the scoring guide to explicitly note that official GSSoC scoring includes undisclosed constraints

This way the feature still provides useful activity insights (merged PRs count, labeled issues, opened issues, resolution time) without falsely claiming to replicate the official scoring.

Regarding your point about looking up by project repo instead of username — that route already exists at /project-admin/[username]/[repo] for per-repo tracking. Happy to adjust the entry point if you'd prefer repo-first navigation.

Let me know if this approach works for you or if you'd like any further changes! 🚀

@Ixotic27

Ixotic27 commented Jun 26, 2026

Copy link
Copy Markdown
Author

Hey @PRODHOSH,

Quick update: after aligning on the scope of the tracking formula, I decided to revert back to the original points formula (which counts all approved and merged contributor PRs in the repository, rather than filtering exclusively by merged-by:${adminUsername}).

What's new:

  • The scoring calculations have been restored to the previous values.
  • All display approximations (like the ~ prefix and Est. labels) have been removed.
  • All disclaimer banners and activity tracking notes explaining the differences between GitHub data and official GSSoC metrics are preserved.

The build is green and the branch has been updated. Let me know what you think! 🚀

@Ixotic27

Ixotic27 commented Jun 26, 2026

Copy link
Copy Markdown
Author

Hey @PRODHOSH,

Quick follow-up: I identified and resolved a caching issue and corrected the PR counting logic.

What was happening:

  1. Caching Collision: The unstable_cache was using a static ["admin-scoring-data"] cache key across all users and repositories instead of caching dynamically based on the owner/repo/username arguments. This was causing profile pages to display incorrect cached scores from other profiles.
  2. Scoring Logic Restored: We reverted the pull request fetching queries back to the original layout (counting closed and merged PRs with the gssoc:approved label).

Changes made:

  • Refactored buildAdminScore, buildProjectAdminData, and buildMentorTrackerData caching structures to generate unique parameter-based cache keys (e.g. ["admin-scoring-data", owner, repo, username]).
  • Re-aligned the counting behavior with the original formulas.

The local page now correctly computes 9,444 points (matching the original score) for @ixotic27 on the-leetcode-city repository. The PR branch is updated! 🚀

@Ixotic27

Ixotic27 commented Jun 26, 2026

Copy link
Copy Markdown
Author

Hi @PRODHOSH please assign me this pr as an assignee and close this pr

@PRODHOSH

PRODHOSH commented Jun 26, 2026

Copy link
Copy Markdown
Owner

Sry, i saw u made some changes.
Does it match the gssoc score? if so i will merge it
if not will close this

@Ixotic27

@Ixotic27

Ixotic27 commented Jun 26, 2026

Copy link
Copy Markdown
Author

Sry, i saw u made some changes. Does it match the gssoc score? if so i will merge it if not will close this

@Ixotic27

yes
image
image
image

@PRODHOSH

Copy link
Copy Markdown
Owner

@Ixotic27 thank you so much for the pr
i will merge this tdy or tmrw currently im adding an backend supabase for this
as some contributor hit a limit of 1000 prs and api cant fetch more than that
so working on that
once done i will merge thanks!

@PRODHOSH PRODHOSH reopened this Jun 27, 2026
@Ixotic27

Copy link
Copy Markdown
Author

@Ixotic27 thank you so much for the pr i will merge this tdy or tmrw currently im adding an backend supabase for this as some contributor hit a limit of 1000 prs and api cant fetch more than that so working on that once done i will merge thanks!

Take your time

@PRODHOSH

Copy link
Copy Markdown
Owner

@Ixotic27 hey bro can u work on this.... with the supabase setup
just make it such a way that pa's enter their repo and they can see their stats

sry for making u do it again
i was working on the supabase setup as some of em crossed more than 1000 prs which reached github api limit

currently im fetching and filtering by date, so i can fetch more than 1000
next up, 1 min fetching time is given rn... b4 it was instant 0 sec

so ye, pls check the new code and create a new pr
thanks for ur help!

@PRODHOSH PRODHOSH closed this Jun 29, 2026
@Ixotic27

Ixotic27 commented Jun 29, 2026

Copy link
Copy Markdown
Author

@Ixotic27 hey bro can u work on this.... with the supabase setup just make it such a way that pa's enter their repo and they can see their stats

sry for making u do it again i was working on the supabase setup as some of em crossed more than 1000 prs which reached github api limit

currently im fetching and filtering by date, so i can fetch more than 1000 next up, 1 min fetching time is given rn... b4 it was instant 0 sec

so ye, pls check the new code and create a new pr thanks for ur help!

@PRODHOSH ok will work on it

@Ixotic27

Copy link
Copy Markdown
Author

Hey @PRODHOSH! Created a new PR as requested: #10

Key improvements over the old approach:

  • Supabase caching with delta-sync (same pattern as pr-tracker.ts) — handles repos with 1000+ PRs
  • Date-filtering on subsequent visits — only fetches updated PRs, keeping it fast
  • Project Admin role on homepage — PAs can now enter owner/repo directly from the landing page
  • Graceful fallback — works without Supabase configured (falls back to direct GitHub API)

SQL for the two new tables (pa_repos, pa_pull_requests) is in the PR description. Let me know if you need any changes!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants