복사해서 바로 쓸 수 있는 실전 하네스 3종
9편에서 하네스의 물리적 구조를 해부했다. 이 편에서는 실제 도메인에 맞춰 작성된 하네스 템플릿 3종을 제공한다. 각 템플릿은 해당 도메인의 특성을 반영한 완결된 하네스로, 프로젝트에 복사한 후 자신의 맥락에 맞게 수정하여 사용할 수 있다.
템플릿 1: REST API 백엔드
웹 서비스의 백엔드 API를 구축하는 가장 일반적인 시나리오다. Express/NestJS/FastAPI 등 프레임워크에 관계없이 적용할 수 있는 구조다.
디렉토리 구조
my-api/
├── .claude/
│ ├── CLAUDE.md
│ ├── agents/
│ │ ├── api-designer.md
│ │ ├── backend-dev.md
│ │ ├── db-engineer.md
│ │ └── qa-engineer.md
│ └── skills/
│ ├── endpoint-creation/
│ │ └── skill.md
│ └── db-migration/
│ └── skill.md
├── feature-list.json
├── progress.md
├── tests/
│ └── architecture.test.ts
└── .github/workflows/
└── pr-check.yml
CLAUDE.md
# CLAUDE.md — REST API 백엔드
## 프로젝트 개요
[서비스명]의 백엔드 REST API.
[프레임워크] + TypeScript + [DB] 기반.
[핵심 도메인 한 줄 설명].
## 기술 스택
- Runtime: Node.js 20
- Framework: [Express / NestJS / Fastify]
- ORM: [Prisma / TypeORM / Drizzle]
- DB: [PostgreSQL / MySQL]
- Cache: [Redis] (사용 시)
- Auth: [JWT / Session / OAuth]
- Test: Jest + Supertest
## 디렉토리 구조
src/
├── controllers/ # HTTP 요청 처리, 입력 검증, 응답 포맷팅
├── services/ # 비즈니스 로직 (HTTP 무관)
├── repositories/ # 데이터 접근 (DB 쿼리)
├── models/ # 데이터 모델, 타입 정의
├── middlewares/ # 인증, 에러 핸들링, 로깅
├── validators/ # 입력 검증 스키마
└── utils/ # 공용 유틸리티
## 의존성 규칙
controllers/ → services/, validators/, models/
services/ → repositories/, models/, utils/
repositories/→ models/, utils/
models/ → (의존 없음)
middlewares/ → services/, utils/
validators/ → models/
역방향 의존 금지:
- services/에서 controllers/ import 금지
- repositories/에서 services/ import 금지
- models/에서 어떤 레이어도 import 금지
## 코딩 컨벤션
- 함수명: camelCase
- 파일명: kebab-case.ts
- 클래스명: PascalCase
- HTTP 상태 코드: controllers/에서만 사용
- DB 쿼리: repositories/에서만 실행
- 환경 변수: config/ 모듈을 통해서만 접근
## 에러 처리
- 비즈니스 에러: src/utils/errors.ts의 AppError 상속
- NotFoundError (404)
- ValidationError (400)
- UnauthorizedError (401)
- ForbiddenError (403)
- ConflictError (409)
- services/에서 HttpException 사용 금지
- error middleware가 AppError → HTTP 응답 매핑
## API 설계 원칙
- RESTful 네이밍: 복수형 명사 (/users, /projects)
- 페이지네이션: cursor 기반 (?cursor=xxx&limit=20)
- 필터링: 쿼리 파라미터 (?status=active&sort=createdAt:desc)
- 응답 형식: { data: T, meta?: { cursor, hasMore } }
- 에러 형식: { error: { code, message, details? } }
## 테스트
- controllers/: E2E 테스트 (Supertest)
- services/: 단위 테스트 (의존성 mock)
- repositories/: 통합 테스트 (실제 DB)
- 파일 위치: 대상 파일 옆에 *.test.ts
- 커버리지 목표: 라인 80% 이상
## 에이전트 팀
- api-designer: 엔드포인트 설계, OpenAPI 스펙
- backend-dev: 서비스/컨트롤러/리포지토리 구현
- db-engineer: 스키마 설계, 마이그레이션, 쿼리 최적화
- qa-engineer: 테스트 작성, 커버리지 확보
엔드포인트 생성 스킬
# .claude/skills/endpoint-creation/skill.md
## 트리거
"엔드포인트 만들어줘", "API 추가", "CRUD 만들어줘"
## 절차
1. 리소스명과 필드 정의 확인
2. 파일 생성 순서:
a. models/{resource}.ts — 타입/인터페이스 정의
b. validators/{resource}.validator.ts — 입력 검증 스키마
c. repositories/{resource}.repository.ts — DB 접근
d. services/{resource}.service.ts — 비즈니스 로직
e. controllers/{resource}.controller.ts — HTTP 핸들러
f. routes/{resource}.routes.ts — 라우팅
3. 각 파일 작성 시:
- models/: 순수 타입만, 외부 의존 없음
- validators/: Zod 스키마, 에러 메시지 한글
- repositories/: ORM 사용, raw SQL 금지
- services/: HTTP 관련 코드 금지, AppError 사용
- controllers/: 검증 → 서비스 호출 → 응답 포맷팅만
4. 테스트 작성:
- services/*.test.ts (단위)
- controllers/*.test.ts (E2E)
5. 확인:
- npm run test:architecture 통과
- npm run lint 통과
- npm test 통과
템플릿 2: 프론트엔드 웹 애플리케이션
React/Next.js 기반 프론트엔드 프로젝트를 위한 하네스다. 컴포넌트 설계, 상태 관리, API 연동의 경계를 잡는 데 초점을 둔다.
디렉토리 구조
my-frontend/
├── .claude/
│ ├── CLAUDE.md
│ ├── agents/
│ │ ├── ui-designer.md
│ │ ├── frontend-dev.md
│ │ ├── state-engineer.md
│ │ └── a11y-reviewer.md
│ └── skills/
│ ├── component-creation/
│ │ └── skill.md
│ └── page-creation/
│ └── skill.md
├── feature-list.json
├── progress.md
└── tests/
└── architecture.test.ts
CLAUDE.md
# CLAUDE.md — 프론트엔드 웹 애플리케이션
## 프로젝트 개요
[서비스명]의 웹 프론트엔드.
Next.js 14 (App Router) + TypeScript + Tailwind CSS.
[핵심 사용자 경험 한 줄 설명].
## 기술 스택
- Framework: Next.js 14 (App Router)
- Language: TypeScript (strict mode)
- Styling: Tailwind CSS + shadcn/ui
- State: Zustand (클라이언트) / TanStack Query (서버)
- Form: React Hook Form + Zod
- Test: Vitest + Testing Library + Playwright
## 디렉토리 구조
src/
├── app/ # Next.js App Router (라우팅)
│ ├── (auth)/ # 인증 관련 페이지 그룹
│ ├── (dashboard)/ # 대시보드 페이지 그룹
│ └── api/ # Route Handlers (BFF)
├── components/
│ ├── ui/ # shadcn/ui 기반 원자 컴포넌트
│ ├── features/ # 도메인 기능 컴포넌트
│ └── layouts/ # 레이아웃 컴포넌트
├── hooks/ # 커스텀 훅
├── stores/ # Zustand 스토어
├── services/ # API 클라이언트, 외부 서비스 연동
├── types/ # 공유 타입 정의
└── lib/ # 유틸리티, 헬퍼
## 의존성 규칙
app/ → components/, hooks/, services/, stores/
components/ui/→ types/, lib/ (다른 컴포넌트 금지)
components/features/ → components/ui/, hooks/, services/, stores/, types/
hooks/ → services/, stores/, types/, lib/
stores/ → types/, lib/ (services/ 금지 — 훅에서 연결)
services/ → types/, lib/
types/ → (의존 없음)
lib/ → (의존 없음)
역방향 의존 금지:
- components/ui/에서 features/ import 금지
- services/에서 components/ import 금지
- stores/에서 services/ 직접 import 금지
## 컴포넌트 규칙
- ui/ 컴포넌트: 순수 UI, 비즈니스 로직 없음, props만으로 동작
- features/ 컴포넌트: 도메인 로직 포함 가능, hooks/stores 사용 가능
- 모든 컴포넌트에 displayName 설정
- Props 타입은 컴포넌트 파일 안에서 정의 (별도 파일 금지)
- children을 받는 컴포넌트는 PropsWithChildren 사용
## 상태 관리 원칙
- 서버 상태: TanStack Query (캐싱, 재검증, 낙관적 업데이트)
- 클라이언트 상태: Zustand (UI 상태, 폼 외의 로컬 상태)
- 폼 상태: React Hook Form (유효성 검증은 Zod)
- URL 상태: Next.js searchParams (필터, 페이지네이션)
- 전역 상태 남용 금지: "이 상태가 정말 전역이어야 하는가?" 확인
## 스타일링 규칙
- Tailwind 유틸리티 클래스 사용
- 인라인 style 속성 금지
- 커스텀 CSS 최소화 (글로벌 스타일은 globals.css에만)
- 반응형: mobile-first (sm → md → lg → xl)
- 다크 모드: Tailwind dark: 접두사 사용
## 접근성 (a11y)
- 모든 img에 alt 속성 필수
- 인터랙티브 요소에 aria-label 필수 (텍스트 없는 경우)
- 키보드 내비게이션 지원
- 색상 대비 WCAG AA 이상
## 테스트
- 컴포넌트: Vitest + Testing Library (사용자 관점 테스트)
- 훅: renderHook으로 테스트
- E2E: Playwright (핵심 사용자 흐름만)
- 파일 위치: 대상 파일 옆에 *.test.tsx
- 커버리지 목표: 라인 75% 이상
## 에이전트 팀
- ui-designer: 컴포넌트 설계, UI/UX 구조
- frontend-dev: 페이지/컴포넌트/훅 구현
- state-engineer: 상태 관리, API 연동, 캐싱 전략
- a11y-reviewer: 접근성 검수, 키보드/스크린리더 테스트
컴포넌트 생성 스킬
# .claude/skills/component-creation/skill.md
## 트리거
"컴포넌트 만들어줘", "UI 추가", "화면 만들어줘"
## 분류
먼저 컴포넌트 유형을 판별한다:
1. UI 컴포넌트 (components/ui/)
- 비즈니스 로직 없음, props만으로 동작
- 예: Button, Input, Card, Modal, Badge
2. Feature 컴포넌트 (components/features/)
- 특정 도메인에 종속
- hooks, stores, services 사용 가능
- 예: TaskCard, ProjectList, UserProfile
## UI 컴포넌트 작성 규칙
```tsx
// components/ui/button.tsx
import { cva, type VariantProps } from 'class-variance-authority';
import { forwardRef, type ButtonHTMLAttributes } from 'react';
import { cn } from '@/lib/utils';
const buttonVariants = cva(
'inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-2',
{
variants: {
variant: {
primary: 'bg-blue-600 text-white hover:bg-blue-700',
secondary: 'bg-gray-100 text-gray-900 hover:bg-gray-200',
destructive: 'bg-red-600 text-white hover:bg-red-700',
ghost: 'hover:bg-gray-100',
},
size: {
sm: 'h-8 px-3 text-sm',
md: 'h-10 px-4 text-sm',
lg: 'h-12 px-6 text-base',
},
},
defaultVariants: { variant: 'primary', size: 'md' },
}
);
interface ButtonProps
extends ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
isLoading?: boolean;
}
const Button = forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, isLoading, children, disabled, ...props }, ref) => (
<button
ref={ref}
className={cn(buttonVariants({ variant, size }), className)}
disabled={disabled || isLoading}
{...props}
>
{isLoading ? <Spinner className="mr-2 h-4 w-4" /> : null}
{children}
</button>
)
);
Button.displayName = 'Button';
export { Button, buttonVariants };
Feature 컴포넌트 작성 규칙
- ‘use client’ 지시문 필요 여부 판단
- 상태 관리 훅은 컴포넌트 최상위에서만 호출
- 로딩/에러/빈 상태 모두 처리
- 컴포넌트 당 JSX 50줄 초과 시 하위 컴포넌트로 분리
---
## 템플릿 3: 데이터 파이프라인
데이터 수집, 변환, 적재(ETL) 파이프라인을 위한 하네스다. Python 기반이며, 데이터 품질 검증과 멱등성에 초점을 둔다.
### CLAUDE.md
```markdown
# CLAUDE.md — 데이터 파이프라인
## 프로젝트 개요
[데이터 소스]에서 데이터를 수집하여 [데이터 웨어하우스]에 적재하는 ETL 파이프라인.
Python + [Airflow / Prefect / Dagster] 기반.
## 기술 스택
- Language: Python 3.12
- Orchestrator: [Airflow / Prefect / Dagster]
- Data Validation: Pydantic + Great Expectations
- DB: [BigQuery / Snowflake / PostgreSQL]
- Storage: [S3 / GCS]
- Test: pytest + pytest-mock
- Linter: ruff + mypy
## 디렉토리 구조
src/
├── extractors/ # 데이터 소스별 추출 로직
│ ├── base.py # BaseExtractor 추상 클래스
│ ├── api_extractor.py
│ ├── db_extractor.py
│ └── file_extractor.py
├── transformers/ # 데이터 변환 로직
│ ├── base.py # BaseTransformer 추상 클래스
│ ├── cleaning.py
│ ├── enrichment.py
│ └── aggregation.py
├── loaders/ # 데이터 적재 로직
│ ├── base.py # BaseLoader 추상 클래스
│ ├── bigquery_loader.py
│ └── file_loader.py
├── validators/ # 데이터 품질 검증
│ ├── schemas.py # Pydantic 모델
│ └── expectations.py # Great Expectations 스위트
├── pipelines/ # 파이프라인 정의 (DAG)
│ ├── daily_sync.py
│ └── hourly_metrics.py
├── models/ # 데이터 모델, 타입 정의
└── utils/ # 공용 유틸리티
├── config.py
├── logging.py
└── retry.py
## 의존성 규칙
extractors/ → models/, utils/, validators/
transformers/ → models/, utils/, validators/
loaders/ → models/, utils/, validators/
validators/ → models/
pipelines/ → extractors/, transformers/, loaders/, validators/
models/ → (의존 없음)
utils/ → (의존 없음)
역방향 의존 금지:
- extractors/에서 transformers/, loaders/ import 금지
- transformers/에서 extractors/, loaders/ import 금지
- models/에서 어떤 레이어도 import 금지
## 핵심 원칙
### 멱등성
- 모든 파이프라인은 같은 입력에 대해 같은 결과를 보장
- 적재 시 MERGE/UPSERT 사용 (INSERT만 금지)
- 재실행 시 중복 데이터가 생기지 않아야 함
### 데이터 검증
- 추출 직후: 스키마 검증 (Pydantic)
- 변환 직후: 비즈니스 규칙 검증 (Great Expectations)
- 적재 직후: row count 및 null 비율 확인
### 에러 처리
- 개별 레코드 실패가 전체 파이프라인을 중단시키지 않음
- 실패 레코드는 dead_letter_queue에 저장
- 임계값 초과 시 (전체의 5% 이상 실패) 파이프라인 중단
### 로깅
- 각 단계의 입력/출력 row count 기록
- 처리 시간 기록
- 에러 발생 시 원인 레코드 샘플 (최대 5건) 기록
- print() 금지 → structlog 사용
## 코딩 컨벤션
- Type hints 필수 (mypy strict mode)
- 함수명: snake_case
- 클래스명: PascalCase
- 상수: UPPER_SNAKE_CASE
- docstring: Google 스타일
- 최대 라인 길이: 120
## 테스트
- extractors/: mock 외부 소스 + 스키마 검증 테스트
- transformers/: 입력→출력 매핑 테스트 (순수 함수)
- loaders/: testcontainers 또는 mock DB
- validators/: 유효/무효 데이터 경계값 테스트
- 파이프라인: 통합 테스트 (소규모 샘플 데이터)
- 커버리지 목표: 라인 85% 이상
## 에이전트 팀
- data-architect: 파이프라인 설계, 스키마 설계, 데이터 모델링
- pipeline-dev: Extractor/Transformer/Loader 구현
- data-qa: 데이터 품질 검증, 테스트 작성
- infra-engineer: Airflow DAG, 스케줄링, 모니터링
데이터 검증 스킬
# .claude/skills/data-validation/skill.md
## 트리거
"데이터 검증 추가", "스키마 만들어줘", "데이터 품질 체크"
## 절차
1. 데이터 소스의 필드 목록과 타입 확인
2. Pydantic 모델 작성 (스키마 검증)
3. Great Expectations 스위트 작성 (비즈니스 규칙)
4. 파이프라인의 적절한 위치에 검증 삽입
5. 실패 시 처리 로직 구현 (dead letter queue)
## Pydantic 모델 템플릿
```python
from pydantic import BaseModel, Field, field_validator
from datetime import datetime
class SalesRecord(BaseModel):
transaction_id: str = Field(..., min_length=1, max_length=50)
amount: float = Field(..., gt=0, le=1_000_000)
currency: str = Field(..., pattern=r'^[A-Z]{3}$')
customer_id: str
timestamp: datetime
@field_validator('timestamp')
@classmethod
def timestamp_not_future(cls, v: datetime) -> datetime:
if v > datetime.now():
raise ValueError('미래 시점의 거래는 허용되지 않음')
return v
class Config:
str_strip_whitespace = True
Great Expectations 스위트 템플릿
def create_sales_expectations(context):
suite = context.add_expectation_suite("sales_validation")
suite.add_expectation(
expect_column_values_to_not_be_null("transaction_id")
)
suite.add_expectation(
expect_column_values_to_be_between("amount", min_value=0, max_value=1000000)
)
suite.add_expectation(
expect_column_values_to_be_in_set("currency", ["USD", "EUR", "KRW", "JPY"])
)
suite.add_expectation(
expect_column_pair_values_to_be_unique(["transaction_id", "timestamp"])
)
return suite
검증 삽입 위치
Extract → [스키마 검증] → Transform → [비즈니스 규칙 검증] → Load → [적재 후 확인]
---
## 템플릿 활용법
세 가지 템플릿은 각 도메인의 시작점이다. 활용할 때의 원칙:
- 복사 후 커스터마이징
- 템플릿을 그대로 쓰지 않는다
- 프로젝트의 기술 스택, 규모, 팀 구성에 맞게 수정한다
- 사용하지 않는 에이전트나 스킬은 제거한다
- 점진적 확장
- CLAUDE.md만 먼저 적용하고 효과를 확인한다
- 필요에 따라 에이전트 정의를 추가한다
- 스킬은 반복되는 작업 패턴이 보일 때 추가한다
- 팀에 맞게 진화
- 에이전트가 반복적으로 실수하는 영역에 규칙을 추가한다
- 사용하지 않는 규칙은 정리한다
- feature-list.json은 프로젝트 초기에 가장 유용하다
- 도메인을 혼합할 수 있다
- 풀스택 프로젝트: 백엔드 + 프론트엔드 템플릿 조합
- 데이터 기반 서비스: API + 데이터 파이프라인 조합
- 모노레포: 디렉토리별로 다른 CLAUDE.md 적용
하네스는 프레임워크가 아니라 패턴이다. 정해진 형태가 있는 것이 아니라, 프로젝트의 맥락에 맞게 구성하는 것이다. 이 템플릿들이 그 출발점이 되기를 바란다.