A competitive LeetCode tracker for MCA students at NIT Warangal. It pulls public profile, problem, contest, badge and calendar data from LeetCode's GraphQL API and renders a sortable leaderboard, per-user analytics, and a head-to-head comparison view.
Live: https://leetcode-among-us.onrender.com (Render free tier: the first request after ~15 minutes of inactivity takes 30-60 seconds while the service wakes up).
- Leaderboard with Overview, Problem Stats, Contest Stats, Contest Performance and Advanced tabs; sortable columns, name search, batch filter, medals for the top three, and a Recent Contest Activity feed.
- User Stats page: profile, difficulty breakdown, topic radar, submission heatmap, contest rating history and scatter, badges, streaks.
- Compare page: two users side by side across problems, contests, beats percentages and rating history, with an overall winner.
- Dark/light theme (persisted, applied before first paint).
- Server-side cache so the roster loads in seconds on repeat visits and LeetCode is not hammered on every page load.
| Layer | Technology |
|---|---|
| Client | React 19, TypeScript, Vite 8, React Router 7, Chart.js 4, React Icons |
| Server | Node 22+, Express 5, TypeScript, Helmet, CORS, express-rate-limit |
| Data | LeetCode GraphQL API (public queries only), roster JSON in the repo |
| Tooling | pnpm 12 workspace, Prettier, Vitest, Supertest |
| CI/Deploy | GitHub Actions (org reusable workflows), Render |
Prerequisites: Node 22 or newer and pnpm 12 (corepack enable will pick up the
pinned version from package.json).
git clone https://github.com/MCA-NITW/leetcode_among_us.git
cd leetcode_among_us
pnpm install
pnpm devpnpm dev starts the API on http://localhost:3001 and the Vite client on
http://localhost:3000. The client proxies /leetcode/* and /health to the
API during development (see client/vite.config.ts).
| Command | What it does |
|---|---|
pnpm dev |
API (tsx watch) + client (Vite) concurrently |
pnpm start:dev |
API only, with reload |
pnpm build |
Install, compile server to dist/, validate roster, build UI |
pnpm start |
Run the compiled server (serves client/dist) |
pnpm test |
Server tests (Vitest + Supertest) then client tests |
pnpm validate:data |
Validate client/src/assets/leetcoders_data.json |
pnpm format |
Prettier write |
pnpm format:check |
Prettier check (what CI runs) |
Server (.env, see .env.example):
| Variable | Default | Purpose |
|---|---|---|
PORT |
3001 |
Listen port |
NODE_ENV |
development |
Set to production on Render |
CACHE_TTL_MINUTES |
10 |
How long a fetched profile is served from memory |
Client (client/.env, see client/.env.example):
| Variable | Default | Purpose |
|---|---|---|
VITE_API_URL |
'' |
API origin when the client is hosted separately from the API |
Leave VITE_API_URL empty when Express serves the built client (the default
Render setup).
Both endpoints are rate limited (2000 requests per 5 minutes per IP) and
CORS-restricted to the origins listed in server.ts.
| Method | Path | Body | Notes |
|---|---|---|---|
GET |
/health |
- | Liveness probe; never calls LeetCode |
POST |
/leetcode/user-data |
{ "username": "..." } |
Aggregated profile for one user |
POST |
/leetcode/batch-user-data |
{ "usernames": ["...", …] } |
Up to 10 users; duplicates share one fetch |
Usernames must match ^[a-zA-Z0-9_-]{1,40}$. Invalid input returns 400,
upstream failures 502, unknown /leetcode/* paths a JSON 404, disallowed
origins 403. Successful profiles are cached for CACHE_TTL_MINUTES; not-found
users are never cached.
Each profile response bundles six LeetCode queries: public profile, contest
ranking and history, problems solved, skill tags, badges, and a per-year
submission calendar for every year in the user's activeYears.
-
Fork and clone the repository.
-
Add an entry to
client/src/assets/leetcoders_data.json(template inclient/src/assets/TEMPLATE_ENTRY.json):{ "id": "22MCF1R01", "name": "Your Name", "userName": "your_leetcode_username", "batch": "2025", "gender": "male" } -
Run
pnpm validate:data. It checks required fields, the username pattern, four-digit batch, gender value, and duplicate ids/usernames (case-insensitive - LeetCode usernames are case-insensitive too). -
Open a pull request. CI runs the same validation as part of the build.
Your LeetCode profile must be public. See CONTRIBUTING.md for the full guide.
.
├── server.ts Express 5 API + static server (single file)
├── tsconfig.server.json Compiles server.ts -> dist/server.js
├── vitest.config.ts Server test runner config
├── tests/ Server + validator tests
├── scripts/validate-data.mjs Roster validator (CLI + importable)
├── client/
│ ├── index.html CSP meta, fonts, theme pre-paint script
│ ├── vite.config.ts Dev proxy to :3001
│ ├── vitest.config.ts Client test runner config
│ ├── tests/ Client unit tests
│ └── src/
│ ├── api/OptimizedFetchData.ts Calls the API, shapes responses
│ ├── utils/optimizedLeaderboardData.ts Batching + progress
│ ├── assets/leetcoders_data.json Roster (edit this to add users)
│ ├── components/Charts/ Chart.js wrappers
│ ├── components/{Nav,Loader,ThemeToggle}/
│ ├── contexts/ThemeContext.tsx
│ ├── hooks/useReveal.ts Scroll-triggered entrance reveals
│ ├── pages/{Home,LeaderBoard,UserStats,Compare}/
│ └── types/index.ts
├── .github/workflows/ci.yml Calls mca-nitw/.github reusable workflows
└── pnpm-workspace.yaml Workspace + security overrides
- Formatting is enforced by Prettier in CI (
pnpm format:check). Single quotes, no semicolons, 2 spaces, 80 columns. - Design tokens live in
client/src/index.css(colours, spacing, radius, shadows, motion). Use them; do not add literal colours or durations. For motion, reuse the shared utilities:.reveal+useReveal()for scroll entrances,.staggerwith an inline--ifor cascading siblings,.card-liftfor hover, and theg-*keyframes. Reduced motion is handled globally. - TypeScript runs with
strict,noUnusedLocals,noUnusedParametersandnoFallthroughCasesInSwitchon both sides. - There is no ESLint/Biome yet; adding Biome 2 (lint-only, Prettier stays) is the intended next step.
pnpm buildrunspnpm installfirst because Render's build command ispnpm build. Do not remove that without updating the Render service.- Dependencies are managed by Renovate through the org preset
(
github>mca-nitw/.github): one grouped PR per month, security fixes at any time, auto-merged when CI is green.
Render web service, root directory ., build command pnpm build, start
command pnpm start, health check path /health, environment
NODE_ENV=production. The server serves client/dist and falls back to
index.html for client-side routes.
See SECURITY.md. The server only issues public, unauthenticated GraphQL queries; no LeetCode credentials are involved anywhere.
ISC. See LICENSE.