From d3f7b86f1bc8f73a68def561c5daac3c3a064bdc Mon Sep 17 00:00:00 2001 From: hyeonggil <> Date: Sat, 11 Apr 2026 20:00:58 +0900 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20=ED=94=84=EB=A1=9C=EC=A0=9D?= =?UTF-8?q?=ED=8A=B8=20=EC=A7=80=EC=B9=A8=20=EC=96=91=EC=8B=9D=20=EB=B0=8F?= =?UTF-8?q?=20=EC=84=A4=EC=B9=98=20=EC=8A=A4=ED=81=AC=EB=A6=BD=ED=8A=B8=20?= =?UTF-8?q?=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .cursorrules | 70 ++++++++++++++++++++++ README.md | 48 +++++++++++++++- scripts/init-project.sh | 96 +++++++++++++++++++++++++++++++ scripts/install.sh | 85 ++++++++++++++++----------- templates/CLAUDE.md.tpl | 9 +++ templates/project/architecture.md | 46 +++++++++++++++ templates/project/conventions.md | 44 ++++++++++++++ templates/project/overview.md | 39 +++++++++++++ 8 files changed, 402 insertions(+), 35 deletions(-) create mode 100644 .cursorrules create mode 100755 scripts/init-project.sh create mode 100644 templates/CLAUDE.md.tpl create mode 100644 templates/project/architecture.md create mode 100644 templates/project/conventions.md create mode 100644 templates/project/overview.md diff --git a/.cursorrules b/.cursorrules new file mode 100644 index 0000000..2b341b6 --- /dev/null +++ b/.cursorrules @@ -0,0 +1,70 @@ +# Nuxt 프로젝트 — Cursor 규칙 + +## 언어 + +- 사용자와의 대화·설명·커밋 메시지 본문은 **한국어**를 사용한다. + +## Git 커밋 메시지 (필수) + +- **제목은 한 줄**, [Conventional Commits](https://www.conventionalcommits.org/) + **이모지**를 함께 쓴다. +- 형식: `<이모지> : <한글 설명>` (이모지·타입·콜론 뒤 공백 한 칸) +- **설명(제목 본문)은 반드시 한글**로 작성한다. 영어 제목만 단독으로 쓰지 않는다. +- **명령형** 어조 (`추가`, `수정` — `추가됨`, `수정함` 지양). +- **첫 줄(제목)은 72자 미만**을 권장한다. +- **원자적 커밋**: 한 커밋에 단일 목적만 담는다. 관련 없는 변경은 분할한다. +- 커밋 생성 시 **Claude·AI 서명·Co-authored-by 등 메타 서명을 본문에 넣지 않는다.** + +### 커밋 생성 프로세스 (`/commit` 등 요청 시) + +1. **스테이지된 파일**이 있으면 그 파일만 대상으로 커밋한다. 없으면 사용자에게 스테이징 여부를 확인한다. +2. `git diff` 등으로 **논리적 변경 덩어리**를 분석한다. +3. 타입이 섞였거나 관심사가 다르면 **분할 커밋**을 제안한다. +4. 아래 **이모지 맵**과 타입에 맞춰 제목을 만든다. + +### 타입 (type) + +| type | 용도 | +|------|------| +| `feat` | 새 기능 | +| `fix` | 버그 수정 | +| `docs` | 문서 | +| `style` | 포맷팅·세미콜론 등 의미 없는 스타일 | +| `refactor` | 리팩터링 | +| `perf` | 성능 개선 | +| `test` | 테스트 | +| `chore` | 빌드·도구·잡무 | +| `ci` | CI | +| `build` | 빌드 시스템·번들러 | + +### 이모지 맵 (타입·맥락에 맞게 선택) + +✨ feat | 🐛 fix | 📝 docs | 💄 style | ♻️ refactor | ⚡ perf | ✅ test | 🔧 chore | 🚀 ci | 🚨 warnings | 🔒️ security | 🚚 move | 🏗️ architecture | ➕ add-dep | ➖ remove-dep | 🌱 seed | 🧑‍💻 dx | 🏷️ types | 👔 business | 🚸 ux | 🩹 minor-fix | 🥅 errors | 🔥 remove | 🎨 structure | 🚑️ hotfix | 🎉 init | 🔖 release | 🚧 wip | 💚 ci-fix | 📌 pin-deps | 👷 ci-build | 📈 analytics | ✏️ typos | ⏪️ revert | 📄 license | 💥 breaking | 🍱 assets | ♿️ accessibility | 💡 comments | 🗃️ db | 🔊 logs | 🔇 remove-logs | 🙈 gitignore | 📸 snapshots | ⚗️ experiment | 🚩 flags | 💫 animations | ⚰️ dead-code | 🦺 validation | ✈️ offline + +### 분할 제안 기준 + +- 서로 다른 **관심사**가 한 diff에 섞인 경우 +- **타입**이 혼합된 경우 (예: `feat` + `fix`) +- **파일 패턴**이 완전히 다른 영역(예: 앱 코드 vs 인프라만)인 경우 +- **변경량이 크고** 커밋 단위로 나눌 수 있는 경우 + +### 예시 + +- `✨ feat: 로그인 폼 유효성 검사 추가` +- `♻️ refactor: 사용자 API 호출 로직을 composable로 분리` +- `🐛 fix: 모바일에서 헤더가 겹치는 문제 수정` + +### 본문이 필요할 때 + +- 제목 아래 빈 줄 후 본문을 한글 bullet 또는 문단으로 적는다. + +## 코드·작업 방식 + +- 요청 범위 밖의 리팩터·포맷 일괄 변경·무관 파일 수정을 하지 않는다. +- 기존 코드의 네이밍, import 스타일, 타입·주석 수준에 맞춘다. +- 변경 이유가 드러나는 **작고 집중된 diff**를 선호한다. + +## Cursor 사용 시 + +- 파일을 수정하기 전에 관련 맥락(주변 코드·설정)을 읽고 일관되게 맞춘다. +- 사용자가 명시적으로 요청하지 않은 README·문서 파일은 새로 쓰거나 크게 늘리지 않는다. + diff --git a/README.md b/README.md index 41034bb..c15188b 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,15 @@ fe-common-rules/ │ ├── framework-rules.md # Vue/Nuxt/Tailwind/라이브러리 규칙 │ ├── commit-pr.md # 커밋 & PR 규칙 │ └── claude-workflow.md # Claude 작업 방식 지침 +├── templates/ +│ ├── CLAUDE.md.tpl # 프로젝트 루트 CLAUDE.md 템플릿 +│ └── project/ # 프로젝트 지침 양식 +│ ├── overview.md +│ ├── conventions.md +│ └── architecture.md ├── scripts/ -│ ├── install.sh # 프로젝트에 submodule로 설치 +│ ├── install.sh # 프로젝트에 submodule 설치 + 템플릿 복사 +│ ├── init-project.sh # .claude/project 양식만 다시 초기화/diff │ └── update.sh # 최신 공통 지침으로 업데이트 └── examples/ └── sample-nuxt-project/ # Nuxt4 + Vue3 + TS + Tailwind 샘플 @@ -92,6 +99,45 @@ git commit -m "chore: update fe-common-rules submodule" --- +## 📝 프로젝트 지침 양식 사용 + +`.claude/project/` 에 들어갈 지침은 공통 저장소의 `templates/project/` 에 양식으로 관리됩니다. +팀원은 `install.sh` 를 사용하면 submodule 설치와 동시에 이 양식을 자동으로 복사받아 작성을 +시작할 수 있습니다. + +### 신규 프로젝트 — install.sh 한 번으로 끝 + +```bash +bash .claude/common/scripts/install.sh git@github.com:/fe-common-rules.git +# → .claude/common 에 submodule 설치 +# → templates/project/*.md 를 .claude/project/ 로 복사 +# → templates/CLAUDE.md.tpl 을 루트 CLAUDE.md 로 복사 +``` + +### 이미 submodule 이 있는 프로젝트 — init-project.sh + +이미 공통 저장소를 submodule 로 연결해둔 프로젝트에서 `.claude/project/` 양식만 따로 +초기화하거나, 공통 저장소에 새 양식이 추가됐을 때 사용합니다. + +```bash +# 기본: 없는 파일만 복사 (기존 파일은 건너뜀) +bash .claude/common/scripts/init-project.sh + +# 기존 파일을 덮어쓰고 싶을 때 +bash .claude/common/scripts/init-project.sh --force + +# 차이만 확인하고 복사는 하지 않기 +bash .claude/common/scripts/init-project.sh --diff +``` + +### 양식을 추가/수정하려면 + +공통 저장소의 `templates/project/*.md` 를 수정하는 PR 을 올립니다. 머지 후 팀원들은 +`git submodule update --remote` 로 새 양식을 받은 뒤, 필요하면 +`init-project.sh --diff` 로 자신의 프로젝트 지침과 비교할 수 있습니다. + +--- + ## ✍️ 공통 지침 수정 프로세스 1. 이 저장소를 별도로 clone 합니다. diff --git a/scripts/init-project.sh b/scripts/init-project.sh new file mode 100755 index 0000000..4da89aa --- /dev/null +++ b/scripts/init-project.sh @@ -0,0 +1,96 @@ +#!/usr/bin/env bash +# +# fe-common-rules project template initializer +# 이미 .claude/common 이 설치된 프로젝트에서 templates/project/ 의 +# 양식을 .claude/project/ 에 복사합니다. +# +# 사용법: +# bash .claude/common/scripts/init-project.sh # 없는 파일만 복사 (기본) +# bash .claude/common/scripts/init-project.sh --force # 기존 파일을 덮어씀 +# bash .claude/common/scripts/init-project.sh --diff # 차이만 보여주고 복사는 안 함 +# +set -euo pipefail + +COMMON_PATH=".claude/common" +PROJECT_PATH=".claude/project" +TEMPLATE_DIR="$COMMON_PATH/templates/project" + +MODE="safe" # safe | force | diff +for arg in "$@"; do + case "$arg" in + --force) MODE="force" ;; + --diff) MODE="diff" ;; + -h|--help) + grep '^#' "$0" | sed 's/^# \{0,1\}//' + exit 0 + ;; + *) + echo "❌ 알 수 없는 옵션: $arg" >&2 + exit 1 + ;; + esac +done + +if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then + echo "❌ 현재 디렉토리는 Git 저장소가 아닙니다." >&2 + exit 1 +fi + +cd "$(git rev-parse --show-toplevel)" + +if [[ ! -d "$TEMPLATE_DIR" ]]; then + echo "❌ $TEMPLATE_DIR 가 없습니다. 먼저 submodule 을 설치/업데이트하세요:" >&2 + echo " git submodule update --init --recursive" >&2 + exit 1 +fi + +mkdir -p "$PROJECT_PATH" + +echo "📝 templates/project → $PROJECT_PATH (mode=$MODE)" +echo "" + +shopt -s nullglob +copied=0 +skipped=0 +diffed=0 +for f in "$TEMPLATE_DIR"/*.md; do + name="$(basename "$f")" + dest="$PROJECT_PATH/$name" + + case "$MODE" in + diff) + if [[ -f "$dest" ]]; then + if ! diff -q "$f" "$dest" >/dev/null 2>&1; then + echo "📄 diff: $dest" + diff -u "$dest" "$f" || true + echo "" + diffed=$((diffed + 1)) + fi + else + echo "➕ 새 양식: $dest (복사되지 않음. --force 로 복사하세요)" + diffed=$((diffed + 1)) + fi + ;; + force) + cp "$f" "$dest" + echo " ✅ $dest (덮어씀)" + copied=$((copied + 1)) + ;; + safe) + if [[ -f "$dest" ]]; then + echo " ⏭ $dest (이미 존재)" + skipped=$((skipped + 1)) + else + cp "$f" "$dest" + echo " ✅ $dest" + copied=$((copied + 1)) + fi + ;; + esac +done + +echo "" +case "$MODE" in + diff) echo "🔍 차이가 있는 파일: $diffed 개";; + *) echo "🎉 완료: 복사 $copied개 / 건너뜀 $skipped개";; +esac diff --git a/scripts/install.sh b/scripts/install.sh index aea32d1..08e74cd 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -2,10 +2,11 @@ # # fe-common-rules installer # 현재 Git 프로젝트의 .claude/common 경로에 fe-common-rules 저장소를 -# submodule 로 추가하고 루트 CLAUDE.md 템플릿을 생성합니다. +# submodule 로 추가하고, templates/ 에서 프로젝트 지침 양식과 +# CLAUDE.md 템플릿을 복사합니다. # # 사용법: -# bash scripts/install.sh [] [] +# bash scripts/install.sh [] # # 예: # bash scripts/install.sh git@github.com:our-team/fe-common-rules.git main @@ -15,6 +16,7 @@ set -euo pipefail REPO_URL="${1:-}" BRANCH="${2:-main}" TARGET_PATH=".claude/common" +PROJECT_PATH=".claude/project" if [[ -z "$REPO_URL" ]]; then echo "❌ 사용법: bash scripts/install.sh [branch]" >&2 @@ -28,9 +30,12 @@ if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then exit 1 fi -# 이미 submodule 이 존재하는지 확인 +# 루트로 이동 +cd "$(git rev-parse --show-toplevel)" + +# 1) Submodule 추가 if [[ -d "$TARGET_PATH" ]]; then - echo "⚠️ '$TARGET_PATH' 경로가 이미 존재합니다. 설치를 건너뜁니다." + echo "⚠️ '$TARGET_PATH' 경로가 이미 존재합니다. submodule 추가를 건너뜁니다." else echo "📦 fe-common-rules 를 submodule 로 추가합니다..." git submodule add -b "$BRANCH" "$REPO_URL" "$TARGET_PATH" @@ -38,12 +43,35 @@ else echo "✅ submodule 추가 완료: $TARGET_PATH" fi -# 프로젝트 지침 폴더 생성 -mkdir -p .claude/project +# 2) 프로젝트 지침 양식 복사 (templates/project/ → .claude/project/) +mkdir -p "$PROJECT_PATH" -# CLAUDE.md 템플릿 생성 (없을 때만) +TEMPLATE_DIR="$TARGET_PATH/templates/project" +if [[ -d "$TEMPLATE_DIR" ]]; then + echo "📝 프로젝트 지침 양식을 복사합니다..." + for f in "$TEMPLATE_DIR"/*.md; do + [[ -e "$f" ]] || continue + name="$(basename "$f")" + dest="$PROJECT_PATH/$name" + if [[ -f "$dest" ]]; then + echo " ⏭ $dest (이미 존재 - 건너뜀)" + else + cp "$f" "$dest" + echo " ✅ $dest" + fi + done +else + echo "⚠️ $TEMPLATE_DIR 를 찾지 못했습니다. 공통 저장소의 templates 가 오래됐을 수 있습니다." +fi + +# 3) 루트 CLAUDE.md 템플릿 복사 if [[ ! -f "CLAUDE.md" ]]; then - cat > CLAUDE.md <<'EOF' + TPL_FILE="$TARGET_PATH/templates/CLAUDE.md.tpl" + if [[ -f "$TPL_FILE" ]]; then + cp "$TPL_FILE" CLAUDE.md + echo "✅ CLAUDE.md 템플릿을 생성했습니다." + else + cat > CLAUDE.md <<'EOF' # <프로젝트 이름> ## 공통 지침 @@ -52,42 +80,31 @@ if [[ ! -f "CLAUDE.md" ]]; then ## 프로젝트 지침 @.claude/project/overview.md @.claude/project/conventions.md +@.claude/project/architecture.md EOF - echo "✅ CLAUDE.md 템플릿을 생성했습니다." + echo "✅ CLAUDE.md 템플릿을 생성했습니다. (fallback)" + fi else echo "ℹ️ 기존 CLAUDE.md 가 이미 존재합니다. 아래 블록을 수동으로 추가하세요:" echo "" echo " ## 공통 지침" echo " @.claude/common/CLAUDE.md" echo "" -fi - -# 프로젝트 지침 샘플 파일 -if [[ ! -f ".claude/project/overview.md" ]]; then - cat > .claude/project/overview.md <<'EOF' -# 프로젝트 개요 - -- 서비스명: -- 기술 스택: -- 주요 기능: -- 주의사항: -EOF -fi - -if [[ ! -f ".claude/project/conventions.md" ]]; then - cat > .claude/project/conventions.md <<'EOF' -# 프로젝트 전용 컨벤션 - -공통 지침 외에 이 프로젝트에서만 적용되는 규칙을 작성하세요. -EOF + echo " ## 프로젝트 지침" + echo " @.claude/project/overview.md" + echo " @.claude/project/conventions.md" + echo " @.claude/project/architecture.md" + echo "" fi echo "" echo "🎉 설치가 완료되었습니다." -echo " - 공통 지침: .claude/common/CLAUDE.md" -echo " - 프로젝트 지침: .claude/project/" +echo " - 공통 지침: $TARGET_PATH/CLAUDE.md" +echo " - 프로젝트 지침: $PROJECT_PATH/" echo " - 엔트리 파일: CLAUDE.md" echo "" -echo "변경 사항을 커밋해 주세요:" -echo " git add .gitmodules .claude CLAUDE.md" -echo " git commit -m 'chore: add fe-common-rules submodule'" +echo "다음 작업을 진행해 주세요:" +echo " 1) $PROJECT_PATH/*.md 내용을 프로젝트에 맞게 채우기" +echo " 2) 변경 사항을 커밋하기" +echo " git add .gitmodules .claude CLAUDE.md" +echo " git commit -m 'chore: add fe-common-rules submodule'" diff --git a/templates/CLAUDE.md.tpl b/templates/CLAUDE.md.tpl new file mode 100644 index 0000000..503948e --- /dev/null +++ b/templates/CLAUDE.md.tpl @@ -0,0 +1,9 @@ +# <프로젝트 이름> + +## 공통 지침 +@.claude/common/CLAUDE.md + +## 프로젝트 지침 +@.claude/project/overview.md +@.claude/project/conventions.md +@.claude/project/architecture.md diff --git a/templates/project/architecture.md b/templates/project/architecture.md new file mode 100644 index 0000000..42272bd --- /dev/null +++ b/templates/project/architecture.md @@ -0,0 +1,46 @@ +# 아키텍처 + +> 이 파일은 `fe-common-rules/templates/project/architecture.md` 에서 복사된 양식입니다. +> 프로젝트의 레이어 구조와 데이터 흐름을 간단히 설명해주세요. + +## 레이어 구조 + +<프로젝트의 레이어 구조를 그림 또는 텍스트로 그려주세요> + +``` +┌───────────────────────────────┐ +│ presentation │ ← pages / components +├───────────────────────────────┤ +│ logic │ ← composables / hooks / stores +├───────────────────────────────┤ +│ data access │ ← api wrapper / queries +├───────────────────────────────┤ +│ server │ ← 서버 라우트 / BFF +└───────────────────────────────┘ +``` + +## 의존 규칙 + +- 상위 → 하위 **단방향 의존**만 허용 +- 같은 레이어 간 순환 import 금지 +- <프로젝트 고유 규칙 추가> + +## 데이터 흐름 + +1. <이벤트 발생부터 응답까지의 흐름을 간단히> +2. ... +3. ... + +## 상태 관리 가이드 + +| 상태 종류 | 권장 위치 | +| -------------------- | ------------------------ | +| 컴포넌트 로컬 상태 | <예: ref / useState> | +| 페이지 단위 공유 상태| <예: provide/inject> | +| 앱 전역 상태 | <예: Pinia / Zustand> | +| 서버 데이터 | <예: useFetch / TanStack Query> | + +## 외부 의존성 + +- 반드시 알아야 할 외부 서비스나 내부 API 를 나열 +- 장애 발생 시 fallback 정책이 있다면 함께 기술 diff --git a/templates/project/conventions.md b/templates/project/conventions.md new file mode 100644 index 0000000..04cdf07 --- /dev/null +++ b/templates/project/conventions.md @@ -0,0 +1,44 @@ +# 프로젝트 전용 컨벤션 + +> 이 파일은 `fe-common-rules/templates/project/conventions.md` 에서 복사된 양식입니다. +> 공통 지침(`.claude/common/`) 외에 **이 프로젝트에서만** 적용되는 규칙을 작성하세요. +> 공통 지침과 충돌할 경우 이 문서가 우선합니다. + +## 디렉토리 규칙 + +- `components/` — <설명> +- `composables/` 또는 `hooks/` — <설명> +- `pages/` 또는 `app/` — <설명> +- `server/` 또는 `api/` — <설명> +- `types/` — <설명> + +## 컴포넌트 규칙 (공통 규칙 오버라이드) + +<공통 규칙과 달리 이 프로젝트에서만 적용할 제약을 적어주세요> + +- 예) 컴포넌트 파일 길이 제한: 150줄 (공통 200줄보다 엄격) +- 예) Props 개수 최대 7개, 초과 시 객체 props 로 묶기 + +## 스타일 + +- 색상/간격/타이포는 디자인 토큰만 사용하고 임의값 금지 +- 다크모드 prefix: `dark:` +- 기타 프로젝트 고유 규칙: <작성> + +## 네트워크 / 데이터 + +- API 호출 창구: <예: composables/api 의 wrapper 만 사용> +- 인증 토큰 저장 위치: <예: httpOnly 쿠키> +- 에러 핸들링 규칙: <작성> + +## 금지 사항 + +- <예: 직접 $fetch 사용 금지> +- <예: 전역 이벤트 버스 사용 금지> +- <예: any 타입 사용 금지> + +## 테스트 + +- 테스트 러너: +- 테스트 파일 위치: <소스 옆 / __tests__ 폴더> +- 최소 커버리지: <숫자> diff --git a/templates/project/overview.md b/templates/project/overview.md new file mode 100644 index 0000000..ec9cdfc --- /dev/null +++ b/templates/project/overview.md @@ -0,0 +1,39 @@ +# 프로젝트 개요 + +> 이 파일은 `fe-common-rules/templates/project/overview.md` 에서 복사된 양식입니다. +> 프로젝트 세팅 후 실제 내용으로 채워주세요. + +## 서비스 + +- **이름**: <프로젝트 이름> +- **설명**: <한 줄 설명> +- **배포 환경**: +- **저장소**: + +## 기술 스택 + +- **Framework**: <예: Nuxt 4 / Next 15 / ...> +- **UI**: <예: Vue 3