Skip to content

fix: 특수문자 닉네임과 없는 사용자의 카드 오류 수정 - #21

Merged
with-developer merged 7 commits into
mainfrom
dev
Nov 2, 2026
Merged

with-developer merged 7 commits into
mainfrom
dev

Conversation

@with-developer

Copy link
Copy Markdown
Owner

배경

운영 서버에서 아래 문제들을 직접 재현했습니다.

  • Try&Catch, DUck_<처럼 &·<가 들어간 닉네임은 HTTP 200이지만 SVG가 XML로 파싱되지 않아 깨진 이미지로 표시됨
  • p&p, #7851A9는 Dreamhack에 있는 사용자인데 검색어를 인코딩하지 않아 "User not found"
  • 없는 사용자·오류 시 JSON 400/500을 반환해, GitHub camo가 "502 Error Fetching Resource"로 바꾸고 README에는 깨진 이미지만 보임 (현재 공개 README 2곳이 이 상태)
  • Dreamhack 검색 API는 limit=100을 보내도 50개만 돌려주고 랭킹 순으로 정렬해, 흔한 문자열이 들어간 닉네임은 못 찾을 수 있음 (예: lee는 230명 중 42번째)
  • 캐시된 ID가 404일 때 재시도 로직이 같은 캐시 값을 다시 읽어 실제로는 동작하지 않음
  • README와 메인 페이지가 만드는 프로필 링크 dreamhack.io/users/닉네임은 404 (Dreamhack은 숫자 ID 주소만 받음)

변경 사항

카드

  • 닉네임 등 외부 값을 SVG에 넣을 때 XML 이스케이프 (테마 정의는 공용 모듈로 이동)
  • 오류 시 안내 카드(SVG, HTTP 200)를 반환: 사용자명 누락 / 사용자 없음(닉네임 표시) / 조회 실패
  • 사용자를 먼저 확인한 뒤 마지막 랭크를 조회하도록 순서 변경

Dreamhack 조회

  • 검색어를 URLSearchParams로 인코딩
  • 첫 페이지에 없으면 최대 5페이지(250명)까지 동시에 확인, 일부 페이지가 실패해도 다른 페이지에서 찾으면 사용
  • 찾지 못한 닉네임은 10분간 캐시해 느린 검색(3~4초) 반복을 줄이고, 검색 실패는 캐시하지 않고 "Failed to load stats"로 구분
  • 캐시된 ID가 404면 캐시를 지운 뒤 다시 검색
  • 요청마다 10초 타임아웃, 함수 최대 실행 시간 60초, 64자를 넘는 값은 검색하지 않음

메인 페이지·README

  • /api/user-id 추가: 미리보기 이미지가 로드된 뒤 ID를 조회해 HTML 코드의 프로필 링크를 숫자 ID 주소로 채움
  • 미리보기와 생성 코드의 닉네임 인코딩 (&, #, +, 공백, 괄호 등만 인코딩하고 한글은 그대로), 입력값 앞뒤 공백 제거
  • README의 프로필 링크 안내를 숫자 ID 주소로 수정, 특수문자 닉네임은 메인 페이지 사용 안내

테스트

  • jest 88개 통과 (기존 50개 → 88개). 캐시 재시도 테스트는 수정 전 코드에서 실패하는 것을 확인했고, 버그를 정답으로 고정하던 기존 테스트(test<user>가 이스케이프 없이 들어가야 통과)를 수정
  • tsc --noEmit, next build 통과
  • 로컬 빌드로 실제 Dreamhack API 확인: Try&Catch, p&p, DUck_<, #7851A9, +__+, 포카리에2드%, lee 정상 카드 / miroo 안내 카드 / 64자 초과 즉시 안내 카드
  • 헤드리스 Chrome으로 카드 렌더링(라이트·다크·긴 닉네임)과 메인 페이지 흐름 확인 (p&p → username=p%26p, 프로필 링크 https://dreamhack.io/users/5409)
  • dev 푸시 시 CI 테스트 및 Vercel Preview 배포 확인

🤖 Generated with Claude Code

https://claude.ai/code/session_01AGcght9Lc8cAYdvYCrdSzd

Others 카테고리가 새로 생기며 Most Solved Categories 범례가 4개에서
5개로 늘어나 박스 하단이 빡빡해진 문제 수정. 범례 시작점을 위로 올리고
배경 박스를 키워 5개 항목의 상하 여백 균형을 맞춤.
SVG가 <img>로 렌더링되면(GitHub README, 메인페이지 미리보기) 브라우저가
외부 리소스를 불러오지 않아 Google Fonts @import가 무시되고, OS 기본
monospace 폰트(macOS Chrome은 Menlo, Safari는 Courier 등)로 표시되던 문제 수정.
JetBrains Mono 가변 폰트를 카드에 쓰는 굵기(400~700)와 ASCII 문자만 남겨
서브셋한 뒤 base64 @font-face로 SVG에 직접 임베드하고, 서브셋 생성
스크립트와 폰트 라이선스(OFL)를 함께 추가.

Claude-Session: https://claude.ai/code/session_01AGcght9Lc8cAYdvYCrdSzd
Vercel이 Node.js 20 지원을 종료해(2026-10-01) 배포가 실패하므로
package.json engines로 Vercel 빌드/함수 런타임을 24.x로 지정하고,
CI 테스트도 같은 버전으로 맞춤.

Claude-Session: https://claude.ai/code/session_01AGcght9Lc8cAYdvYCrdSzd
- 닉네임 등 외부 값을 SVG에 넣을 때 XML 이스케이프 (Try&Catch, DUck_< 카드가
  깨지던 문제)
- Dreamhack 검색어를 URL 인코딩 (p&p, #7851A9 등을 찾지 못하던 문제)하고, 검색
  API가 50개까지만 돌려주므로 최대 5페이지까지 확인
- 사용자를 찾지 못하거나 조회에 실패하면 JSON 대신 안내 카드(SVG, 200)를 반환해
  README에 깨진 이미지 대신 이유를 표시 (GitHub camo는 200이 아닌 응답을 502로
  바꿈). 찾지 못한 닉네임은 10분간 캐시
- 캐시된 ID가 404일 때 캐시를 지우고 다시 검색하도록 재시도 로직 수정
- 프로필 링크를 숫자 ID 주소로 생성 (/api/user-id 추가, 메인 페이지와 README
  안내 수정)
- 메인 페이지 미리보기와 생성 코드의 닉네임 인코딩, 입력값 앞뒤 공백 제거
- Dreamhack 요청마다 10초 타임아웃을 두고 함수 최대 실행 시간을 60초로 설정

Claude-Session: https://claude.ai/code/session_01AGcght9Lc8cAYdvYCrdSzd
@with-developer
with-developer merged commit 0109660 into main Nov 2, 2026
6 checks passed

This branch was previously deployed

1 inactive deployment
Preview — ca9fdc26 Deployed Nov 2, 2026 by github-actions[bot]
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.

1 participant