Claude Code를 설치하고 “이거 고쳐줘”라고 말하면 뭔가 해준다. 그런데 결과물이 마음에 안 들 때가 있다. 내 프로젝트 컨벤션을 무시하거나, 이미 있는 유틸 함수를 새로 만들거나.

이유는 간단하다. Claude가 프로젝트를 모른다.

CLAUDE.md를 제대로 쓰면 달라진다.


CLAUDE.md란

프로젝트 루트에 두는 마크다운 파일이다. Claude Code가 세션 시작할 때 자동으로 읽는다.

프로젝트/
├── CLAUDE.md        ← 이 파일
├── src/
├── package.json
└── ...

프로젝트의 컨텍스트를 담는다. 구조, 컨벤션, 주의사항. 사람한테 온보딩 문서 주듯이 Claude한테 주는 문서다.


기본 구조

# 프로젝트 개요

한 줄 설명. 무슨 프로젝트인지.

## 기술 스택

- Frontend: React 18, TypeScript, Tailwind
- Backend: Spring Boot 3.2, Java 21
- DB: PostgreSQL 15

## 프로젝트 구조

src/
├── components/   # 재사용 UI 컴포넌트
├── pages/        # 라우트별 페이지
├── hooks/        # 커스텀 훅
├── utils/        # 유틸리티 함수
└── types/        # 타입 정의

## 코드 컨벤션

- 컴포넌트: PascalCase (Button.tsx)
- 함수/변수: camelCase
- 상수: UPPER_SNAKE_CASE
- 파일당 하나의 컴포넌트

## 중요 파일

- `src/utils/api.ts`: API 호출은 여기 있는 함수 사용
- `src/hooks/useAuth.ts`: 인증 관련 로직
- `src/types/index.ts`: 공통 타입 정의

## 주의사항

- console.log 커밋 금지
- any 타입 사용 금지
- 새 의존성 추가 전 확인 필요

효과적인 CLAUDE.md 작성 팁

1. 짧게 쓴다

Claude의 컨텍스트 윈도우는 무한하지 않다. 장황하게 쓰면 중요한 게 묻힌다.

안 좋은 예:

이 프로젝트는 2023년에 시작되었으며, 초기에는 JavaScript로
작성되었다가 나중에 TypeScript로 마이그레이션되었습니다.
현재는 React 18을 사용하고 있으며...

좋은 예:

React 18 + TypeScript 프로젝트. 이커머스 백오피스.

2. 실제로 필요한 것만 넣는다

모든 폴더 구조를 다 쓸 필요 없다. Claude가 헷갈릴 만한 것, 실수할 만한 것만.

## 헷갈리기 쉬운 것

- `api/` vs `services/`: api는 HTTP 클라이언트, services는 비즈니스 로직
- `Button` vs `BaseButton`: Button은 스타일 포함, BaseButton은 래퍼용

3. 명령형으로 쓴다

설명보다 지시가 낫다.

설명:

우리 팀은 보통 함수형 컴포넌트를 사용합니다.

지시:

클래스 컴포넌트 쓰지 마라. 함수형으로.

프롬프트 팁

CLAUDE.md가 기본 컨텍스트라면, 프롬프트는 실시간 지시다.

패턴 1: 구체적으로

모호함:

이 코드 좀 개선해줘

구체적:

이 함수에서 중복 API 호출 제거해줘. 캐싱 써서.

패턴 2: 참조 파일 명시

src/utils/format.ts 보고 같은 스타일로
src/utils/validate.ts 만들어줘

기존 코드를 레퍼런스로 주면 컨벤션을 맞춘다.

패턴 3: 제약 조건 명시

외부 라이브러리 추가하지 말고, 기존 코드만으로 해결해줘
테스트 코드도 같이 작성해줘. Jest + React Testing Library로.

패턴 4: 단계별 요청

큰 작업은 나눠서.

1단계: 현재 코드 분석하고 문제점 알려줘
2단계: 리팩토링 계획 세워줘
3단계: 승인하면 실행해줘

한 번에 다 하라고 하면 중간에 방향이 틀어질 수 있다.


리팩토링 실전 예시

Spring Boot 프로젝트에서 실제로 있었던 케이스.

문제 상황

// OrderService.java
public OrderResponse createOrder(OrderRequest request) {
    // 1. 재고 확인
    Product product = productRepository.findById(request.getProductId())
        .orElseThrow(() -> new RuntimeException("상품 없음"));
    if (product.getStock() < request.getQuantity()) {
        throw new RuntimeException("재고 부족");
    }

    // 2. 주문 생성
    Order order = new Order();
    order.setProductId(request.getProductId());
    order.setQuantity(request.getQuantity());
    order.setPrice(product.getPrice() * request.getQuantity());
    order.setStatus("PENDING");
    order.setCreatedAt(LocalDateTime.now());
    orderRepository.save(order);

    // 3. 재고 차감
    product.setStock(product.getStock() - request.getQuantity());
    productRepository.save(product);

    // 4. 응답 생성
    OrderResponse response = new OrderResponse();
    response.setOrderId(order.getId());
    response.setStatus(order.getStatus());
    response.setTotalPrice(order.getPrice());
    return response;
}

140줄짜리 서비스에 이런 메서드가 10개. 전형적인 트랜잭션 스크립트.

CLAUDE.md 설정

## 코드 스타일

- 서비스 메서드는 10줄 이내 유지
- 비즈니스 로직은 도메인 객체에
- RuntimeException 대신 커스텀 예외 사용
- setter 대신 생성자/빌더 패턴

## 기존 구조

- `src/main/java/.../exception/`: 커스텀 예외 클래스들
- `src/main/java/.../domain/`: 도메인 엔티티

프롬프트

OrderService.createOrder 메서드 리팩토링해줘.

요구사항:
1. 도메인 로직은 Order, Product 엔티티로 이동
2. 커스텀 예외 사용 (기존 exception 패키지 참고)
3. 빌더 패턴으로 객체 생성
4. 서비스는 흐름 제어만

결과

// Product.java (도메인)
public void validateStock(int quantity) {
    if (this.stock < quantity) {
        throw new InsufficientStockException(this.id, this.stock, quantity);
    }
}

public void decreaseStock(int quantity) {
    validateStock(quantity);
    this.stock -= quantity;
}

// Order.java (도메인)
public static Order create(Product product, int quantity) {
    return Order.builder()
        .productId(product.getId())
        .quantity(quantity)
        .price(product.calculatePrice(quantity))
        .status(OrderStatus.PENDING)
        .createdAt(LocalDateTime.now())
        .build();
}

public OrderResponse toResponse() {
    return OrderResponse.builder()
        .orderId(this.id)
        .status(this.status.name())
        .totalPrice(this.price)
        .build();
}

// OrderService.java (서비스)
@Transactional
public OrderResponse createOrder(OrderRequest request) {
    Product product = productRepository.findById(request.getProductId())
        .orElseThrow(() -> new ProductNotFoundException(request.getProductId()));

    product.decreaseStock(request.getQuantity());
    Order order = Order.create(product, request.getQuantity());

    return orderRepository.save(order).toResponse();
}

서비스 메서드가 6줄로 줄었다. 비즈니스 로직이 도메인으로 들어갔다.


정리

구분 핵심
CLAUDE.md 프로젝트 컨텍스트. 짧고 명확하게. 지시형으로.
프롬프트 구체적으로, 참조 파일 명시, 제약 조건 추가
큰 작업 단계별로 나눠서 요청

CLAUDE.md 잘 써두면 매번 같은 설명 안 해도 된다. 프롬프트는 그 위에서 구체적인 지시만 하면 된다.

“알아서 해줘”보다 “이렇게 해줘”가 낫고, “이렇게 해줘”보다 “여기 보고 이렇게 해줘”가 낫다.