Skip to content

feat(gamification): show API key names on the leaderboard - #12385

Merged
diegosouzapw merged 2 commits into
diegosouzapw:release/v3.8.51from
pacocartones:feat/leaderboard-api-key-names
Sep 2, 2026
Merged

diegosouzapw merged 2 commits into
diegosouzapw:release/v3.8.51from
pacocartones:feat/leaderboard-api-key-names

Conversation

@pacocartones

Copy link
Copy Markdown
Contributor

Summary

  • The Leaderboard page rendered apiKeyId.slice(0, 8)… under a column translated as "name". GET /api/gamification/leaderboard now enriches each entry with the API key's display name (route-local, so the shared getTopN helper and the federation leaderboard stay id-only), and the page renders name ?? shortId with the full id in a title attribute.
  • The lookup (src/lib/db/apiKeys/displayNames.ts) selects only id, name from api_keys, chunked at 200 ids; unknown ids and blank names are omitted. No key material leaves the DB layer.

Related Issues

Validation

  • Change type: UI (+ API payload)
  • Focused tests and category gates from the golden path: tests/unit/gamification/leaderboard-route-names.test.ts (new, 7 cases), tests/unit/ui/leaderboard-api-key-names.test.tsx (new, 2 cases), tests/unit/gamification/*.test.ts + gamification-display-contract.test.ts (100/100), tests/unit/ui/profile-*.test.tsx + the new page test (8/8, vitest), npm run typecheck:core 0, npm run check:changelog-integrity OK, npm run check:db-rules OK
  • npm run lint — repository-wide eslint exit 0 (run with --pass-on-unpruned-suppressions; the literal command reports only pre-existing unused global suppressions on this base)
  • Reconciled with the current active release base release/v3.8.51; focused checks rerun afterward
  • Production-code changes include a new or updated automated test in this PR
  • SonarQube is temporarily opt-in while the private project has no quota; it is not a PR gate.

Mutation: removing the route enrichment fails 2 of 7 route tests; reverting the page to the sliced id fails both page tests.

Tests Added Or Updated

  • tests/unit/gamification/leaderboard-route-names.test.ts (new): names attached per entry; unknown ids and blank names yield null; the response key set is exactly apiKeyId, name, scope, score, updatedAt with no key material; getTopN stays name-free; GET /api/gamification/federation/leaderboard (real registered server token) still returns exactly {apiKeyId, score}.
  • tests/unit/ui/leaderboard-api-key-names.test.tsx (new): names rendered when present; short id fallback otherwise.

Coverage Notes

  • src/lib/db/apiKeys/displayNames.ts and the route wrapper are fully covered by the route test; the page label helper by the jsdom test.

Reviewer Notes

  • Exposure is limited to the key display name; the endpoint stays behind requireManagementAuth. Federation output is unchanged and asserted.
  • neighbors in the REST response remain id-only because the page does not render them; trivial to enrich later.
  • The lookup lives in the existing src/lib/db/apiKeys/ helper folder rather than in apiKeys.ts, whose base version is not prettier-clean and would have dragged a whole-file reformat into this PR.

The dashboard leaderboard labels its rows under a "Name" column but only
had the API key id to render, so operators saw `0f3c2a11...` where they
expected the key they created. GET /api/gamification/leaderboard now
attaches each entry's API key display name; the page renders that name
and falls back to the shortened id when the key is unknown or deleted.

Scope and exposure:
- The enrichment is route-local (`withApiKeyNames`). The shared getTopN
  helper stays id-only, so the federation leaderboard keeps returning
  `{ apiKeyId, score }` to peer servers.
- Names come from a new name-only lookup, `getApiKeyDisplayNames`
  (src/lib/db/apiKeys/displayNames.ts), which selects `id, name` and
  nothing else — no key, key_hash, key_prefix or policy columns can ride
  along with the name.
- Live SSE updates carry scores only; the page merges the names it
  already fetched so rows do not flip back to raw ids every 5 seconds.

Tests:
- tests/unit/gamification/leaderboard-route-names.test.ts exercises the
  route against a temp SQLite database: names attached, `null` for
  orphan ids, only `apiKeyId/name/scope/score/updatedAt` exposed,
  getTopN and the federation route still id-only, limit validation
  unchanged, and the lookup's blank/unknown-id handling.
- tests/unit/ui/leaderboard-api-key-names.test.tsx renders the page
  under jsdom: podium and table show the name, fall back to the short
  id, and keep names across an SSE update.

Related to diegosouzapw#2403

Co-authored-by: Leon Marcos <leonaniagomez@gmail.com>
@diegosouzapw
diegosouzapw merged commit 5a490b1 into diegosouzapw:release/v3.8.51 Sep 2, 2026
16 checks passed
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
…pw#12385)

The Leaderboard rendered apiKeyId.slice(0, 8)… under a column translated as "name". The route now enriches each entry with the key's display name — route-local, so the shared getTopN helper and the federation leaderboard stay id-only — and the page renders name ?? shortId with the full id in a title attribute. The lookup selects only id and name from api_keys, chunked at 200 ids, with unknown ids and blank names omitted; no key material leaves the DB layer.

Validated in a combined worktree with all 25 PRs of this batch boarded together: typecheck:core clean, 443/443 node-runner tests plus 14/14 vitest across every test file the batch touches, and check-changelog-integrity, check:cycles (418 files), check:provider-consistency (272 REGISTRY entries, 355 canonical providers), check:docs-counts, check:docs-sync (42 locales) and check-file-size all green.

Thanks @pacocartones.
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.

2 participants