- Expanded CLAUDE.md with behavioral guidelines for LLM coding practices. - Introduced new documents for frontend code style, Nuxt conventions, and testing conventions. - Added detailed rules for email HTML structure and TailwindCSS styling strategy. - Included a comprehensive EDM email HTML implementation guide.
3.0 KiB
3.0 KiB
코드 스타일 & 네이밍 컨벤션
Nuxt 4 + TypeScript strict 환경 기준 최종 업데이트: 2026-04-07
디렉토리 구조
my-nuxt-app/
├─ app/
│ ├─ assets/
│ ├─ components/ # PascalCase.vue
│ │ └─ ui/ # shadcn-vue 컴포넌트
│ ├─ composables/ # useXxx.ts
│ ├─ layouts/ # kebab-case.vue
│ ├─ middleware/ # kebab-case.ts
│ ├─ pages/ # kebab-case.vue
│ ├─ plugins/ # kebab-case.ts
│ ├─ stores/ # useXxxStore.ts
│ ├─ utils/ # camelCase.ts
│ ├─ app.vue
│ ├─ app.config.ts # 테마/UI 등 공개 설정값
│ └─ error.vue
├─ server/
│ ├─ api/ # kebab-case.ts
│ ├─ middleware/
│ └─ utils/
├─ shared/ # 클라이언트/서버 공유 타입 및 유틸
├─ public/
├─ nuxt.config.ts
├─ tailwind.config.ts
└─ tsconfig.json
네이밍 컨벤션
파일명
| 파일 종류 | 규칙 | 예시 |
|---|---|---|
| 컴포넌트 | PascalCase.vue |
UserProfile.vue |
| 페이지 / 레이아웃 / 미들웨어 / 플러그인 | kebab-case |
user-profile.vue |
| 컴포저블 | useXxx.ts |
useUserProfile.ts |
| 유틸 함수 | camelCase.ts |
formatDate.ts |
| Pinia store | useXxxStore.ts |
useAuthStore.ts |
| API 라우트 | kebab-case.ts |
user-profile.ts |
| 테스트 파일 | *.spec.ts / *.test.ts |
UserProfile.spec.ts |
코드 내
| 대상 | 규칙 | 예시 |
|---|---|---|
| 변수 / 함수 | camelCase |
const userName, function fetchUser() |
| 컴포넌트명 | PascalCase |
UserProfile, AppHeader |
| 상수 | UPPER_SNAKE_CASE |
const MAX_RETRY_COUNT = 3 |
| 타입 / 인터페이스 | PascalCase |
interface UserProfile |
// DO
const MAX_PAGE_SIZE = 100
const DEFAULT_LOCALE = 'ko'
// DON'T
const maxPageSize = 100 // 금지: 상수에 camelCase
const defaultLocale = 'ko' // 금지
TypeScript 엄격 모드
any 타입 사용 금지
any는 타입 안전성을 무력화한다. unknown 또는 명시적 타입을 사용한다.
// DON'T
async function fetchUser(id: any): Promise<any> {
return await $fetch(`/api/users/${id}`)
}
// DO
async function fetchUser(id: string): Promise<User> {
return await $fetch<User>(`/api/users/${id}`)
}
// unknown 사용 시 타입 좁히기
function parseResponse(raw: unknown): User {
if (!isUser(raw)) throw new Error('유효하지 않은 응답입니다.')
return raw
}
Props 타입 명시
<script setup lang="ts">
// DO: interface로 분리 선언
interface Props {
title: string
count: number
variant?: 'primary' | 'secondary'
}
const props = withDefaults(defineProps<Props>(), {
variant: 'primary',
})
// DON'T: 타입 없는 defineProps
// const props = defineProps(['title', 'count'])
</script>