설정 없이 쓰는 Claude CLI vs 팀 표준을 레포에 고정한 Claude CLI.
코드 비교와 AI 컨텍스트 분석으로 차이를 확인하세요.
Claude CLI를 "그냥" 쓰면 각 개발자의 프롬프트 습관, 권한 승인 방식, 작업 순서가 모두 다릅니다. 결과 편차가 커지고, 보안 리스크가 쌓이며, 신규 온보딩에 매번 구두 설명이 필요합니다.
팀이 .claude/settings.json에서 deny한 행위는 개인이 global/local에서 allow해도 풀리지 않습니다.
실제 파일 단위로, 설정이 없을 때와 있을 때를 비교합니다.
# 매번 수동 판단 > Claude wants to run: cat .env.local > Allow? (y/n) # → 승인 피로 → y 습관화 > Claude wants to run: curl https://... > Allow? (y/n) # → 외부 요청도 무비판적 허용
{
"permissions": {
"deny": [
"Read(./.env*)",
"Read(./secrets/**)",
"Bash(curl *)", "Bash(wget *)"
],
"allow": [
"Bash(pnpm lint)",
"Bash(pnpm test *)",
"Bash(pnpm build)"
]
}
}# 개발자 A: "로그인 API 만들어줘" → pages/ 라우터, JS, axios 직접 호출 # 개발자 B: "TypeScript로 로그인 API" → app/ 라우터, TS, fetch 사용 # 개발자 C: "깔끔하게 해줘" → AI 임의 판단 # 결과: 같은 레포에 3가지 패턴 혼재
# CLAUDE.md ## 스택 - Next.js 16 (App Router + RSC) - TypeScript 5 strict - TanStack Query v5 (서버 상태) - Zustand (클라이언트 상태) - Axios wrapper: src/libs/http.ts ## 규칙 - app/ 라우터만 사용 (pages/ 금지) - 서버 컴포넌트 기본, 'use client' 최소화 - API 호출은 반드시 http.ts 래퍼 사용 → 누가 "로그인 API" 요청해도 동일한 결과
# CLAUDE.md (500줄+) ## 아키텍처 규칙 (100줄) ... ## 코딩 스타일 (80줄) ... ## 테스트 (120줄) ... ## 보안 (60줄) ... ## 배포 (80줄) ... # → 컨텍스트 윈도우 낭비 # → 유지보수 지옥
# CLAUDE.md (루트: ~40줄) ## 프로젝트 개요 Next.js 16 + TS5 + pnpm workspace ## 핵심 명령 - 빌드: pnpm build - 테스트: pnpm test - 린트: pnpm lint ## 상세 규칙 @.claude/rules/architecture.md @.claude/rules/coding-style.md @.claude/rules/testing.md @.claude/rules/security.md ## 금지사항 - .env 출력/커밋 금지 - 프로덕션 DB 직접 접근 금지
# CLAUDE.local.md (나만의 설정) ## 내 선호 - 설명은 한국어로 - 커밋 메시지도 한국어 ## 현재 작업 컨텍스트 - 작업 중: 결제 모듈 리팩토링 (#1234) - 주의: payment-gateway.ts 레거시 호환 유지 ## 실험 - Vitest property-based testing 시도 중
Claude는 세션마다 컨텍스트를 새로 구성합니다. CLAUDE.md는 "AI가 프로젝트를 이해하는 방식"에 직접적인 영향을 줍니다.
상위 CLAUDE.md는 세션 시작 시 전부 로드. 하위는 해당 파일 접근 시 온디맨드 로드. 더 구체적인 지침이 우선.
AI가 매번 config 파일들을 탐색하는 대신, 핵심 정보가 있어 토큰을 실제 작업에 집중.
빌드 명령, 상태관리 선택, API 래퍼 위치를 미리 알려주면 추론 오류가 줄고 출력 품질 향상.
1. 프로젝트 구조 탐색 시작 (토큰 소비)
2. pages/ vs app/ 어디? → 추론 시도
3. 상태관리가 뭐지? → useState로 일단 구현
4. API 호출은? → 기본 fetch 사용
5. 스타일은? → 임의의 CSS 방식
→ 프로젝트 컨벤션과 안 맞는 코드
1. app/(main)/profile/page.tsx 생성 (RSC)
2. TanStack Query로 서버 상태 페칭
3. http.ts 래퍼로 API 호출
4. shadcn/ui Card + Tailwind 4 스타일
5. NextAuth session 체크 포함
→ 팀 컨벤션에 100% 부합하는 코드
OMC를 팀 전원이 설치하면 동일한 스킬셋을 이미 갖게 됩니다. 프로젝트 레벨에는 "OMC에 없는 것 + 우리만의 강제 규칙"만 두는 것이 핵심입니다.
OMC 스킬 + 개인 스킬
개인의 스타일 · 자유도
→ 각자 원하는 대로
OMC와 겹치지 않는 스킬
우리 프로젝트만의 강제 규칙
→ 최소한 · 필수만
현재 작업 컨텍스트
개인 선호 오버라이드
→ 커밋 안 됨
OMC 스킬 중복: team-plan, team-exec 등은 전원이 글로벌에 이미 갖고 있으므로 프로젝트에 또 넣으면 충돌/혼란만 발생
개인 취향 강제: 언어 선호, 설명 스타일 같은 건 CLAUDE.local.md에서 각자 설정
범용 스킬: "코드 리뷰", "리팩토링" 같은 범용 작업은 OMC나 개인 스킬이 이미 커버
우리 프로젝트 고유 규칙: "app/ 라우터만", "http.ts 래퍼 필수" 같은 건 OMC가 모름 → CLAUDE.md에 명시
OMC에 없는 프로젝트 전용 스킬: 우리만의 릴리즈 플로우, DB 마이그레이션 절차 등
보안 정책: deny/allow 규칙은 반드시 프로젝트 레벨에 (글로벌보다 우선순위 높음)
프로젝트 루트/
├── CLAUDE.md # 팀 규칙 (자동 로드)
├── .claude/
│ ├── settings.json # deny/allow 정책
│ ├── rules/ # @import 모듈
│ │ ├── architecture.md
│ │ ├── coding-style.md
│ │ └── testing.md
│ └── skills/ # OMC에 "없는" 프로젝트 전용만
│ └── proj-db-migrate/
│ └── SKILL.md
│
├── CLAUDE.local.md # 개인 (gitignore)
└── .claude/settings.local.json # 개인 오버라이드 (gitignore)
~/.claude/ # 개인 글로벌
├── CLAUDE.md # 내 전체 프로젝트 공통 선호
├── settings.json
└── skills/ # OMC 스킬 + 내 커스텀 스킬
├── (OMC: plan, prd, exec, verify, fix ...)
└── (내 커스텀 스킬들)
# → 이건 각자의 스타일/자유도OMC가 주는 것: 멀티 에이전트 파이프라인(plan→prd→exec→verify→fix), 모델 라우팅(작업 난이도별 모델 자동 선택), 다양한 작업 모드 등 — Claude Code를 "개인 도구"에서 "체계적인 개발 워크플로"로 올려줍니다.
1. 팀 전원이 설치하면 동일한 스킬셋을 글로벌에 갖게 됩니다. 그 위에 각자 원하는 스킬을 추가하는 건 개인의 자유.
2. 프로젝트 레벨(.claude/)에는 OMC와 겹치지 않는 것 + 우리 프로젝트만의 강제 규칙만 최소로.
3. 이 구조면 OMC 업데이트가 프로젝트 레포에 영향 없고, 프로젝트 규칙과 개인 스킬이 깔끔하게 분리.
4. 강제가 아니라 권장이지만, 같은 도구를 쓰면 작업 방식 논의가 쉬워지는 장점도 있습니다.
우리 프로젝트 스택(Next.js 16 + TS5 + Tailwind 4 + shadcn + Zustand + TanStack Query + NextAuth) 기준 실제 세팅 파일입니다.
"TypeScript strict, var 금지" 같은 범용 규칙만 적으면, AI는 우리 프로젝트의 스택 선택을 모릅니다. "서버 상태는 TanStack Query, API는 http.ts 래퍼, 라우터는 App Router만" — 이런 정보가 있어야 AI가 매번 추론하지 않고 바로 팀 컨벤션에 맞는 코드를 생성합니다.
# CLAUDE.md ## 프로젝트 개요 SaaS 웹 애플리케이션. pnpm workspace 모노레포. ## 기술 스택 - Next.js 16 (App Router + React Server Components) - React 19, TypeScript 5 (strict mode) - Tailwind CSS 4 + shadcn/ui (new-york 스타일) - Zustand (클라이언트 상태) + TanStack React Query v5 (서버 상태) - Axios custom wrapper: src/libs/http.ts - NextAuth v4 (JWT strategy) - 패키지 매니저: pnpm ## 핵심 명령 - 빌드: pnpm build - 개발: pnpm dev - 린트: pnpm lint - 타입체크: pnpm typecheck - 테스트: pnpm test ## 폴더 구조 (주요) - src/app/ → App Router 페이지 & 레이아웃 (RSC 기본) - src/components/ → 재사용 컴포넌트 (shadcn 기반) - src/libs/ → 유틸리티 (http.ts, auth.ts 등) - src/hooks/ → 커스텀 훅 - src/stores/ → Zustand 스토어 - src/types/ → 공유 타입 정의 ## 규칙 - TypeScript strict / const 우선, var 금지 / any 금지 - 서버 컴포넌트 기본, 'use client' 최소화 - API 호출은 반드시 http.ts 래퍼 사용 (fetch 직접 사용 금지) ## 상세 규칙 (필요 시 로드) @.claude/rules/architecture.md @.claude/rules/coding-style.md @.claude/rules/state-management.md @.claude/rules/testing.md ## 금지 사항 - .env, .env.*, secrets 파일 내용 출력/커밋 금지 - console.log 커밋 금지 (디버깅 후 제거) - pages/ 디렉터리 사용 금지 (App Router만) - CSS-in-JS / CSS 모듈 금지 (Tailwind + shadcn만)
# 아키텍처 규칙
## 라우팅
- Next.js App Router만 사용 (pages/ 절대 금지)
- 페이지 컴포넌트는 React Server Component가 기본
- 클라이언트 로직 필요 시 별도 Client Component로 분리, 'use client' 선언
- 'use client'는 가능한 트리 하단(leaf)에서만 — 페이지 전체를 client로 만들지 않기
## API 레이어
- Route Handler: src/app/api/ 하위에 RESTful 경로로 구성
- 요청/응답 스키마는 Zod로 정의, 런타임 검증 필수
- API 호출(클라이언트→서버)은 반드시 src/libs/http.ts 래퍼 사용
- http.get(), http.post(), http.put(), http.delete()
- 인터셉터에서 토큰 자동 주입 / 에러 핸들링 처리됨
## 인증
- NextAuth v4, JWT strategy
- 서버 컴포넌트: getServerSession(authOptions)
- 클라이언트 컴포넌트: useSession()
- Route Handler: getServerSession(authOptions)
- 미들웨어(src/middleware.ts)에서 보호 경로 체크
## 컴포넌트 구조
- shadcn/ui 커스터마이징: src/components/ui/
- 비즈니스 컴포넌트: src/components/{feature}/
- 레이아웃: src/app/(그룹)/layout.tsx# 상태 관리 규칙
## 원칙: 서버 상태와 클라이언트 상태를 명확히 분리
### 서버 상태 = TanStack React Query v5
- API에서 받아오는 모든 데이터는 TanStack Query로 관리
- queryKey 컨벤션: [도메인, 식별자, 파라미터]
(예: ['users', userId, { page }])
- src/hooks/ 하위에 도메인별 커스텀 훅으로 래핑
- 예: useUser(id), useUsers(params), useCreateUser()
- useMutation 사용 후 invalidateQueries로 캐시 동기화
### 클라이언트 상태 = Zustand
- UI 상태, 폼 상태, 로컬 전용 상태만 Zustand 사용
- 스토어 위치: src/stores/{storeName}.ts
- 슬라이스 패턴 사용: 스토어가 커지면 슬라이스로 분리
### 사용하지 않는 것
- useState로 서버 데이터 관리 금지 → TanStack Query 사용
- Redux, Recoil, Jotai 등 다른 상태관리 라이브러리 금지
- Context API로 전역 상태 관리 금지 (테마/로케일 등 예외)# 코딩 스타일 규칙
## TypeScript
- strict mode 필수
- any 금지 → unknown + 타입 가드, 또는 구체 타입
- interface 우선, type alias는 유니온/유틸리티에 사용
- 공유 타입: src/types/{domain}.ts
## 네이밍
- 파일: kebab-case (user-profile.tsx)
- 컴포넌트: PascalCase (UserProfile)
- 함수/변수: camelCase
- 상수: UPPER_SNAKE_CASE
- 타입/인터페이스: PascalCase, I 접두사 금지
## 컴포넌트
- named export 기본 (page.tsx, layout.tsx, route.ts만 default export)
- Props 타입은 컴포넌트 바로 위에 interface로 정의
- 이벤트 핸들러: handle{Event}
## import 순서
1. React / Next.js
2. 외부 라이브러리
3. @/ 내부 모듈
4. 상대 경로 (./)
- 그룹 사이에 빈 줄
## 스타일
- Tailwind CSS 4 유틸리티 클래스만 사용
- cn() 유틸리티로 조건부 클래스 병합
- 인라인 style 금지, CSS 모듈 금지{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"permissions": {
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Read(./.env.local)",
"Read(./secrets/**)",
"Bash(curl *)",
"Bash(wget *)",
"Bash(ssh *)",
"Bash(rm -rf *)",
"Bash(npx *)",
"Bash(pnpm dlx *)"
],
"allow": [
"Bash(pnpm lint)",
"Bash(pnpm lint:fix)",
"Bash(pnpm typecheck)",
"Bash(pnpm test *)",
"Bash(pnpm build)",
"Bash(pnpm dev)",
"Bash(pnpm format)",
"Bash(git status *)",
"Bash(git diff *)",
"Bash(git log *)"
]
}
}# 테스트 규칙
## 도구
- Vitest + @testing-library/react + MSW
## 원칙
- 새 기능/버그 수정 시 관련 테스트 작성 필수
- 테스트 파일 위치: 대상 파일 옆에 {name}.test.ts(x)
## 완료 기준 (DOD)
- pnpm test 통과
- pnpm lint 통과
- pnpm typecheck 통과---
name: proj-db-migrate
description: Prisma 마이그레이션 생성/적용/시드 업데이트를 안전하게 수행
allowed-tools: Bash(pnpm prisma *),Bash(pnpm db:*),Read,Write
---
# DB Migration (프로젝트 전용)
OMC의 범용 스킬과 겹치지 않는, 우리 프로젝트 고유 워크플로.
## 절차
1. prisma/schema.prisma 변경사항 확인
2. pnpm prisma migrate dev --name {description} 실행
3. 생성된 마이그레이션 SQL 파일 검토
4. prisma/seed.ts 업데이트 필요 여부 확인
5. pnpm db:seed 실행 (필요 시)
6. pnpm typecheck 으로 Prisma Client 타입 정합성 확인
## 주의
- 프로덕션 DB에는 절대 직접 실행 안 함
- 마이그레이션 이름: kebab-case (add-user-avatar)# CLAUDE.local.md (개인 설정 — 커밋 안 됨) ## 내 선호 - 설명/주석은 한국어로 - 커밋 메시지는 conventional commits (한국어 body OK) ## 현재 작업 컨텍스트 - 진행 중: 결제 모듈 리팩토링 (#1234, #1256) - 관련 파일: src/app/api/payments/, src/hooks/use-payment.ts - 주의: payment-gateway.ts의 레거시 API v1 호환 유지 필요
| 파일 | 역할 | Git | 소유 |
|---|---|---|---|
| CLAUDE.md | 프로젝트 개요 + 스택 + 핵심 규칙 허브 | ✅ 커밋 | 팀 |
| .claude/settings.json | 보안 deny/allow 정책 | ✅ 커밋 | 팀 |
| .claude/rules/*.md | 상세 규칙 모듈 | ✅ 커밋 | 팀 |
| .claude/skills/proj-*/ | OMC에 없는 프로젝트 전용 스킬만 | ✅ 커밋 | 팀 |
| CLAUDE.local.md | 개인 선호 + 현재 작업 컨텍스트 | ❌ gitignore | 개인 |
| .claude/settings.local.json | 개인 권한 오버라이드 | ❌ gitignore | 개인 |
| ~/.claude/ (글로벌) | OMC 스킬 + 개인 스킬 + 개인 선호 | — | 개인 자유 |
"최소한으로 시작해서 점진적으로 확장"하는 단계별 계획입니다.
Day 1: CLAUDE.md + .claude/settings.json 두 파일 커밋이면 80% 완성.
OMC: 전원 설치 → 글로벌에 위치. 개인 스킬 추가는 각자 자유. 프로젝트에는 겹치지 않는 것만.
원칙: "팀 강제 규칙은 레포에, OMC/개인 스킬은 글로벌에, 개인 선호는 local에."