← 글 목록

블로그에 프로젝트별 개발 기록 트리 만들기 (연재 4/6)

/ 6분 분량

글이 하나둘 쌓이다 보니 어느 순간부터 이 프로젝트를 어떤 순서로 만들어왔는지 한눈에 안 보인다는 걸 느꼈다. 그래서 프로젝트 페이지에 개발 기록을 시간순 트리로 보여주는 기능을 직접 만들어봤고, 그 과정에서 SVG와 API 페이지네이션에 대해서도 다시 짚어보게 됐다.

학습 주제

  • 프로젝트별 블로그 글을 시간순 트리 UI로 묶어서 보여주기
  • 부수적으로 발생한 SVG 아이콘 클리핑 문제와 API 페이지네이션 문제 해결
  • 학습 날짜: 2026년 7월 24일

탐구 과정

처음 문제의식은 단순했다. 글이 100개 넘게 쌓이니까 정작 "이 프로젝트를 이런 순서로 만들었다"는 흐름이 하나도 안 보였다. 그래서 프로젝트별로 관련 글을 모아서 개발 순서대로 보여주는 트리 뷰를 만들어보기로 했다.

그런데 막상 손대다 보니 사소한데 거슬리는 문제들이 먼저 눈에 들어왔다. 메인 페이지 히어로 문구가 중간에 어색하게 잘려 내려가는 것, 서버 아이콘 SVG가 아래쪽이 살짝 잘려 보이는 것. 아이콘 문제를 파고들어 보니 원인은 의외로 단순했다. SVG의 viewBox는 24×24인데 사각형 좌표가 그 범위를 0.25만큼 벗어나 있었다. viewBox 밖으로 나간 부분은 그대로 잘려서 렌더링된다는 걸 이번에 확인했다. 좌표를 y=1.75, 9.25, 16.75로 다시 계산해서 중앙에 오도록 맞추니 해결됐다.

트리 기능을 만들면서는 API 쪽에서 막혔다. "website" 태그가 붙은 글이 110개인데, 트리에 표시되는 건 100개까지밖에 안 됐다. 확인해보니 API가 서버 단에서 limit을 100으로 강제 제한하고 있었다. 한 번의 요청으로는 전체를 가져올 수 없는 구조였다. 그래서 프론트엔드에서 페이지를 넘겨가며 여러 번 요청해서 전체 데이터를 모으는 방식(페이지네이션)으로 바꿔야 했다.

마지막으로 실제로 눈으로 확인하고 싶어서 Playwright로 페이지를 직접 렌더링해서 스크린샷까지 찍어봤다. nginx 로컬 라우팅이 걸려 있어서 --resolve 옵션으로 도메인을 강제 매핑해 접근해야 했는데, 이 방식으로 실제 배포 환경과 비슷하게 테스트할 수 있었다.

핵심 학습 내용

SVG viewBox와 좌표계
viewBox는 SVG 내부 좌표계의 가시 영역을 정의한다. 도형의 좌표나 stroke가 이 영역을 벗어나면 그 부분은 그대로 잘려서 안 보인다. 아이콘이 이상하게 잘려 보인다면 좌표 값이 viewBox 경계를 넘는지부터 확인하면 된다.

<!-- 문제 상황: viewBox는 24x24인데 y=16.75+stroke가 24를 넘어감 -->
<rect y="17" width="24" height="8" />

<!-- 수정: 중앙에 오도록 좌표 재계산 -->
<rect y="16.75" width="24" height="6.5" />

API 페이지네이션 처리
서버가 한 번에 줄 수 있는 데이터 개수를 제한(limit=100)해두는 건 흔한 패턴이다. 클라이언트에서 전체 데이터가 필요하면 offset이나 page 값을 바꿔가며 응답이 빈 배열이 될 때까지 반복 요청해야 한다.

async function loadAllPosts(tag) {
  let page = 1, all = [];
  while (true) {
    const res = await fetch(`/api/posts?tag={tag}&limit=100&page={page}`);
    const data = await res.json();
    if (data.length === 0) break;
    all = all.concat(data);
    page++;
  }
  return all;
}

태그 기반 매칭으로 트리 구성
프로젝트마다 트리 코드를 따로 짜지 않고, 프로젝트의 github_url에서 레포 이름을 뽑아 그 이름이 태그로 붙은 글들을 모으는 방식을 썼다. 이렇게 하면 새 프로젝트를 추가해도 코드 변경 없이 자동으로 트리가 채워진다. UI는 <details>/<summary> 태그로 월별 접기/펼치기를 구현했다.

이해한 내용

  • SVG는 좌표계와 화면에 보이는 영역(viewBox)이 분리되어 있고, 이 둘이 안 맞으면 클리핑이 일어난다는 걸 실제 버그로 체감했다.
  • 서버 API에 제한이 걸려 있으면 클라이언트가 "한 번에 다 가져왔겠지"라고 가정하면 안 된다는 걸 깨달았다. 데이터 개수가 예상과 다르면 페이지네이션부터 의심해봐야 한다.
  • 태그(레포명) 기반으로 데이터를 느슨하게 연결하면, 프로젝트별로 별도 로직을 짜지 않아도 확장 가능한 구조를 만들 수 있다는 걸 확인했다.
  • 눈으로 직접 렌더링 결과를 봐야 확신이 생긴다는 것도 다시 느꼈다. 코드만 보고 "될 것 같다"로 끝내지 않고 Playwright로 실제 화면을 캡처해서 검증하는 습관이 도움이 됐다.

실전 적용

이 트리 구조는 프로젝트 페이지 전체에 자동으로 적용됐다. github_url만 있으면 되기 때문에 새 프로젝트를 만들 때 트리 로직을 신경 쓸 필요가 없었다. 실제로 로컬 git 저장소들을 훑어보면서 프로젝트로 만들 만한 걸 골라내는 작업도 했는데, 이 과정에서 공개/비공개 저장소를 구분하는 기준도 다시 생각해봤다. 비공개 저장소는 링크를 걸어도 방문자가 들어갈 수 없으니 프로젝트 목록에서 제외하는 게 맞다고 판단했다. 대신 공개 저장소 두 개(쿠버네티스 배포용 매니페스트, Rust로 만든 터미널 시스템 모니터)를 새 프로젝트로 등록했다.

추가 학습 계획

  • 지금은 글이 전부 한 달에 몰려 있어서 월별 접기 효과가 잘 안 보이는데, 데이터가 더 쌓이면 UX가 어떻게 달라지는지 지켜볼 계획
  • Playwright로 하던 수동 검증을 CI 파이프라인에 자동 테스트로 넣는 방법 공부
  • SVG 관련해서 viewBox, preserveAspectRatio 등 좌표계 개념을 좀 더 정리해볼 것