ClOr

ClOr

백엔드 실무 트러블슈팅과 AI 에이전트 구조 분석을 기록합니다.

Claude Code 해부학 (완결)

51만 줄 소스코드를 19편에 걸쳐 분석한 완결 시리즈

전체 시리즈 보기 →

백엔드 트러블슈팅

실무에서 겪은 장애와 해결 과정 기록

전체 시리즈 보기 →

최신 글

article thumbnail

사이드 프로젝트를 "언젠간 해야지" 하면서 미루는 개발자가 대부분이다. 나도 그랬다. 포트폴리오에 넣을 게 하나 필요한데, 매번 기획만 하다 흐지부지됐다.

그래서 이번엔 조건을 걸었다. 오늘 하루 안에 아이디어부터 배포까지 끝낸다. 안 되면 프로젝트를 버린다. 도구는 Claude Code 하나. 이 글은 그 하루의 기록이다. 튜토리얼이 아니라 실제로 무슨 일이 있었는지를 시간순으로 적은 것이다. 삽질도, 좌절도 다 포함이다.

목차

  • 만들려는 것
  • 타임라인
    • 09:00 — 프로젝트 초기화 (30분)
  • 프로젝트 개요
  • 기술 스택
  • 컨벤션
  • 주의사항
  • 빌드/실행
    • 09:30 — GitHub API 연동 (1시간)
    • 10:30 — AI 분석 로직 (1시간)
  • 절대 금지
    • 11:30 — UI 구현 (2시간)
    • 13:30 — 점심 + 중간 정리 (30분)
    • 14:00 — 폴리싱 (2시간)
    • 16:00 — 배포 (1시간)
    • 17:00 — 최종 점검 + 마무리 (1시간)
  • 결산
    • 시간
    • 비용
    • Claude Code 없이 했다면?
  • 배운 것 5가지
      1. CLAUDE.md를 먼저 써라
      1. 모델 전환을 적극적으로 하라
      1. 삽질도 Claude에게 설명하라
      1. 한 번에 완벽을 기대하지 마라
      1. 배포까지 해야 '완성'이다
  • 요약

만들려는 것

GitHub Profile Analyzer — GitHub 유저명을 입력하면 그 사람의 기여 패턴, 기술 스택, 활동 성향을 AI가 분석해서 "개발자 페르소나 카드"로 보여주는 웹앱이다.

왜 이걸 만들었나? 이유는 단순하다.

  1. 포트폴리오에 넣을 사이드 프로젝트가 필요했다. 면접에서 "개인 프로젝트 있으세요?" 물어보면 할 말이 있어야 한다.
  2. "AI + 개발자 도구" 조합이 요즘 관심을 끈다. GitHub 프로필을 분석해주는 서비스가 이미 몇 개 있지만, AI로 "페르소나"를 만들어주는 건 차별점이 될 수 있다고 판단했다.
  3. 기술적으로 적당히 도전적이다. 외부 API 연동 + AI 통합 + 동적 OG 이미지 생성 — 면접에서 설명하기 좋은 기술 포인트가 여러 개 들어간다.

스택은 이렇게 정했다:

  • Next.js 14 (App Router) + TypeScript + Tailwind CSS
  • Claude API — 분석 엔진
  • GitHub REST API — 데이터 소스
  • Vercel — 배포

이제 시작이다.

타임라인

09:00 — 프로젝트 초기화 (30분)

커피 한 잔 내리고 터미널을 열었다. Claude Code에 첫 프롬프트를 던졌다.

나: Next.js 14 + TypeScript + Tailwind 프로젝트를 만들어줘. 
    GitHub API로 유저 프로필을 가져와서 AI가 분석하는 앱이야.
    src/app 구조로 잡아줘.

Claude가 create-next-app을 실행하고, 기본 디렉토리 구조를 잡고, 불필요한 보일러플레이트를 정리하고, 기본 페이지까지 만들었다. 여기까지는 순조로웠다.

그런데 여기서 핵심적인 한 가지를 먼저 했다CLAUDE.md 작성이다.

# GitHub Profile Analyzer

## 프로젝트 개요
GitHub 유저명을 입력하면 AI가 기여 패턴, 기술 스택, 개발자 성향을 분석하는 웹앱.

## 기술 스택
- Next.js 14 (App Router, src/app 구조)
- TypeScript (strict mode)
- Tailwind CSS
- Claude API (분석 엔진)
- GitHub REST API

## 컨벤션
- 컴포넌트: PascalCase, 파일명도 PascalCase
- 유틸/훅: camelCase
- API 응답 타입: interface로 정의, type 보다 interface 선호
- 에러 핸들링: try-catch + 사용자 친화적 에러 메시지

## 주의사항
- Claude API만 사용한다. OpenAI API 사용 금지.
- 서버 컴포넌트와 클라이언트 컴포넌트를 명확히 분리한다.

## 빌드/실행
- npm run dev: 개발 서버
- npm run build: 프로덕션 빌드
- npm run lint: 린트 체크

이걸 먼저 써놓으니 이후 모든 프롬프트에서 Claude가 일관된 코드를 출력했다. CLAUDE.md 없이 시작하면 중간에 스타일이 왔다갔다하는데, 이걸 먼저 잡아놓으면 그런 문제가 없다. 하루 프로젝트의 성패를 가른 건 이 파일이었다.

09:30 — GitHub API 연동 (1시간)

본격적으로 코드를 짜기 시작했다. GitHub REST API로 가져올 데이터를 정리했다.

  • 유저 기본 정보 (/users/{username})
  • 공개 레포 목록 (/users/{username}/repos)
  • 최근 이벤트 (커밋, PR, 이슈 등) (/users/{username}/events)
  • 사용 언어 통계 (각 레포의 /languages 엔드포인트)

Claude에게 "GitHub API로 유저 프로필 데이터를 가져오는 래퍼를 만들어줘. 타입도 같이"라고 했더니 한 번의 프롬프트로 API 래퍼 함수 + TypeScript interface + 에러 핸들링까지 나왔다. GitHubUser, GitHubRepo, GitHubEvent 같은 인터페이스가 API 응답 스키마에 맞게 정의됐다.

여기서 첫 번째 문제가 발생했다. Rate limit이다.

GitHub API는 인증 없이 시간당 60회만 호출할 수 있다. 개발 중에 계속 테스트하다 보니 금방 한도에 걸렸다. Claude에게 상황을 설명했더니 바로 GitHub Personal Access Token을 환경변수로 추가하는 코드를 작성해줬다. 인증하면 시간당 5,000회로 늘어난다.

const headers: HeadersInit = {
  'Accept': 'application/vnd.github.v3+json',
};

if (process.env.GITHUB_TOKEN) {
  headers['Authorization'] = `Bearer ${process.env.GITHUB_TOKEN}`;
}

간단한 수정이지만, rate limit에 걸렸을 때 "왜 안 되지?" 하고 삽질할 시간을 Claude가 아껴줬다. 원인을 설명하고 해결책까지 한 번에 제시하니까.

레포별 언어 통계를 합산해서 전체 기술 스택 비율을 계산하는 로직도 Claude가 깔끔하게 처리했다. 수동으로 했으면 Promise.all + reduce 조합을 머릿속으로 설계하면서 한참 걸렸을 텐데, Claude는 바로 작동하는 코드를 내놨다.

10:30 — AI 분석 로직 (1시간)

이제 수집한 GitHub 데이터를 Claude API에 넘겨서 분석하는 부분이다. Next.js의 Server Action으로 구현했다.

핵심은 프롬프트 설계였다. GitHub 데이터를 넣으면 아래 형태의 JSON을 반환하도록 했다:

{
  "persona": "오픈소스 수호자",
  "description": "...",
  "stats": {
    "consistency": 85,
    "diversity": 70,
    "impact": 60,
    "collaboration": 90
  },
  "topLanguages": ["TypeScript", "Python", "Go"],
  "badges": ["야간 코딩러", "PR 리뷰어", "문서화 챔피언"],
  "summary": "..."
}

여기서 삽질 1이 발생했다. Claude Code가 분석 로직 코드를 작성하는데, OpenAI API 코드를 썼다. new OpenAI()로 시작하는 코드가 나왔다. 왜? Claude Code의 학습 데이터에 OpenAI API 예제가 압도적으로 많기 때문이다. AI 분석 로직이라고 하면 반사적으로 OpenAI SDK를 가져오는 거다.

즉시 CLAUDE.md에 한 줄을 추가했다:

## 절대 금지
- OpenAI SDK/API 사용 금지. 모든 AI 호출은 @anthropic-ai/sdk의 Claude API를 사용한다.

이렇게 추가하고 다시 시키니 깔끔하게 Anthropic SDK로 코드가 나왔다. CLAUDE.md에 금지사항을 명시하는 게 생각보다 중요하다.

삽질 2도 여기서 터졌다. Claude API 응답이 가끔 JSON이 아닌 텍스트로 오는 문제다. "물론이죠! 분석 결과입니다:" 같은 서문이 붙어서 JSON 파싱이 실패했다. Claude에게 이 문제를 설명하니 두 가지 해결책을 제시했다:

  1. 시스템 프롬프트에 "JSON만 반환하라"를 더 강하게 명시
  2. 응답에서 JSON 부분만 추출하는 fallback 파서 추가

둘 다 적용했다. 이중 안전장치를 걸어두니 이후로는 파싱 에러가 안 났다.

11:30 — UI 구현 (2시간)

기능은 돌아간다. 이제 보여주는 부분이다. 여기서 전략적으로 /model opus로 모델을 전환했다. 디자인 관련 작업은 Opus가 확실히 감각이 있다. Sonnet으로 UI를 시키면 기능적으로는 동작하지만, 디자인 감각이 떨어지는 경우가 많다.

메인 페이지부터 시작했다. 검색창 하나와 결과 카드를 보여주는 단순한 구조다. 하지만 "개발자 페르소나 카드"가 이 앱의 핵심 비주얼이다. Claude에게 이렇게 요청했다:

게임 캐릭터 카드 느낌으로 페르소나 카드를 만들어줘.
그라데이션 배경, 스탯 바(체력 바처럼), 뱃지, 칭호가 있어야 해.
다크 테마 기반으로 하고, 카드에 빛나는 효과도 넣어줘.

결과물이 기대 이상이었다. Tailwind로 구현된 카드에 그라데이션 보더, 반투명 백드롭, 스탯 바(프로그레스 바 형태), 뱃지 칩 등이 포함됐다. 호버하면 미세하게 빛나는 glow 효과까지 CSS로 구현해놨다.

<div className="relative group">
  <div className="absolute -inset-0.5 bg-gradient-to-r from-purple-600 
    to-cyan-600 rounded-xl blur opacity-30 group-hover:opacity-60 
    transition duration-500" />
  <div className="relative bg-gray-900 rounded-xl p-6">
    {/* 카드 내용 */}
  </div>
</div>

이런 Tailwind 조합을 직접 찾아가며 했으면 아마 카드 하나에 1시간은 걸렸을 거다. Claude는 10분 만에 완성했다.

반응형도 한 번에 처리됐다. 모바일에서 카드가 풀 너비로, 데스크탑에서 적절한 최대 너비로. md: 프리픽스를 잘 활용해서 깔끔하게 나왔다.

스탯 바 컴포넌트, 뱃지 컴포넌트, 언어 비율 차트까지 약 2시간 만에 전체 UI가 완성됐다. 손으로 했으면 이것만 하루가 걸렸을 작업이다.

13:30 — 점심 + 중간 정리 (30분)

점심을 먹으면서 현재 상태를 정리했다.

  • 기본 동작은 된다: 유저명 입력 → GitHub 데이터 수집 → AI 분석 → 페르소나 카드 출력
  • 하지만 로딩 UX가 없다: 분석에 5-10초 걸리는데 그 동안 화면이 멈춰 보인다
  • 에러 처리가 부족하다: 존재하지 않는 유저명을 넣으면 빈 화면이다
  • 공유 기능이 없다: 결과를 다른 사람에게 보여줄 수 없다

Claude Code로 돌아와서 /compact를 실행했다. 오전 내내 작업한 대화가 꽤 길어졌기 때문이다. 컨텍스트가 커지면 응답 품질이 떨어지고, 비용도 올라간다. 요약할 때 "현재 파일 구조, 완성된 기능, 남은 작업"에 초점을 맞추라고 키워드를 지정했다.

/compact 현재 파일 구조, 완성된 기능 목록, 남은 TODO

14:00 — 폴리싱 (2시간)

오후는 제품을 "쓸 만한 수준"으로 올리는 작업이다. 기능 추가보다 UX 다듬기에 시간을 쏟았다.

로딩 스켈레톤 — 분석 중일 때 카드 형태의 스켈레톤 UI를 보여준다. Claude에게 "분석 결과 카드와 동일한 레이아웃의 스켈레톤을 만들어줘. Tailwind animate-pulse 사용"이라고 했더니 바로 나왔다. 스켈레톤이 있으니 체감 로딩 시간이 훨씬 짧게 느껴진다.

에러 상태 UI — 유저를 찾을 수 없는 경우, API 한도 초과, 네트워크 에러 각각에 대해 다른 에러 메시지와 일러스트를 보여준다. 에러 분기를 enum으로 정의하고 각 상태에 맞는 UI를 Claude가 만들었다.

분석 결과 공유 기능 — 분석 결과를 URL로 공유할 수 있게 했다. 유저명을 쿼리 파라미터로 넣어서 /analyze?user=octocat 같은 형태로. "URL 복사" 버튼을 누르면 클립보드에 복사되고, 토스트 알림이 뜬다.

OG 이미지 동적 생성 — 이건 솔직히 해본 적이 없는 작업이었다. 카카오톡이나 트위터에 링크를 공유하면 미리보기 이미지가 뜨는 그것. Next.js의 @vercel/og를 사용하면 서버에서 이미지를 동적으로 생성할 수 있다. Claude에게 시켰더니 한 번에 됐다. 유저의 페르소나와 스탯이 들어간 이미지가 생성되는 API 라우트를 만들었다.

그런데 여기서 삽질 3이 터졌다. OG 이미지에 한글이 전부 깨져서 네모(□)로 나온다. 원인은 폰트다. @vercel/og는 기본적으로 영문 폰트만 내장하고 있어서, 한글을 렌더링하려면 별도 폰트를 로딩해야 한다.

Claude에게 "OG 이미지에 한글이 깨진다"고 했더니 바로 원인을 짚고 해결책을 제시했다:

// Google Fonts에서 Noto Sans KR을 fetch로 가져온다
const fontData = await fetch(
  'https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@700'
).then(res => res.arrayBuffer());

return new ImageResponse(
  (<div style={{ fontFamily: 'Noto Sans KR' }}>{/* ... */}</div>),
  {
    width: 1200,
    height: 630,
    fonts: [{ name: 'Noto Sans KR', data: fontData, style: 'normal' }],
  }
);

이 문제를 직접 구글링해서 해결했으면 30분은 더 걸렸을 거다. "해본 적 없는 작업"에서 Claude의 가치가 가장 크다. 내가 모르는 것의 존재조차 모를 때, Claude는 문제의 원인과 해결책을 동시에 안다.

16:00 — 배포 (1시간)

로컬에서는 완벽하게 돌아간다. 이제 세상에 내놓을 차례다. Vercel에 배포하기로 했다.

Vercel CLI로 프로젝트를 연결하고, 환경변수를 설정했다:

  • GITHUB_TOKEN — GitHub API 인증용
  • ANTHROPIC_API_KEY — Claude API 호출용

첫 배포. 빌드 에러. 여기서 삽질 4가 터졌다.

Error: useState is not allowed in Server Components.

서버 컴포넌트에서 useState를 사용하는 파일이 있었다. 로컬 개발 서버에서는 이게 경고만 뜨고 동작하는 경우가 있는데, 프로덕션 빌드에서는 에러로 잡힌다. 로컬에서 된다고 끝이 아니다.

Claude에게 에러 로그를 보여줬더니 해당 컴포넌트를 분리하는 방안을 제시했다. 검색 폼과 결과 표시 영역을 'use client' 컴포넌트로 분리하고, 데이터 페칭은 서버 컴포넌트에서 처리하는 구조로 리팩토링했다.

// SearchSection.tsx — 클라이언트 컴포넌트
'use client';
// useState, useTransition 등 사용 가능

// page.tsx — 서버 컴포넌트  
// SearchSection을 import해서 렌더링

수정하고 두 번째 배포. 성공. 빌드가 통과하고 프리뷰 URL이 떴다. 실제로 접속해서 GitHub 유저명을 넣어봤다. 동작한다.

커스텀 도메인도 연결했다. Vercel 대시보드에서 도메인을 추가하고, DNS 설정을 바꾸고, SSL이 자동으로 붙는다. 이 과정은 Claude 없이도 5분이면 되는 작업이다.

17:00 — 최종 점검 + 마무리 (1시간)

배포된 앱을 실제로 여러 GitHub 유저로 테스트했다.

  • torvalds (Linus Torvalds) — "커널의 수호자" 페르소나가 나왔다. C 100% 스택. 일관성 스탯이 99.
  • sindresorhus — "npm 생태계의 건축가". JavaScript/TypeScript 비중이 압도적.
  • octocat — GitHub 공식 마스코트 계정. 활동이 거의 없어서 "잠재된 관찰자" 페르소나가 나왔다.

각각 다른 페르소나와 스탯이 나오는 걸 보니 확실히 재미있었다. 분석 품질도 나쁘지 않다. Claude API의 분석 능력이 이 앱의 핵심 가치인데, 꽤 그럴듯한 결과를 내놓는다.

README도 Claude에게 시켰다. 프로젝트 설명, 스크린샷 위치, 로컬 실행 방법, 환경변수 목록, 배포 방법까지 3분 만에 완성.

마지막으로 /cost를 눌러서 오늘 하루 세션 비용을 확인했다.

결산

시간

단계 소요 시간
초기화 + CLAUDE.md 30분
GitHub API 연동 1시간
AI 분석 로직 1시간
UI 구현 2시간
폴리싱 2시간
배포 1시간
최종 점검 1시간
합계 8.5시간

아침 9시에 시작해서 저녁 6시 30분에 끝났다. 점심 30분 빼면 순수 작업 시간 8시간. 하루 만에 아이디어→배포를 완료했다.

비용

항목 비용
Claude Code 세션 ~$8 (Max 플랜이면 구독에 포함)
Claude API (앱 내부 테스트) ~$0.50
Vercel 배포 무료 (Hobby 플랜)
GitHub API 무료
총합 ~$8.50

$8.50으로 포트폴리오에 넣을 사이드 프로젝트가 하나 생겼다. 커피 두 잔 값이다.

Claude Code 없이 했다면?

솔직하게 견적을 내보면:

  • 프로젝트 초기화 + 설정: 동일 (30분)
  • GitHub API 연동: 2-3시간. 타입 정의를 수동으로 하고, 에러 핸들링 패턴을 찾아보고, rate limit 문제를 구글링해야 한다.
  • AI 분석 로직: 2시간. API 문서 읽고, 프롬프트 실험하고, JSON 파싱 문제 해결.
  • UI 구현: 4-6시간. 이게 가장 큰 차이다. Tailwind 클래스 조합을 하나하나 찾아보고, 그라데이션 효과를 실험하고, 반응형을 잡는 시간.
  • 폴리싱: 3-4시간. OG 이미지 같은 건 처음 해보는 작업이라 러닝커브가 있다.
  • 배포 + 디버깅: 2시간.

합치면 14-18시간, 즉 2-3일은 걸렸을 거다. Claude Code가 8.5시간으로 압축해준 것이다.

특히 차이가 큰 영역은:

  1. UI 작업 — Tailwind 조합을 일일이 찾아볼 필요 없음
  2. 타입 정의 — API 응답에 맞는 인터페이스를 수동으로 짜는 건 지루하고 오래 걸림
  3. "해본 적 없는 작업" — OG 이미지 동적 생성 같은 것. 러닝커브를 Claude가 대신 타줌

배운 것 5가지

1. CLAUDE.md를 먼저 써라

이게 있고 없고가 Claude의 코드 품질을 결정한다. CLAUDE.md 없이 시작하면 Claude가 매번 다른 스타일로 코드를 짠다. interface 대신 type을 쓰기도 하고, 네이밍 컨벤션이 왔다갔다 하고, 심지어 OpenAI SDK를 가져다 쓰기도 한다.

프로젝트의 "헌법"을 먼저 작성해라. 5분이면 된다. 그 5분이 뒤에서 2시간을 아껴준다.

2. 모델 전환을 적극적으로 하라

모든 작업에 같은 모델을 쓸 필요가 없다. 내가 오늘 쓴 패턴은:

  • 디자인/UI 작업 → Opus. 감각이 다르다.
  • 반복적인 코드 수정, 버그 수정 → Sonnet. 빠르고 저렴하다.
  • 아키텍처 결정, 복잡한 로직 → Opus.

/model 명령어로 언제든 전환 가능하다. 비용 효율과 품질의 균형을 잡는 핵심 전략이다.

3. 삽질도 Claude에게 설명하라

"이거 안 되는데"라고 하면 Claude도 뭘 해야 할지 모른다. "이 에러 메시지가 나오는데, 이런 상황에서 이런 것을 시도했다"고 구체적으로 말해야 한다.

OG 이미지 한글 깨짐 문제를 예로 들면:

  • 나쁜 프롬프트: "OG 이미지가 이상해"
  • 좋은 프롬프트: "OG 이미지에서 한글이 □로 나온다. @vercel/og를 사용 중이고, 영문은 정상 출력된다"

후자가 10배 빠르게 해결된다.

4. 한 번에 완벽을 기대하지 마라

Claude가 처음에 OpenAI API를 쓴 것처럼, 첫 결과물은 완벽하지 않다. 그게 정상이다. 첫 결과물을 기반으로 수정하는 게, 처음부터 완벽한 프롬프트를 설계하는 것보다 훨씬 빠르다.

완벽한 프롬프트를 쓰려고 10분을 고민하는 대신, 대충 시키고 결과를 보고 수정 지시하는 게 5분이면 끝난다. 반복이 빠르다는 게 AI 코딩의 핵심 장점이다.

5. 배포까지 해야 '완성'이다

로컬에서 돌아가는 건 50%다. 진짜 문제는 배포 과정에서 나온다. 서버/클라이언트 컴포넌트 분리 문제처럼 로컬에서는 안 잡히는 에러가 프로덕션 빌드에서 터진다.

"나중에 배포해야지" 하면서 로컬에서만 완성해두면, 그 "나중"은 거의 안 온다. 하루 프로젝트라면 무조건 당일 배포까지 끝내라.

요약

  • 소요 시간: 8.5시간 (아이디어 → 배포)
  • 총 비용: $8.50
  • 핵심 무기: CLAUDE.md 선행 작성, 모델 전환 (/model), 컨텍스트 관리 (/compact)
  • 가장 큰 시간 절약: UI 구현 (체감 4배 빨라짐)과 "해본 적 없는 작업" (OG 이미지 등)
  • 삽질 횟수: 4번. 전부 Claude가 해결해줌. 직접 구글링했으면 각각 30분 이상.

결국 AI 코딩의 핵심은 "코드를 대신 짜주는 것"이 아니다. 의사결정을 빠르게 하는 것이다. "이 라이브러리를 쓸까 저걸 쓸까", "이 에러의 원인이 뭘까", "이 UI를 어떤 Tailwind 클래스로 구현할까" — 이런 고민의 시간이 초 단위로 줄어든다.

하루 만에 사이드 프로젝트를 완성할 수 있다는 건, 더 이상 "시간이 없어서"라는 핑계가 안 통한다는 뜻이기도 하다. 주말 하루면 된다. 커피 두 잔 값이면 된다. 이제 남은 건 아이디어와 실행력뿐이다.


관련글:

profile

ClOr

@ClOr

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!

ClOr · 백엔드 트러블슈팅과 AI 에이전트 구조 분석을 기록합니다.