깃허브 활동을 한 장의 랭크 카드로

2025.12 ~ 2025.12 (운영 중)

GitHub 활동 지표 5개를 하나의 티어로 환산해 SVG 카드로 보여주는 서비스입니다.

과제

  • 프로필 통계 카드는 숫자를 나열할 뿐 상대적 수준을 알려주지 않음
  • 커밋·스타·PR·팔로워·이슈를 31개 구간 순위로 환산할 방법이 필요

담당 범위

  • 점수 산출 로직과 GitHub REST / GraphQL 연동 (1인)
  • SVG 카드 렌더러: 엠블럼·스탯바·9종 테마
  • Vercel 서버리스 배포(esbuild 번들), CI(타입체크 + Vitest)

설계 판단

  • Next.js를 Hono + SVG 문자열 생성으로 교체 → 라우트 하나에 프레임워크 적재 회피
  • Edge 대신 Node.js 서버리스, 번들 산출물 커밋 → 배포 대상을 파일 하나로 고정
  • 점수 계산을 정규화 함수와 순수 함수로 격리 → API 없이 테스트, 지표 추가 용이

결과 지표

  • 테스트 45개 / 6파일 전부 통과
  • 런타임 의존성 3개 (hono, @hono/node-server, esbuild)
원문 자세히 보기

과제

GitHub 프로필 README에 붙이는 통계 카드는 숫자를 나열할 뿐 '이게 잘하는 건지'를 알려주지 않는다. 커밋·스타·PR·팔로워·이슈 5개 지표를 하나의 상대적 순위(Iron~Challenger, 31개 구간)로 환산해 한 장의 SVG로 보여주는 것이 목표였다.

담당 범위

소스 1,193줄 · 테스트 45개 · 티어 구간 31개 · 테마 9종

1인 개발. 티어 점수 산출 로직(CDF 가중합·디비전 매핑) 설계와 구현, GitHub REST/GraphQL 연동부 작성, SVG 카드 렌더러(엠블럼·스탯바·프리미엄 효과·9종 테마) 구현, Vercel 서버리스 배포 파이프라인(esbuild 번들 + 산출물 커밋) 구성, GitHub Actions CI(타입체크 + vitest) 및 Dependabot·이슈/PR 템플릿 설정, README 문서 작성

보기

선택안 · 대안 · 근거 · 비용

Next.js로 시작한 프로젝트를 하루 만에 Hono + 순수 SVG 문자열 생성으로 갈아엎었다 (커밋 e292625 → 7e3508b)

대안Next.js Route Handler를 그대로 두고 이미지 응답만 추가근거실제 라우트가 /api/tier 하나뿐이고 반환값이 image/svg+xml 문자열이다. 페이지·번들러·React 런타임이 전혀 쓰이지 않는데 프레임워크 전체를 서버리스 함수에 싣게 된다.비용라우팅·검증·에러 처리를 직접 짜야 하고, JSX 대신 템플릿 리터럴로 SVG를 조립하게 되어 렌더러 파일(render-tier-card.ts 124줄 등)이 문자열 덩어리로 남았다. 마크업 오타를 타입 시스템이 잡아주지 못한다.

Vercel Edge Runtime을 포기하고 Node.js 서버리스 함수로 전환한 뒤, esbuild 번들 산출물 api/tier.js를 저장소에 커밋해 배포한다 (c06baab에서 .gitignore에서 제외, be4ce90/b180e7b/851154a에서 런타임 전환)

대안Vercel의 buildCommand로 배포 시점에 빌드시키기 / Edge Runtime을 계속 붙들기근거Edge 경로 매칭·모듈 포맷 문제로 디버깅 커밋이 10여 개 쌓였고(f4f4030 '디버그: 최소 Edge Function 테스트', 2f21c13 '디버그 에러 메시지 노출' 등), 빌드 산출물을 직접 커밋하니 '무엇이 배포되는지'가 눈에 보이는 파일 하나로 고정됐다. type: module도 CJS 호환을 위해 제거했다(851154a).비용947줄짜리 생성 파일이 저장소에 들어와 diff를 오염시키고, 소스를 고치고 빌드를 잊으면 배포본과 소스가 조용히 어긋난다. CI가 타입체크·테스트는 돌리지만 '번들이 최신인지'는 검사하지 않아 이 위험은 남아 있다. Edge의 콜드스타트 이점도 포기했다.

점수 계산을 f(x) = x / (1 + x) 형태의 정규화 함수와 지표별 중앙값·가중치 테이블로 만들고, 네트워크·환경변수에 의존하지 않는 순수 함수로 features/tier/lib에 격리했다

대안지표별 하드코딩 구간(예: 커밋 1000개 이상이면 Gold)으로 임계값 테이블만 두기근거구간 하드코딩은 경계에서 계단처럼 튀고 지표를 추가할 때마다 표 전체를 다시 손봐야 한다. 중앙값으로 나눈 뒤 0~1로 눌러주면 상위값에서 자연스럽게 수확체감이 생기고, 새 지표는 MEDIANS/WEIGHTS에 한 줄만 추가하면 된다. 순수 함수라 GitHub API 없이 테스트가 된다. 중앙값·가중치는 감이 아니라 실제 GitHub 사용자 표본을 수집해 분포를 확인하고, 합성 사용자 시뮬레이션으로 티어 분포가 한쪽에 몰리지 않는지 검증한 뒤 정했다.비용표본 조사와 시뮬레이션은 실제로 수행했지만 그 스크립트와 데이터를 저장소에 남기지 않아, 지금은 상수가 근거 없는 매직넘버처럼 보인다. 값을 바꿨을 때 무엇이 좋아졌는지 재현할 방법이 없다는 뜻이라 실질적으로는 검증하지 않은 것과 같은 상태다.

사용 기술

SVG CSS 애니메이션SMIL animate테마 토큰 9종TypeScriptHono@hono/node-server