Tips & Tricks (업데이트: 2026. 6. 3.)

Claude Code 버그 리포트 템플릿: 모호한 오류를 재현 가능한 수정으로 바꾸기

Claude Code에 재현 단계, 로그, 환경, 실패 테스트, PR 인계를 함께 전달하는 실전 템플릿입니다.

Claude Code 버그 리포트 템플릿: 모호한 오류를 재현 가능한 수정으로 바꾸기

Claude Code에 “화면이 깨졌어요” 또는 “테스트가 실패합니다”라고만 말하면, 모델은 추측으로 시작합니다. 처음 나온 패치가 그럴듯해 보여도 근본 원인, 검증 명령, 리뷰어가 읽을 설명이 빠지기 쉽습니다. 좋은 버그 리포트는 불만을 재현 가능한 디버깅 작업으로 바꿉니다.

이 글은 Claude Code 세션에 바로 넣을 수 있는 템플릿을 제공합니다. 증상, 기대 동작, 실제 동작, 최소 재현, 로그, 환경, 실패 테스트, 제약, PR 인계까지 한 번에 정리합니다. 먼저 첫 작업 runbook을 읽고, 깊은 조사는 디버깅 기법과 연결하세요. 수정 뒤에는 PR 품질 체크리스트로 마무리합니다.

공식 문서는 CLI reference, commands reference, common workflows, GitHub Actions guide를 확인하면 됩니다. --verbose, /debug, /feedback, /bug, PR 자동화의 용도가 분명해집니다.

유용한 리포트의 구성

항목적을 내용Claude Code가 판단하는 것
증상페이지, 명령, route, API 중 어디서 깨지는지조사 시작점
기대 동작올바른 비즈니스 또는 UI 규칙수정 완료 기준
실제 동작에러 문구, 상태 코드, 깨진 화면, 잘못된 출력사실과 추측의 분리
최소 재현몇 분 안에 실패하는 가장 짧은 절차가설 검증 방법
환경OS, runtime, 브라우저, branch, env 이름로컬과 CI 차이
증거로그, 스크린샷, stack trace, 실패 테스트수정 전후의 증명
제약수정 가능 파일과 건드리지 말아야 할 파일불필요한 큰 diff 방지
인계근본 원인, 검증, 위험, 후속 작업빠른 PR 리뷰

초보자가 가장 자주 빠뜨리는 것은 기대 동작입니다. “에러 없애기”는 요구사항이 아닙니다. API가 빈 배열을 반환해야 하는지, 400을 반환해야 하는지, 사용자에게 경고를 보여야 하는지 한 문장으로 적어야 합니다.

복사해서 쓰는 템플릿

아래 내용을 bug-report.md로 저장하고 빈칸을 채운 뒤 Claude Code에 전달하세요.

# Bug report for Claude Code

## Goal
- 고칠 버그:
- 원하는 결과:
- 이번 범위가 아닌 것:

## Environment
- OS:
- Node / package manager:
- Browser / device:
- Branch:
- 관련 env 이름, 값은 제외:

## Symptom
- 발생 위치:
- 영향을 받는 사용자:
- 빈도: 항상 / 간헐적 / 모름

## Expected behavior
-

## Actual behavior
-

## Minimum reproduction
1.
2.
3.

## Evidence
- Error message:
- Logs:
- Screenshot:
- Failing command:

## Recent changes
- PR / commit:
- 관련 가능성이 높은 파일:

## Constraints
- 수정 가능한 범위:
- 수정하지 말 것:
- secrets 또는 고객 데이터는 붙여 넣지 말 것:

## Request to Claude Code
1. 바로 패치하지 말 것
2. 가능성이 높은 원인 3개를 먼저 나열할 것
3. 각 가설을 반박할 최소 확인을 제안할 것
4. 최소 재현 또는 실패 테스트를 먼저 만들 것
5. 가장 작은 유효 diff로 수정할 것
6. 검증 명령과 남은 위험을 보고할 것

이 템플릿은 내부 티켓, 고객 지원 인계, PR 댓글에 모두 사용할 수 있습니다. 핵심은 Claude Code가 편집하기 전에 성공 기준을 정하는 것입니다.

실행 가능한 컨텍스트 수집 스크립트

branch, Node 버전, 현재 diff는 손으로 적다 보면 빠지기 쉽습니다. 아래 Node 스크립트는 의존성 없이 동작하고, 명백한 secret 문자열을 마스킹합니다.

// scripts/collect-bug-context.mjs
import { execFileSync } from "node:child_process";
import { existsSync, readFileSync } from "node:fs";
import { platform, release } from "node:os";
import { cwd } from "node:process";

function run(command, args) {
  try {
    return execFileSync(command, args, {
      cwd: cwd(),
      encoding: "utf8",
      stdio: ["ignore", "pipe", "pipe"],
    }).trim();
  } catch (error) {
    return `(failed: ${command} ${args.join(" ")})`;
  }
}

function maskSecrets(text) {
  return text
    .replace(/(api[_-]?key|token|secret|password)=([^\\s]+)/gi, "$1=***")
    .replace(/Bearer\\s+[A-Za-z0-9._-]+/g, "Bearer ***");
}

function readPackageScripts() {
  if (!existsSync("package.json")) return "package.json not found";
  const pkg = JSON.parse(readFileSync("package.json", "utf8"));
  return JSON.stringify(pkg.scripts ?? {}, null, 2);
}

const report = {
  generatedAt: new Date().toISOString(),
  cwd: cwd(),
  os: `${platform()} ${release()}`,
  node: process.version,
  branch: run("git", ["branch", "--show-current"]),
  status: run("git", ["status", "--short"]),
  lastCommit: run("git", ["log", "-1", "--oneline"]),
  diffStat: run("git", ["diff", "--stat"]),
  packageScripts: readPackageScripts(),
};

console.log(maskSecrets(JSON.stringify(report, null, 2)));

실행:

mkdir -p scripts
# 위 코드를 scripts/collect-bug-context.mjs 로 저장
node scripts/collect-bug-context.mjs > bug-context.json

마스킹은 보조 수단입니다. 실제 API 키, 고객 데이터, 운영 로그 전체는 붙여 넣지 말고 필요한 줄만 추리세요.

사용 사례1: 모바일 CTA가 넘침

나쁜 보고:

모바일 페이지가 깨집니다.

좋은 보고:

Symptom:
  /ko/blog/... 에서 390px 폭으로 상품 CTA 영역을 보면 버튼 오른쪽이 화면 밖으로 나간다.

Expected behavior:
  CTA 두 개가 세로로 쌓이고 가로 스크롤이 없어야 한다.

Minimum reproduction:
  1. Chrome DevTools에서 폭을 390px로 설정
  2. 문제가 있는 페이지 열기
  3. CTA 영역까지 스크롤

Evidence:
  document.documentElement.scrollWidth is 412
  Screenshot attached

Constraints:
  상품 링크와 문구는 바꾸지 말고 CSS 레이아웃만 확인한다.

이 정도면 Claude Code가 width, gap, 버튼 텍스트, 부모 컨테이너를 확인할 수 있습니다. 수익 페이지라면 productstraining 경로가 수정 후에도 살아 있는지 함께 확인하세요.

사용 사례2: Checkout API가 500 반환

API 문제에는 요청 형태, 기대 응답, 실제 에러, 관련 설정 이름이 필요합니다.

Symptom:
  POST /api/checkout 이 plan=pro 일 때만 500을 반환한다.

Expected behavior:
  200과 결제 URL을 반환한다. 설정이 없으면 명확한 설정 오류로 실패해야 한다.

Actual behavior:
  TypeError: Cannot read properties of undefined (reading 'prices')

Minimum reproduction:
  curl -X POST http://localhost:3000/api/checkout \
    -H "content-type: application/json" \
    -d '{"plan":"pro"}'

Environment:
  STRIPE_SECRET_KEY 와 PRICE_PRO_ID 를 사용한다. 값은 붙여 넣지 않는다.

Constraints:
  실제 결제 provider 호출을 늘리지 않는다. 먼저 설정 로딩과 입력 검증을 확인한다.

Claude Code에는 설정 로딩, 요청 검증, 가격 매핑이라는 세 가설을 비교하게 합니다. 로컬에서 재현 가능하면 handler 또는 config module 테스트로 실패 테스트를 만들 수 있습니다.

사용 사례3: 날짜 경계 회귀

timezone과 월말 버그는 스크린샷보다 실패 테스트가 더 강한 증거입니다.

import { describe, expect, it } from "vitest";
import { exportMonthlyOrderIds } from "../src/export-orders";

describe("exportMonthlyOrderIds", () => {
  it("includes March orders and excludes April 1 UTC", () => {
    const orders = [
      { id: "mar-start", createdAt: "2026-03-01T00:00:00.000Z" },
      { id: "mar-end", createdAt: "2026-03-31T23:59:59.999Z" },
      { id: "apr-start", createdAt: "2026-04-01T00:00:00.000Z" },
    ];

    expect(exportMonthlyOrderIds(orders, "2026-03")).toEqual(["mar-start", "mar-end"]);
  });
});

프롬프트는 명확해야 합니다. “이 테스트를 먼저 실패시키고, 로컬 timezone에 의존하지 않게 구현을 고쳐 주세요.” 흔한 함정은 UI 날짜 표시만 고치고 집계 경계를 그대로 두는 것입니다.

Claude Code 조사 프롬프트

Read bug-report.md and bug-context.json.

Process:
1. Do not edit yet
2. Separate facts from guesses
3. Rank the top three root-cause hypotheses
4. Propose the smallest check that could disprove each one
5. Create a minimum reproduction or failing test first
6. After approval, make the smallest useful fix

Done means:
- The expected/actual gap is explained
- A failing test or reproduction command remains
- Verification commands are reported
- The PR handoff includes root cause, fix, risk, and follow-up

공식 common workflows도 에러, 재현 명령, 절차, 간헐성 여부를 Claude에게 알려야 한다고 설명합니다. /debug는 Claude Code 세션 진단용이고, /feedback 또는 /bug는 Claude Code 제품에 대한 피드백입니다. 애플리케이션 버그 리포트와 섞지 마세요.

PR 인계 템플릿

## Root cause
-

## Fix
-

## Regression coverage
- Added failing test:
- Manual reproduction checked:

## Verification
- [ ] npm test
- [ ] npm run typecheck
- [ ] npm run build
- [ ] mobile / desktop visual check if UI changed

## Risk
-

## Claude Code notes
- Hypotheses rejected:
- Files intentionally not touched:
- Follow-up issue:

세션 handoff 템플릿테스트 전략에 연결하면 팀에서 반복하기 쉽습니다.

피해야 할 함정

서로 다른 버그를 하나의 리포트에 넣지 마세요. 로그인, 결제, 레이아웃은 별도 재현이 필요합니다.

로그 전체를 붙이지 마세요. 에러 주변 20줄, request ID, 재현 명령이면 충분한 경우가 많습니다.

경계값, 데이터 매핑, API 계약, 권한 판단 버그는 실패 테스트 없이 끝내지 마세요.

Claude Code에 “전체를 보고 알아서 고쳐”라고 요청하지 마세요. 작은 재현이 넓은 수정 권한보다 낫습니다.

PR 인계를 생략하지 마세요. 리뷰어는 근본 원인, 증거, 남은 위험을 알아야 합니다.

수익 동선도 검증 범위에 넣기

ClaudeCodeLab 같은 콘텐츠 사이트에서는 버그 수정이 CTA, 상품 카드, 무료 PDF 폼, Gumroad 링크, 상담 링크를 깨뜨릴 수 있습니다. 기사 레이아웃이나 상품 경로를 건드렸다면 이 동선도 검증 대상입니다.

개인 사용자는 무료 체크리스트를 자신의 저장소에 맞게 바꾸면 됩니다. 반복 가능한 프롬프트와 review gate, 설정 자료가 필요하면 products를 보세요. 팀이 bug report, Claude Code 권한, PR review, CI handoff를 하나의 프로세스로 묶어야 한다면 training에서 시작할 수 있습니다.

직접 적용한 결과

직접 적용해 보니 재현 단계, 기대 동작, 실패 테스트, PR 인계를 포함한 리포트가 단순한 “고쳐줘” 프롬프트보다 diff가 작고 리뷰 질문도 적었습니다. 가장 효과가 컸던 단계는 편집 전에 세 가지 가설을 먼저 요구하는 것이었습니다. 틀린 가설을 빨리 버리면 세션이 추측 패치가 아니라 증거 기반 디버깅으로 바뀝니다.

#claude-code #debugging #bug report #template #triage #communication
무료

무료 PDF: Claude Code 치트시트

이메일을 입력하면 명령, 리뷰 습관, 안전한 워크플로를 정리한 PDF를 받을 수 있습니다.

개인정보를 안전하게 관리하며 스팸을 보내지 않습니다.

Masa

작성자 소개

Masa

Claude Code 실무 워크플로와 팀 도입을 검증하는 엔지니어입니다.