{"id":50139208,"url":"https://github.com/iprashantraj/leetcode-tracker","last_synced_at":"2026-05-24T00:05:10.193Z","repository":{"id":358118442,"uuid":"1240070571","full_name":"iprashantraj/leetcode-tracker","owner":"iprashantraj","description":"Chrome extension + React dashboard that tracks LeetCode time, charts your grind, and adds a friends leaderboard. Supabase backend.","archived":false,"fork":false,"pushed_at":"2026-05-23T00:39:22.000Z","size":172,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-23T02:23:50.201Z","etag":null,"topics":["chrome-extension","javascript","leetcode","manifest-v3","react","supabase","tracker","vite"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/iprashantraj.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-15T18:29:49.000Z","updated_at":"2026-05-23T00:39:26.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/iprashantraj/leetcode-tracker","commit_stats":null,"previous_names":["iprashantraj/leetcode-tracker"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/iprashantraj/leetcode-tracker","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iprashantraj%2Fleetcode-tracker","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iprashantraj%2Fleetcode-tracker/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iprashantraj%2Fleetcode-tracker/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iprashantraj%2Fleetcode-tracker/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/iprashantraj","download_url":"https://codeload.github.com/iprashantraj/leetcode-tracker/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iprashantraj%2Fleetcode-tracker/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33416317,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-23T22:14:44.296Z","status":"ssl_error","status_checked_at":"2026-05-23T22:14:43.778Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["chrome-extension","javascript","leetcode","manifest-v3","react","supabase","tracker","vite"],"created_at":"2026-05-24T00:05:09.390Z","updated_at":"2026-05-24T00:05:10.183Z","avatar_url":"https://github.com/iprashantraj.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# LeetCode Tracker\n\n\u003e Know how much time you actually spend on LeetCode, which topics you neglect, and which problems you keep coming back to.\n\nA Chrome/Brave extension that quietly tracks your LeetCode practice — time spent, runs, submits, verdicts — and a web dashboard that turns it into something useful: solved-by-difficulty badges, a topic-time chart, a filterable problem list, and friend comparison.\n\n**[→ Try the dashboard](https://theleetcodetracker.netlify.app/)** · **[→ Install the extension](https://github.com/iprashantraj/leetcode-tracker/releases/latest)** *(invite-only)*\n\n![Dashboard overview](docs/dashboard.png)\n\n---\n\n## Why this exists\n\nLeetCode shows you what you've solved. It doesn't show:\n\n- **Where your time actually goes** — that 30 min on Two Sum vs 3 hours stuck on Trapping Rain Water\n- **Which topics you avoid** — you've done 18 array problems and 0 graph problems this month\n- **What your real attempt history looks like** — every run, every submit, every verdict, timestamped\n- **How you compare to friends grinding the same problems**\n\nThis fills those gaps with one Chrome extension and one dashboard. No screenshots, no manual logging, no behavior change on your part — it just runs in the background while you practice as normal.\n\n---\n\n## How it works\n\n```\n┌─────────────────────┐         ┌─────────────────────┐         ┌─────────────────────┐\n│  Browser Extension  │         │     Supabase        │         │   Web Dashboard     │\n│                     │  sync   │                     │  read   │                     │\n│  • Tracks time      │ ──────► │  • Postgres + RLS   │ ──────► │  • Stats + charts   │\n│  • Detects run/sub  │  every  │  • Auth (invite)    │  live   │  • Problem list     │\n│  • Verdict watcher  │  60s +  │  • Realtime ready   │         │  • Friends compare  │\n│  • LeetCode meta    │  events │                     │         │                     │\n└─────────────────────┘         └─────────────────────┘         └─────────────────────┘\n       MV3 + JS                    Postgres + GoTrue              React + Vite + Recharts\n```\n\nA few design choices worth calling out:\n\n- **`chrome.webRequest` for Run/Submit detection** (not page-level fetch hooks). LeetCode caches a native fetch reference before any content script can patch it, so MAIN-world overrides silently miss every request. webRequest sits at the network layer and catches everything.\n- **Shared `problems` catalogue populated organically.** When any user's extension visits \"Two Sum\" for the first time, it fetches difficulty + topics from LeetCode's GraphQL endpoint (using the user's own session) and writes one row to a shared table. Every other user benefits from that cache.\n- **Time tracking treats \"opened-and-bounced\" as noise.** A visit without any run, submit, or 30+ seconds of input is discarded at the sync boundary. Your dashboard reflects real practice, not curiosity.\n- **Phantom-time safeguard.** Tab closed without firing `pagehide`? The background worker caps the active interval after 90 seconds of silence so the timer doesn't accumulate hours of imaginary time.\n- **Row Level Security on every table.** Anon key is shipped in the client; access control is enforced at the database layer, not the application layer.\n- **Single-use invite codes** gate signups. Codes live in a table the anon key cannot read, validated by a `SECURITY DEFINER` trigger on `auth.users` insert.\n\n---\n\n## Tech\n\n| Layer | Stack |\n|---|---|\n| Extension | Manifest V3 · vanilla JS · ES modules · `chrome.webRequest` |\n| Dashboard | React 19 · Vite 8 · Recharts · date-fns |\n| Backend | Supabase (Postgres 15 · GoTrue · PostgREST · pg_cron) |\n| Hosting | Netlify (dashboard) · Supabase (DB + auth) · GitHub Releases (extension) |\n| Distribution | Unpacked .zip (current) → Chrome Web Store (planned) |\n\nTotal footprint: ~3000 lines across extension + dashboard + SQL migrations.\n\n---\n\n## Install (invite-only)\n\n\u003e Signups require a single-use code. DM me if you'd like one.\n\n1. Download the latest `leetcode-tracker-X.Y.Z.zip` from the **[releases page](https://github.com/iprashantraj/leetcode-tracker/releases/latest)** and unzip it.\n2. Open `chrome://extensions` (or `brave://extensions`) → toggle **Developer mode** ON.\n3. **Load unpacked** → pick the unzipped folder.\n4. Open the **[dashboard](https://theleetcodetracker.netlify.app/)** and **Sign up** with your email, a password, and the invite code you were given.\n5. Click the extension icon → **Sign in** with the same credentials.\n6. Open any [leetcode.com/problems/](https://leetcode.com/problems/) page. Practice as usual. Your dashboard updates within ~60 seconds of each Run or Submit.\n\n---\n\n## Repo layout\n\n```\nextension/          Manifest V3 Chrome extension\n  ├ background.js     service worker (sync, webRequest, attempt lifecycle)\n  ├ content.js        isolated-world script (slug detection, idle tracking)\n  ├ page-hook.js      MAIN-world script (fetch fallback)\n  ├ supabase.js       thin REST/auth wrapper, no SDK\n  ├ popup.html/.js    extension popup UI\n  ├ config.js         public Supabase URL + anon key (safe to commit, RLS enforces)\n  └ build-zip.sh      packages the release zip\n\ndashboard/          React + Vite SPA\n  └ src/\n      ├ pages/        Dashboard + Auth + Friends\n      ├ components/   StatsBar, ActivityChart, Heatmap, TopicChart, ProblemList, DifficultyBadges\n      ├ hooks/        useAttempts, useProblems, useFriendships, useSession\n      └ utils/stats.js  pure aggregation (testable, no React, no Supabase)\n\nsupabase/           SQL migrations (idempotent, re-runnable)\n  ├ schema.sql              core tables + RLS + triggers\n  ├ phase4.sql              friends/groups\n  ├ phase4_usernames.sql    username uniqueness\n  ├ phase5_event_log.sql    granular event tracking + 90-day cron cleanup\n  ├ phase6_invite_codes.sql single-use signup codes\n  └ phase7_lockdown_problems.sql  immutable shared catalogue\n\nscripts/            admin tooling (runs only on owner machine)\n  ├ new-invite.sh           generate an invite code\n  └ .env.example            service_role config (real .env is gitignored)\n```\n\n---\n\n## Local development\n\nFor forking or self-hosting your own instance:\n\n\u003cdetails\u003e\n\u003csummary\u003eClick to expand\u003c/summary\u003e\n\n### Supabase\n\n1. Create a project at [supabase.com](https://supabase.com) (free tier is plenty).\n2. SQL Editor → run each file in `supabase/` in numeric order (`schema.sql` first, then `phase4.sql`, etc).\n3. Project Settings → API → copy the **Project URL** and **anon public** key.\n\n### Extension\n\n1. Edit `extension/config.js` — replace the URL and anon key with your own project's values.\n2. `chrome://extensions` → Developer Mode → Load unpacked → pick the `extension/` folder.\n\n### Dashboard\n\n```bash\ncd dashboard\ncp .env.example .env\n# Set VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY\nnpm install\nnpm run dev    # → http://localhost:5173\n```\n\nDeploy `dashboard/` to Netlify, Vercel, or any static host. Build command: `npm run build`, output dir: `dist`.\n\n### Generate invite codes (admin)\n\n```bash\ncp scripts/.env.example scripts/.env\n# Fill in SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY (the latter NEVER leaves your machine)\n./scripts/new-invite.sh \"Note for this invite\"\n```\n\n\u003c/details\u003e\n\n---\n\n## Security model\n\nA few notes since this is a multi-user system with a public-anon client:\n\n- **Anon key is committed.** It's safe by design — Supabase anon keys are intended for client use; access control happens at the database via Row Level Security policies, not by hiding the key.\n- **service_role key is admin-only.** Lives only in `scripts/.env` on the owner's machine. Never shipped, never committed.\n- **Every table has RLS enabled.** Users can read/write only their own rows except `problems` (a shared catalogue with read-anyone / write-once / update-admin-only).\n- **Invite codes** use a `SECURITY DEFINER` trigger that locks the row (`SELECT FOR UPDATE`) to prevent race conditions when two signups attempt the same code.\n- **Events are auto-purged.** `pg_cron` runs nightly to delete events older than 90 days, keeping storage bounded at the free-tier limit.\n\n---\n\n## License\n\nMIT — see [LICENSE](LICENSE).\n\n---\n\nBuilt by [@iprashantraj](https://github.com/iprashantraj). Open an [issue](https://github.com/iprashantraj/leetcode-tracker/issues) for bugs or feature requests — there's also a \"Report a bug\" link inside the extension popup.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fiprashantraj%2Fleetcode-tracker","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fiprashantraj%2Fleetcode-tracker","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fiprashantraj%2Fleetcode-tracker/lists"}