Nobody has started this yet — be first.
Business impact
Right now the only way to see how a link is performing is GET /:code/stats, one code at a time -- you have to already know which short code you're asking about. There's no way to answer "which of our links are actually getting clicked?" without querying the database by hand. That's a real gap for anyone using this service to track campaign links, social posts, or anything where "what's working?" is the whole point of tracking clicks in the first place -- right now that question requires direct DB access, not the API.
Problem
GET /stats/top is registered as a stub in src/routes/redirect.js (right before GET /:code). It compiles and the route exists, but its handler unconditionally throws -- hitting it always returns a 500, regardless of query parameters.
Current behavior
GET /stats/top?limit=2 always returns HTTP 500 instead of a ranked list of links.
Expected behavior
GET /stats/top?limit=N returns a JSON array of the N links with the highest clicks count, sorted descending by clicks (most-clicked first). limit is optional, defaulting to 10 if omitted, and clamped to a sane range (e.g. 1–100) rather than trusting an arbitrary client-supplied number directly. Each entry has the shape { shortCode, longUrl, clicks } -- no need to include createdAt/expiresAt, this is intentionally a lighter-weight response than GET /:code/stats. An empty database (no links at all) returns 200 [], not an error.
Steps to reproduce
npm run dev curl -s "http://localhost:3003/stats/top?limit=2"
Why this matters
This is a straightforward read: one Prisma query with orderBy: { clicks: 'desc' } and a take: limit. The part actually worth thinking through is the limit query parameter -- it arrives as a string (or is absent entirely), and it's client-controlled, so it needs to be parsed and clamped defensively (an unbounded or non-numeric limit should never reach Prisma's take unvalidated).
Suggested approach
Look at how GET /:code/stats (right below where you'll add this) already shapes a Prisma response into a small JSON object -- you want the same idea, but for many rows instead of one, using prisma.link.findMany with an orderBy and a take instead of findUnique. Parse req.query.limit with Number(...), and think about what should happen if it's missing, non-numeric, zero, negative, or absurdly large.
Acceptance criteria
Verification
npx jest --config practice-tickets/jest.config.js practice-tickets/tests/05-top-links-leaderboard.test.js
Hints (0/2)
Try it without hints first — the reading is the exercise.
Working on this ticket
Work on a branch named for the ticket — that's what you'll submit.
Branch off your fork
$git checkout -b feat/top-links-leaderboardFix it and commit
Meet every acceptance criterion, and add a test that would have caught this.
Push the branch
$git push -u origin feat/top-links-leaderboardSubmit it below
Paste your fork URL and the branch name, with a short write-up of the root cause.
Questions
Ask about anything unclear in the ticket — the maintainer and anyone who has solved it can answer. Please don't post full solutions.
Sign in to ask a question or reply.
Sign inOr run the whole stack in Docker instead of the steps above -- docker compose up --build (dev, hot-reloaded via a bind-mounted src/) or docker compose -f docker-compose.prod.yml up --build (prod-style multi-stage build, non-root user). Either way the app container runs prisma migrate deploy on startup, so no separate migration step is needed. Host ports are non-default -- app 3003, Postgres 5436, Redis 6380 -- to avoid clashing with sibling projects in this repo.
The project's own real test suite (npm test, Jest + Supertest against real Postgres/Redis) is separate from the practice tickets below -- run it any time to confirm you haven't broken anything already-working.
Each ticket in practice-tickets/tickets/ (01 through 07) names a dedicated test under practice-tickets/tests/, run via its own Jest project (practice-tickets/jest.config.js, excluded from plain npm test):
# a single ticket
npx jest --config practice-tickets/jest.config.js practice-tickets/tests/01-health-check-false-positive.test.js
# all 7, one at a time, with a pass/fail summary
./practice-tickets/run.sh
Fixing tickets 01, 03, 04, and 07 also turns several pre-existing failures in the real suite (tests/health.test.js, tests/redirect.test.js, tests/concurrency.test.js) back to green -- that's expected, not a coincidence, since the injected bugs live in shared code that suite also exercises. tests/concurrency.test.js specifically fails for two unrelated reasons at once (tickets 04 and 07 both touch code paths it exercises), so fixing only one of the two will not turn it green.
Level 2
Implement a feature
Extend the system within its own patterns.