Skip to content

[Bug]: CodingVerse leaderboard fetches entire users collection without server-side limit or ordering #565

@nyxsky404

Description

@nyxsky404

Bug Description

In src/pages/CodingVerse.jsx (around line 370), the leaderboard effect fetches every completed user from Firestore and then sorts and slices client-side:

const q = query(
  collection(db, "users"),
  where("onboardingStatus", "==", "complete")
  // no orderBy, no limit
);
const snapshot = await getDocs(q);

const sortedUsers = users
  .filter(u => (u.points?.codingVersePoints || 0) > 0)
  .sort((a, b) => b.points.codingVersePoints - a.points.codingVersePoints)
  .slice(0, 20); // only 20 are ever shown

This downloads every user document on every tab switch (the effect re-runs each time activeSidebarTab becomes "leaderboard"). Firestore charges per document read — at 1,000 users that's 1,000 reads for a list that only ever shows 20 entries. The client is also doing work the database should be doing.

Why it can't just be a limit(50) patch

Adding limit without orderBy("points.codingVersePoints", "desc") returns an arbitrary 50 users, not the top 50. And adding that orderBy without a matching composite index in firestore.indexes.json will throw a Firestore index error at runtime.

Proposed fix

  1. Add a composite index to firestore.indexes.json:
{
  "collectionGroup": "users",
  "queryScope": "COLLECTION",
  "fields": [
    { "fieldPath": "onboardingStatus", "order": "ASCENDING" },
    { "fieldPath": "points.codingVersePoints", "order": "DESCENDING" }
  ]
}
  1. Replace the unbounded query:
const q = query(
  collection(db, "users"),
  where("onboardingStatus", "==", "complete"),
  where("points.codingVersePoints", ">", 0),
  orderBy("points.codingVersePoints", "desc"),
  limit(20)
);
const snapshot = await getDocs(q);
const sortedUsers = snapshot.docs.map(d => ({ uid: d.id, ...d.data() }));
  1. Add a simple timestamp guard (similar to the syncGitHubData cooldown pattern already in the codebase) so repeat tab switches within a few minutes don't re-fetch.

Metadata

Metadata

Assignees

Labels

NSoC'26NSoC 2026backendBackend/Firebase related changesbugSomething isn't workingdocumentationImprovements or additions to documentationenhancementNew feature or requestfrontendFrontend related changes (HTML/CSS/JS/React)gssocGirlScript Summer of Codegssoc26GirlScript Summer of Code 2026needs-reviewIssue needs reviewnsocNSoC

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions