🎉 init: Nuxt 프로젝트를 위한 공통 지침 및 스크립트 추가
This commit is contained in:
62
.claude/rules/claude-workflow.md
Normal file
62
.claude/rules/claude-workflow.md
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
# Claude 작업 방식 지침
|
||||||
|
|
||||||
|
이 문서는 Claude가 팀 프로젝트에서 작업할 때 따라야 할 일반적인 원칙을 정의합니다.
|
||||||
|
|
||||||
|
## 기본 원칙
|
||||||
|
|
||||||
|
1. **기존 코드 존중**: 수정 전에 관련 파일과 주변 컨벤션을 먼저 파악합니다.
|
||||||
|
2. **최소 변경**: 요구사항을 충족하는 최소한의 변경만 수행합니다. 관련 없는 리팩토링은 별도 작업으로 분리합니다.
|
||||||
|
3. **가정 대신 질문**: 요구사항이 모호하면 추측하지 말고 사용자에게 확인합니다.
|
||||||
|
4. **근거 있는 수정**: 코드 변경의 이유를 설명할 수 있어야 합니다.
|
||||||
|
|
||||||
|
## 작업 순서
|
||||||
|
|
||||||
|
1. **탐색 (Explore)**
|
||||||
|
- 관련 파일을 먼저 읽고 프로젝트 구조를 파악합니다.
|
||||||
|
- 유사한 패턴이 이미 존재하는지 확인합니다.
|
||||||
|
|
||||||
|
2. **계획 (Plan)**
|
||||||
|
- 여러 파일을 수정하거나 복잡한 작업이면 할 일 목록을 만들어 공유합니다.
|
||||||
|
- 아키텍처에 영향을 주는 변경은 착수 전에 사용자 승인을 받습니다.
|
||||||
|
|
||||||
|
3. **구현 (Implement)**
|
||||||
|
- 한 번에 하나의 논리적 변경에 집중합니다.
|
||||||
|
- 공통 지침과 프로젝트 지침을 모두 준수합니다.
|
||||||
|
|
||||||
|
4. **검증 (Verify)**
|
||||||
|
- 린트 / 타입체크 / 빌드가 깨지지 않는지 확인합니다.
|
||||||
|
- 테스트가 있는 프로젝트라면 관련 테스트를 실행합니다.
|
||||||
|
- 수동 검증이 필요한 경우 확인 방법을 사용자에게 안내합니다.
|
||||||
|
|
||||||
|
## 해서는 안 되는 것
|
||||||
|
|
||||||
|
- **임의 기능 추가 금지**: 사용자가 요청하지 않은 기능을 추가하지 않습니다.
|
||||||
|
- **기존 코드 대량 리팩토링 금지**: 요청 범위를 벗어나는 변경은 하지 않습니다.
|
||||||
|
- **주석 / 문서 임의 삭제 금지**: 불필요해 보여도 삭제 전 사용자에게 확인합니다.
|
||||||
|
- **비밀정보 출력 금지**: 환경변수, 키, 토큰 등은 코드에 하드코딩하지 않습니다.
|
||||||
|
- **의존성 버전 임의 변경 금지**: 요청이 없다면 `package.json`의 버전을 변경하지 않습니다.
|
||||||
|
- **강제 푸시 / 히스토리 재작성 금지**: `push --force`, `reset --hard` 등은 사용자의 명시적 요청 없이 실행하지 않습니다.
|
||||||
|
|
||||||
|
## 커뮤니케이션
|
||||||
|
|
||||||
|
- 답변은 간결하게, 결론을 먼저 말합니다.
|
||||||
|
- 코드를 수정했다면 **어떤 파일을 어떻게 바꿨는지** 요약합니다.
|
||||||
|
- 불확실한 부분은 솔직하게 밝히고 대안을 제시합니다.
|
||||||
|
- 긴 설명보다 실제 결과물(코드/파일)을 우선합니다.
|
||||||
|
|
||||||
|
## 파일 작업 원칙
|
||||||
|
|
||||||
|
- 새 파일 생성보다 **기존 파일 수정**을 우선합니다.
|
||||||
|
- README, 문서는 사용자가 명시적으로 요청했을 때만 생성합니다.
|
||||||
|
- 파일을 읽지 않고 수정하지 않습니다.
|
||||||
|
- 대량 변경 시에는 diff를 확인할 수 있도록 단계별로 진행합니다.
|
||||||
|
|
||||||
|
## 질문이 필요한 상황
|
||||||
|
|
||||||
|
다음의 경우 반드시 사용자에게 확인을 요청합니다.
|
||||||
|
|
||||||
|
- 요구사항의 일부가 불명확할 때
|
||||||
|
- 여러 구현 방식이 있고 각각 장단점이 뚜렷할 때
|
||||||
|
- 공통 지침과 프로젝트 지침이 충돌할 때
|
||||||
|
- 파괴적 작업(파일 삭제, 데이터 마이그레이션, 스키마 변경 등)이 필요할 때
|
||||||
|
- 외부 서비스 호출이나 결제 관련 작업일 때
|
||||||
50
.claude/rules/coding-conventions.md
Normal file
50
.claude/rules/coding-conventions.md
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
# 코딩 컨벤션
|
||||||
|
|
||||||
|
## 기본 원칙
|
||||||
|
|
||||||
|
- **가독성 우선**: 영리한 코드보다 읽기 쉬운 코드를 선호합니다.
|
||||||
|
- **일관성 유지**: 기존 코드의 스타일을 먼저 관찰하고 그에 맞춥니다.
|
||||||
|
- **작은 단위**: 함수와 파일은 한 가지 책임만 지도록 작게 유지합니다.
|
||||||
|
|
||||||
|
## 포맷팅
|
||||||
|
|
||||||
|
- 들여쓰기: 스페이스 2칸 (탭 사용 금지)
|
||||||
|
- 문자열: 싱글 쿼터(`'`) 사용, JSX/템플릿 속성값은 더블 쿼터(`"`)
|
||||||
|
- 세미콜론: 생략하지 않고 항상 작성
|
||||||
|
- 줄 끝 공백 제거, 파일 끝 개행 1줄 유지
|
||||||
|
- 한 줄 최대 100자 (초과 시 줄바꿈)
|
||||||
|
- Prettier 설정 파일(`.prettierrc`)이 있는 경우 해당 설정을 우선합니다.
|
||||||
|
|
||||||
|
## 네이밍
|
||||||
|
|
||||||
|
- **변수/함수**: `camelCase` (예: `userProfile`, `fetchUserData`)
|
||||||
|
- **상수**: `UPPER_SNAKE_CASE` (예: `MAX_RETRY_COUNT`)
|
||||||
|
- **컴포넌트/클래스/타입**: `PascalCase` (예: `UserCard`, `OrderStatus`)
|
||||||
|
- **파일명**
|
||||||
|
- Vue 컴포넌트: `PascalCase.vue` (예: `UserCard.vue`)
|
||||||
|
- Composable: `use` 접두사 + `camelCase` (예: `useAuth.ts`)
|
||||||
|
- 일반 TS 모듈: `kebab-case.ts` (예: `format-date.ts`)
|
||||||
|
- **이벤트 핸들러**: `handle` 또는 `on` 접두사 (예: `handleClick`, `onSubmit`)
|
||||||
|
- **불리언**: `is`, `has`, `can`, `should` 접두사 (예: `isLoading`, `hasError`)
|
||||||
|
|
||||||
|
## 타입
|
||||||
|
|
||||||
|
- `any` 사용 금지. 불가피할 경우 주석으로 이유를 남기고 `unknown`을 먼저 고려합니다.
|
||||||
|
- 함수 시그니처에는 매개변수와 반환 타입을 명시합니다.
|
||||||
|
- 공개 API(타 모듈에서 import 되는 것)는 반드시 타입을 export 합니다.
|
||||||
|
- 유니온 타입은 `as const` 또는 별도 타입 alias로 관리합니다.
|
||||||
|
|
||||||
|
## 주석
|
||||||
|
|
||||||
|
- "무엇을" 보다 "왜"를 설명합니다.
|
||||||
|
- TODO/FIXME 주석에는 작성자와 날짜 또는 이슈 번호를 포함합니다.
|
||||||
|
- 공개 함수/컴포넌트에는 JSDoc 한 줄 설명을 권장합니다.
|
||||||
|
|
||||||
|
## import 순서
|
||||||
|
|
||||||
|
1. 외부 라이브러리 (예: `vue`, `nuxt`)
|
||||||
|
2. 내부 절대 경로 (예: `~/components/...`)
|
||||||
|
3. 상대 경로 (예: `./utils`)
|
||||||
|
4. 타입 only import는 각 그룹 내에서 별도 블록으로 분리
|
||||||
|
|
||||||
|
그룹 사이에는 빈 줄을 한 줄 둡니다.
|
||||||
83
.claude/rules/commit-pr.md
Normal file
83
.claude/rules/commit-pr.md
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
# 커밋 / PR 규칙
|
||||||
|
|
||||||
|
## 커밋 메시지
|
||||||
|
|
||||||
|
[Conventional Commits](https://www.conventionalcommits.org/)를 따릅니다.
|
||||||
|
|
||||||
|
```
|
||||||
|
<type>(<scope>): <subject>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
```
|
||||||
|
|
||||||
|
### type
|
||||||
|
|
||||||
|
- `feat`: 새로운 기능 추가
|
||||||
|
- `fix`: 버그 수정
|
||||||
|
- `refactor`: 기능 변화 없는 구조 개선
|
||||||
|
- `style`: 코드 포맷/세미콜론 등 스타일 변경
|
||||||
|
- `docs`: 문서 수정
|
||||||
|
- `test`: 테스트 추가/수정
|
||||||
|
- `chore`: 빌드, 설정, 패키지 업데이트 등
|
||||||
|
- `perf`: 성능 개선
|
||||||
|
- `ci`: CI 설정 변경
|
||||||
|
|
||||||
|
### 작성 규칙
|
||||||
|
|
||||||
|
- **subject**는 50자 이내, 명령형 현재 시제(예: `add`, `fix` — `added`, `fixes` 아님)
|
||||||
|
- subject 끝에 마침표를 찍지 않습니다.
|
||||||
|
- body는 "무엇을"보다 "왜"를 설명합니다. 한 줄 72자 이내로 줄바꿈합니다.
|
||||||
|
- 한 커밋에는 하나의 논리적 변경만 담습니다.
|
||||||
|
|
||||||
|
### 예시
|
||||||
|
|
||||||
|
```
|
||||||
|
feat(user): add profile image upload
|
||||||
|
|
||||||
|
프로필 이미지 업로드 요구사항에 따라 multipart 업로드 경로를 추가했습니다.
|
||||||
|
기존 텍스트 필드 업데이트 API는 변경하지 않았습니다.
|
||||||
|
|
||||||
|
Refs: #123
|
||||||
|
```
|
||||||
|
|
||||||
|
## Pull Request
|
||||||
|
|
||||||
|
### 제목
|
||||||
|
|
||||||
|
커밋 메시지와 동일한 컨벤션을 따릅니다. (`<type>(<scope>): <subject>`)
|
||||||
|
|
||||||
|
### 본문 템플릿
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## 변경 사항
|
||||||
|
- 무엇이 바뀌었는지 요약
|
||||||
|
|
||||||
|
## 배경 / 이유
|
||||||
|
- 왜 이 변경이 필요했는지
|
||||||
|
|
||||||
|
## 테스트
|
||||||
|
- 어떻게 검증했는지 (수동/자동 테스트 내용)
|
||||||
|
|
||||||
|
## 스크린샷 (UI 변경 시)
|
||||||
|
- Before / After
|
||||||
|
|
||||||
|
## 체크리스트
|
||||||
|
- [ ] 로컬에서 빌드/테스트 통과
|
||||||
|
- [ ] 린트/포맷 통과
|
||||||
|
- [ ] 공통 지침(gameservice-fe-agent) 준수
|
||||||
|
- [ ] 관련 문서 업데이트
|
||||||
|
```
|
||||||
|
|
||||||
|
### 리뷰 기준
|
||||||
|
|
||||||
|
- 최소 1명 이상의 승인 필요
|
||||||
|
- CI(Lint / Test / Build) 전부 통과 필요
|
||||||
|
- 머지 전략은 **Squash and merge**를 기본으로 합니다.
|
||||||
|
- 리뷰어는 변경 범위에 대해 질문이 남지 않도록 배경을 충분히 이해한 뒤 승인합니다.
|
||||||
|
|
||||||
|
### Draft PR
|
||||||
|
|
||||||
|
- 작업 중간 중간 피드백이 필요한 경우 Draft로 먼저 올리는 것을 권장합니다.
|
||||||
|
- Draft 상태에서는 CI 실패가 있어도 괜찮습니다.
|
||||||
47
.claude/rules/framework-rules.md
Normal file
47
.claude/rules/framework-rules.md
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# 프레임워크 / 라이브러리 사용 규칙
|
||||||
|
|
||||||
|
## Vue 3 / Nuxt
|
||||||
|
|
||||||
|
### 컴포넌트 작성
|
||||||
|
|
||||||
|
- **`<script setup lang="ts">` 사용**을 기본으로 합니다. Options API는 신규 코드에서 사용하지 않습니다.
|
||||||
|
- 컴포넌트는 단일 책임 원칙을 지키며, 200줄을 넘으면 분리를 검토합니다.
|
||||||
|
- Props는 `defineProps<T>()` 제네릭 형태로 타입을 명시합니다.
|
||||||
|
- Emits는 `defineEmits<{ ... }>()` 제네릭 형태로 선언합니다.
|
||||||
|
- `ref` vs `reactive`: 원시값과 단일 객체는 `ref`, 복잡한 상태 트리는 `reactive`를 고려합니다. 일관성을 위해 팀 내에서 가능한 `ref`를 우선합니다.
|
||||||
|
|
||||||
|
### 상태 관리
|
||||||
|
|
||||||
|
- 컴포넌트 내 로컬 상태: `ref` / `reactive`
|
||||||
|
- 여러 컴포넌트가 공유하는 상태: **Pinia** 사용
|
||||||
|
- 서버 상태: Nuxt `useFetch` / `useAsyncData` 사용, 직접 `fetch` 호출은 지양합니다.
|
||||||
|
|
||||||
|
### 라우팅
|
||||||
|
|
||||||
|
- Nuxt의 파일 기반 라우팅을 사용합니다. 수동 라우트 정의는 특수한 경우에만 허용됩니다.
|
||||||
|
- 동적 라우트 파라미터는 `[param].vue` 형식을 사용합니다.
|
||||||
|
|
||||||
|
### Composable
|
||||||
|
|
||||||
|
- 재사용 가능한 로직은 `composables/` 디렉토리의 `useXxx` 함수로 추출합니다.
|
||||||
|
- Composable은 부수효과를 최소화하고, 반환 객체에 상태와 메서드를 함께 묶어 반환합니다.
|
||||||
|
|
||||||
|
## TypeScript
|
||||||
|
|
||||||
|
- `strict: true`를 유지합니다.
|
||||||
|
- 공용 타입은 `types/` 또는 각 도메인의 `types.ts`에 모아둡니다.
|
||||||
|
- 외부 API 응답은 반드시 타입을 정의하여 사용합니다.
|
||||||
|
|
||||||
|
## Tailwind CSS
|
||||||
|
|
||||||
|
- **유틸리티 클래스 우선** 사용. 공통 패턴은 컴포넌트로 추출합니다.
|
||||||
|
- `@apply`는 꼭 필요한 경우에만 사용하고, 가능한 유틸리티를 직접 나열합니다.
|
||||||
|
- 임의값 클래스(`w-[123px]`)는 디자인 시스템에 등록되지 않은 값에만 제한적으로 사용합니다.
|
||||||
|
- 조건부 클래스는 `clsx` 또는 `cn` 유틸리티를 사용하여 가독성을 확보합니다.
|
||||||
|
- 클래스 순서는 Tailwind 공식 프리셋(`prettier-plugin-tailwindcss`)을 따릅니다.
|
||||||
|
|
||||||
|
## 외부 라이브러리 도입
|
||||||
|
|
||||||
|
- 새로운 라이브러리를 추가할 때는 **PR 설명에 도입 이유, 번들 영향, 대안 검토 내용**을 기록합니다.
|
||||||
|
- 동일 기능의 라이브러리를 중복 도입하지 않습니다.
|
||||||
|
- 유지보수가 중단된 패키지(6개월 이상 업데이트 없음)는 도입하지 않습니다.
|
||||||
96
.claude/scripts/init-project.sh
Executable file
96
.claude/scripts/init-project.sh
Executable file
@@ -0,0 +1,96 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# gameservice-fe-agent 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
|
||||||
135
.claude/scripts/install.sh
Executable file
135
.claude/scripts/install.sh
Executable file
@@ -0,0 +1,135 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# gameservice-fe-agent installer
|
||||||
|
# 현재 Git 프로젝트의 .claude/common 경로에 gameservice-fe-agent 저장소를
|
||||||
|
# submodule 로 추가하고, templates/ 에서 프로젝트 지침 양식과
|
||||||
|
# CLAUDE.md 템플릿을 복사합니다.
|
||||||
|
#
|
||||||
|
# 사용법:
|
||||||
|
# bash scripts/install.sh <repo-url> [<branch>]
|
||||||
|
#
|
||||||
|
# 예:
|
||||||
|
# bash scripts/install.sh https://git.sginfra.net/sgp-web-d/gameservice-fe-agent master
|
||||||
|
#
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
REPO_URL="${1:-}"
|
||||||
|
BRANCH="${2:-master}"
|
||||||
|
TARGET_PATH=".claude/common"
|
||||||
|
PROJECT_PATH=".claude/project"
|
||||||
|
|
||||||
|
if [[ -z "$REPO_URL" ]]; then
|
||||||
|
echo "❌ 사용법: bash scripts/install.sh <repo-url> [branch]" >&2
|
||||||
|
echo " 예: bash scripts/install.sh https://git.sginfra.net/sgp-web-d/gameservice-fe-agent master" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Git 프로젝트인지 확인
|
||||||
|
if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
||||||
|
echo "❌ 현재 디렉토리는 Git 저장소가 아닙니다. 먼저 'git init' 후 실행해주세요." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 루트로 이동
|
||||||
|
cd "$(git rev-parse --show-toplevel)"
|
||||||
|
|
||||||
|
# 1) Submodule 추가
|
||||||
|
if [[ -d "$TARGET_PATH" ]]; then
|
||||||
|
echo "⚠️ '$TARGET_PATH' 경로가 이미 존재합니다. submodule 추가를 건너뜁니다."
|
||||||
|
else
|
||||||
|
echo "📦 gameservice-fe-agent 를 submodule 로 추가합니다..."
|
||||||
|
git submodule add -b "$BRANCH" "$REPO_URL" "$TARGET_PATH"
|
||||||
|
git submodule update --init --recursive
|
||||||
|
echo "✅ submodule 추가 완료: $TARGET_PATH"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 2) 프로젝트 지침 양식 복사 (templates/project/ → .claude/project/)
|
||||||
|
mkdir -p "$PROJECT_PATH"
|
||||||
|
|
||||||
|
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
|
||||||
|
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'
|
||||||
|
# <프로젝트 이름>
|
||||||
|
|
||||||
|
## 공통 지침
|
||||||
|
@.claude/common/CLAUDE.md
|
||||||
|
|
||||||
|
## 프로젝트 지침
|
||||||
|
@.claude/project/overview.md
|
||||||
|
@.claude/project/conventions.md
|
||||||
|
@.claude/project/architecture.md
|
||||||
|
EOF
|
||||||
|
echo "✅ CLAUDE.md 템플릿을 생성했습니다. (fallback)"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "ℹ️ 기존 CLAUDE.md 가 이미 존재합니다. 아래 블록을 수동으로 추가하세요:"
|
||||||
|
echo ""
|
||||||
|
echo " ## 공통 지침"
|
||||||
|
echo " @.claude/common/CLAUDE.md"
|
||||||
|
echo ""
|
||||||
|
echo " ## 프로젝트 지침"
|
||||||
|
echo " @.claude/project/overview.md"
|
||||||
|
echo " @.claude/project/conventions.md"
|
||||||
|
echo " @.claude/project/architecture.md"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 4) 공통 skill 심볼릭 링크 (.claude/common/skills/* → .claude/skills/*)
|
||||||
|
SKILLS_SRC="$TARGET_PATH/skills"
|
||||||
|
SKILLS_DEST=".claude/skills"
|
||||||
|
|
||||||
|
if [[ -d "$SKILLS_SRC" ]]; then
|
||||||
|
echo "🔗 공통 skill 을 $SKILLS_DEST 로 링크합니다..."
|
||||||
|
mkdir -p "$SKILLS_DEST"
|
||||||
|
for dir in "$SKILLS_SRC"/*/; do
|
||||||
|
[[ -d "$dir" ]] || continue
|
||||||
|
name="$(basename "$dir")"
|
||||||
|
[[ "$name" == "README"* ]] && continue
|
||||||
|
link_src="../common/skills/$name"
|
||||||
|
link_dest="$SKILLS_DEST/$name"
|
||||||
|
if [[ -L "$link_dest" ]]; then
|
||||||
|
echo " ⏭ $link_dest (이미 링크됨)"
|
||||||
|
elif [[ -e "$link_dest" ]]; then
|
||||||
|
echo " ⚠️ $link_dest (실제 파일/폴더 존재 - 건너뜀. link-skills.sh --force 로 덮어쓰기)"
|
||||||
|
else
|
||||||
|
ln -s "$link_src" "$link_dest"
|
||||||
|
echo " ✅ $link_dest → $link_src"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "🎉 설치가 완료되었습니다."
|
||||||
|
echo " - 공통 지침: $TARGET_PATH/CLAUDE.md"
|
||||||
|
echo " - 프로젝트 지침: $PROJECT_PATH/"
|
||||||
|
echo " - 공통 skill: $SKILLS_DEST/ (submodule 에 심볼릭 링크)"
|
||||||
|
echo " - 엔트리 파일: CLAUDE.md"
|
||||||
|
echo ""
|
||||||
|
echo "다음 작업을 진행해 주세요:"
|
||||||
|
echo " 1) $PROJECT_PATH/*.md 내용을 프로젝트에 맞게 채우기"
|
||||||
|
echo " 2) 변경 사항을 커밋하기"
|
||||||
|
echo " git add .gitmodules .claude CLAUDE.md"
|
||||||
|
echo " git commit -m 'chore: add gameservice-fe-agent submodule'"
|
||||||
139
.claude/scripts/link-skills.sh
Executable file
139
.claude/scripts/link-skills.sh
Executable file
@@ -0,0 +1,139 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# gameservice-fe-agent skill linker
|
||||||
|
# 공통 저장소의 skills/* 를 프로젝트의 .claude/skills/* 로 심볼릭 링크합니다.
|
||||||
|
# 심볼릭 링크이므로 submodule 업데이트 시 skill 도 자동으로 최신 버전이 됩니다.
|
||||||
|
#
|
||||||
|
# 사용법:
|
||||||
|
# bash .claude/common/scripts/link-skills.sh # 모든 skill 링크
|
||||||
|
# bash .claude/common/scripts/link-skills.sh <skill-name> # 특정 skill 만
|
||||||
|
# bash .claude/common/scripts/link-skills.sh --dry-run # 실제 링크 없이 미리보기
|
||||||
|
# bash .claude/common/scripts/link-skills.sh --force # 기존 링크/폴더 덮어쓰기
|
||||||
|
# bash .claude/common/scripts/link-skills.sh --unlink # 공통 skill 링크 제거
|
||||||
|
#
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
COMMON_PATH=".claude/common"
|
||||||
|
SKILLS_SRC="$COMMON_PATH/skills"
|
||||||
|
SKILLS_DEST=".claude/skills"
|
||||||
|
|
||||||
|
MODE="safe" # safe | force | dry-run | unlink
|
||||||
|
TARGET=""
|
||||||
|
|
||||||
|
for arg in "$@"; do
|
||||||
|
case "$arg" in
|
||||||
|
--dry-run) MODE="dry-run" ;;
|
||||||
|
--force) MODE="force" ;;
|
||||||
|
--unlink) MODE="unlink" ;;
|
||||||
|
-h|--help)
|
||||||
|
grep '^#' "$0" | sed 's/^# \{0,1\}//'
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
-*)
|
||||||
|
echo "❌ 알 수 없는 옵션: $arg" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
TARGET="$arg"
|
||||||
|
;;
|
||||||
|
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 "$SKILLS_SRC" ]]; then
|
||||||
|
echo "❌ $SKILLS_SRC 가 없습니다. 먼저 submodule 을 설치/업데이트하세요:" >&2
|
||||||
|
echo " git submodule update --init --recursive" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$SKILLS_DEST"
|
||||||
|
|
||||||
|
# 링크 대상 결정
|
||||||
|
declare -a skills
|
||||||
|
if [[ -n "$TARGET" ]]; then
|
||||||
|
if [[ ! -d "$SKILLS_SRC/$TARGET" ]]; then
|
||||||
|
echo "❌ '$TARGET' skill 을 $SKILLS_SRC 에서 찾지 못했습니다." >&2
|
||||||
|
echo " 사용 가능한 skill:" >&2
|
||||||
|
ls -1 "$SKILLS_SRC" 2>/dev/null | grep -v '^README' | sed 's/^/ - /' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
skills=("$TARGET")
|
||||||
|
else
|
||||||
|
shopt -s nullglob
|
||||||
|
for dir in "$SKILLS_SRC"/*/; do
|
||||||
|
name="$(basename "$dir")"
|
||||||
|
# README 같은 파일은 이미 걸러지지만 추가 보호
|
||||||
|
[[ "$name" == "README"* ]] && continue
|
||||||
|
skills+=("$name")
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${#skills[@]} -eq 0 ]]; then
|
||||||
|
echo "ℹ️ 링크할 skill 이 없습니다."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "🔗 공통 skill 링크 (mode=$MODE)"
|
||||||
|
echo " source: $SKILLS_SRC"
|
||||||
|
echo " dest: $SKILLS_DEST"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
linked=0
|
||||||
|
skipped=0
|
||||||
|
removed=0
|
||||||
|
|
||||||
|
for name in "${skills[@]}"; do
|
||||||
|
src="../common/skills/$name" # 심볼릭 링크의 상대 경로 (.claude/skills 기준)
|
||||||
|
dest="$SKILLS_DEST/$name"
|
||||||
|
|
||||||
|
case "$MODE" in
|
||||||
|
unlink)
|
||||||
|
if [[ -L "$dest" ]]; then
|
||||||
|
rm "$dest"
|
||||||
|
echo " 🗑 $dest (링크 제거)"
|
||||||
|
removed=$((removed + 1))
|
||||||
|
else
|
||||||
|
echo " ⏭ $dest (링크 아님 - 건너뜀)"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
dry-run)
|
||||||
|
if [[ -e "$dest" || -L "$dest" ]]; then
|
||||||
|
echo " ⏭ $dest (이미 존재)"
|
||||||
|
else
|
||||||
|
echo " ➕ ln -s $src $dest"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
force)
|
||||||
|
rm -rf "$dest"
|
||||||
|
ln -s "$src" "$dest"
|
||||||
|
echo " ✅ $dest → $src (덮어씀)"
|
||||||
|
linked=$((linked + 1))
|
||||||
|
;;
|
||||||
|
safe)
|
||||||
|
if [[ -L "$dest" ]]; then
|
||||||
|
echo " ⏭ $dest (이미 링크됨)"
|
||||||
|
skipped=$((skipped + 1))
|
||||||
|
elif [[ -e "$dest" ]]; then
|
||||||
|
echo " ⚠️ $dest (실제 파일/폴더가 존재. --force 로 덮어쓰세요)"
|
||||||
|
skipped=$((skipped + 1))
|
||||||
|
else
|
||||||
|
ln -s "$src" "$dest"
|
||||||
|
echo " ✅ $dest → $src"
|
||||||
|
linked=$((linked + 1))
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
case "$MODE" in
|
||||||
|
unlink) echo "🎉 제거 완료: $removed 개 링크 제거됨";;
|
||||||
|
dry-run) echo "🔍 미리보기 완료 (실제 변경 없음)";;
|
||||||
|
*) echo "🎉 완료: 링크 $linked개 / 건너뜀 $skipped개";;
|
||||||
|
esac
|
||||||
36
.claude/scripts/update.sh
Executable file
36
.claude/scripts/update.sh
Executable file
@@ -0,0 +1,36 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# gameservice-fe-agent updater
|
||||||
|
# 현재 프로젝트에 설치된 .claude/common submodule 을 최신 버전으로 갱신합니다.
|
||||||
|
#
|
||||||
|
# 사용법:
|
||||||
|
# bash .claude/common/scripts/update.sh
|
||||||
|
#
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
TARGET_PATH=".claude/common"
|
||||||
|
|
||||||
|
if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
||||||
|
echo "❌ 현재 디렉토리는 Git 저장소가 아닙니다." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -d "$TARGET_PATH" ]]; then
|
||||||
|
echo "❌ '$TARGET_PATH' 가 존재하지 않습니다. 먼저 install.sh 로 설치하세요." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "🔄 gameservice-fe-agent 를 최신 버전으로 업데이트합니다..."
|
||||||
|
git submodule update --remote --merge "$TARGET_PATH"
|
||||||
|
|
||||||
|
# 변경 사항 확인
|
||||||
|
if git diff --quiet -- "$TARGET_PATH"; then
|
||||||
|
echo "✅ 이미 최신 상태입니다."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✅ 업데이트가 완료되었습니다. 변경된 submodule 포인터를 커밋하세요:"
|
||||||
|
echo ""
|
||||||
|
echo " git add $TARGET_PATH"
|
||||||
|
echo " git commit -m 'chore: update gameservice-fe-agent submodule'"
|
||||||
8
.claude/settings.local.json
Normal file
8
.claude/settings.local.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"permissions": {
|
||||||
|
"allow": [
|
||||||
|
"mcp__wiki__get_page_by_id",
|
||||||
|
"mcp__wiki__update_page"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
52
.claude/skills/README.md
Normal file
52
.claude/skills/README.md
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
# Common Skills
|
||||||
|
|
||||||
|
이 폴더는 팀 공통으로 사용할 Claude **skill** 들을 모아두는 공간입니다.
|
||||||
|
각 프로젝트는 submodule 로 이 저장소를 가져온 뒤, `.claude/common/skills/*` 를
|
||||||
|
`.claude/skills/*` 로 **심볼릭 링크**하여 사용합니다.
|
||||||
|
|
||||||
|
## Skill 구조
|
||||||
|
|
||||||
|
각 skill 은 하나의 폴더이며, 루트에 `SKILL.md` 를 가집니다.
|
||||||
|
|
||||||
|
```
|
||||||
|
skills/
|
||||||
|
└── <skill-name>/
|
||||||
|
├── SKILL.md # YAML frontmatter (name, description) + 지시문
|
||||||
|
└── (선택) 추가 자료 — 예시 파일, 템플릿, 스크립트 등
|
||||||
|
```
|
||||||
|
|
||||||
|
`SKILL.md` 예시:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
---
|
||||||
|
name: <skill-name>
|
||||||
|
description: <Claude 가 이 skill 을 언제 써야 하는지 한 줄로>
|
||||||
|
---
|
||||||
|
|
||||||
|
# <스킬 제목>
|
||||||
|
|
||||||
|
## 언제 사용하는가
|
||||||
|
...
|
||||||
|
|
||||||
|
## 작업 순서
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
## 프로젝트에 연결하기
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 공통 저장소의 skill 을 .claude/skills/ 로 전부 링크
|
||||||
|
bash .claude/common/scripts/link-skills.sh
|
||||||
|
|
||||||
|
# 차이 확인
|
||||||
|
bash .claude/common/scripts/link-skills.sh --dry-run
|
||||||
|
|
||||||
|
# 특정 skill 만 링크
|
||||||
|
bash .claude/common/scripts/link-skills.sh vue-component-review
|
||||||
|
```
|
||||||
|
|
||||||
|
## 새 skill 추가 프로세스
|
||||||
|
|
||||||
|
1. 이 저장소에서 `skills/<skill-name>/SKILL.md` 를 작성
|
||||||
|
2. PR 을 올리고 팀 리뷰
|
||||||
|
3. 머지 후 각 프로젝트에서 `git submodule update --remote` → `link-skills.sh` 실행
|
||||||
78
.claude/skills/conventional-commit/SKILL.md
Normal file
78
.claude/skills/conventional-commit/SKILL.md
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
---
|
||||||
|
name: conventional-commit
|
||||||
|
description: Git 변경사항을 팀의 Conventional Commits 규칙(gameservice-fe-agent/rules/commit-pr.md)에 맞춰 커밋 메시지로 작성할 때 사용합니다. 사용자가 "커밋 메시지 만들어줘", "commit", "커밋해줘" 등을 요청하면 트리거됩니다.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Conventional Commit 작성
|
||||||
|
|
||||||
|
이 skill 은 `git diff --staged` / `git status` 결과를 바탕으로 팀 규칙에 맞는 커밋
|
||||||
|
메시지를 작성합니다.
|
||||||
|
|
||||||
|
## 팀 규칙 요약
|
||||||
|
|
||||||
|
```
|
||||||
|
<type>(<scope>): <subject>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
```
|
||||||
|
|
||||||
|
### type
|
||||||
|
|
||||||
|
- `feat`: 새로운 기능
|
||||||
|
- `fix`: 버그 수정
|
||||||
|
- `refactor`: 기능 변화 없는 구조 개선
|
||||||
|
- `style`: 포맷/세미콜론 등 스타일
|
||||||
|
- `docs`: 문서
|
||||||
|
- `test`: 테스트 추가/수정
|
||||||
|
- `chore`: 빌드, 설정, 패키지
|
||||||
|
- `perf`: 성능 개선
|
||||||
|
- `ci`: CI 설정
|
||||||
|
|
||||||
|
### subject
|
||||||
|
|
||||||
|
- 50자 이내
|
||||||
|
- 명령형 현재 시제 (`add`, `fix` — `added`/`fixes` 아님)
|
||||||
|
- 끝에 마침표 금지
|
||||||
|
- 영어 소문자 시작
|
||||||
|
|
||||||
|
### body
|
||||||
|
|
||||||
|
- "무엇을"보다 **"왜"** 를 설명
|
||||||
|
- 한 줄 72자 이내
|
||||||
|
- 한 커밋 = 한 논리적 변경
|
||||||
|
|
||||||
|
## 작업 순서
|
||||||
|
|
||||||
|
1. **상태 확인**
|
||||||
|
- `git status` 로 staged/unstaged 파일 파악
|
||||||
|
- staged 변경이 없으면 사용자에게 먼저 `git add` 를 하라고 안내
|
||||||
|
2. **변경 분석**
|
||||||
|
- `git diff --staged` 로 실제 변경 내용 확인
|
||||||
|
- 변경을 한 문장으로 요약 (type + scope + subject 를 정하는 근거)
|
||||||
|
3. **메시지 작성**
|
||||||
|
- subject 는 50자 이내, 영문 명령형
|
||||||
|
- body 는 한국어로 "왜" 중심 설명 (한 줄 72자 제한)
|
||||||
|
- 이슈 번호가 있으면 `Refs: #123` footer 추가
|
||||||
|
4. **사용자 확인**
|
||||||
|
- 작성한 메시지를 보여주고 커밋 실행 여부를 물음
|
||||||
|
- 사용자가 명시적으로 "커밋해" 라고 할 때만 실제 `git commit` 실행
|
||||||
|
|
||||||
|
## 출력 예시
|
||||||
|
|
||||||
|
```
|
||||||
|
feat(user): add profile image upload
|
||||||
|
|
||||||
|
프로필 이미지 업로드 요구사항에 따라 multipart 업로드 경로를 추가했습니다.
|
||||||
|
기존 텍스트 필드 업데이트 API 는 변경하지 않았습니다.
|
||||||
|
|
||||||
|
Refs: #123
|
||||||
|
```
|
||||||
|
|
||||||
|
## 주의사항
|
||||||
|
|
||||||
|
- **논리적으로 섞인 변경**이 감지되면(예: feat + refactor 가 같이 있음) 커밋 분리를 제안한다.
|
||||||
|
- `package.json` / lock 파일이 함께 staged 되어 있으면 의존성 추가 사유를 body 에 명시한다.
|
||||||
|
- 사용자가 커밋 실행을 명시적으로 허락하기 전까지 `git commit` 명령을 직접 실행하지 않는다.
|
||||||
|
- Co-authored-by 등 footer 는 사용자가 요청할 때만 추가한다.
|
||||||
310
.claude/skills/edm-email-html/SKILL.md
Normal file
310
.claude/skills/edm-email-html/SKILL.md
Normal file
@@ -0,0 +1,310 @@
|
|||||||
|
---
|
||||||
|
name: edm-email-html
|
||||||
|
description: |
|
||||||
|
EDM(이메일 다이렉트 마케팅) HTML을 구현하는 전체 워크플로우 스킬.
|
||||||
|
Figma 디자인 → HTML table 마크업 → 아웃룩 호환 → 검수까지 단계별 가이드를 제공합니다.
|
||||||
|
|
||||||
|
다음 상황에서 반드시 사용하세요:
|
||||||
|
- "EDM 만들어줘", "이메일 템플릿 구현", "뉴스레터 HTML"
|
||||||
|
- "아웃룩에서 깨지는 이메일 수정", "이메일 HTML 마크업"
|
||||||
|
- Figma 디자인을 받고 이메일 HTML로 변환할 때
|
||||||
|
- "메일 발송용 HTML", "eDM 퍼블리싱", "HTML 이메일"
|
||||||
|
- 이메일 클라이언트 호환성 문제가 있을 때
|
||||||
|
---
|
||||||
|
|
||||||
|
# EDM HTML 구현 가이드
|
||||||
|
|
||||||
|
이메일 HTML은 일반 웹과 다른 세계입니다. 2000년대 테이블 코딩이 아직도 정답이며, Flexbox와 Grid는 쓸 수 없습니다. 이 스킬은 Figma 디자인에서 시작해 모든 이메일 클라이언트에서 깨지지 않는 HTML을 만드는 과정을 안내합니다.
|
||||||
|
|
||||||
|
## 워크플로우
|
||||||
|
|
||||||
|
```
|
||||||
|
1. Figma 디자인 파악 → 2. HTML 마크업 → 3. 아웃룩 호환 → 4. 검수
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 1: Figma 디자인 파악
|
||||||
|
|
||||||
|
### Figma MCP 사용 가능 시
|
||||||
|
Claude Code에 Figma MCP가 설정되어 있다면 Figma URL로 직접 디자인 데이터를 읽을 수 있습니다. MCP가 연결되어 있는지 먼저 확인하고, 가능하다면 자동 추출을 시도하세요.
|
||||||
|
|
||||||
|
추출 가능한 속성:
|
||||||
|
- 컬러 HEX값 (RGBA → HEX 자동 변환)
|
||||||
|
- 폰트 패밀리, 사이즈(px), 굵기, 줄간격
|
||||||
|
- 레이아웃 치수: 너비, 높이, padding, 섹션 간격
|
||||||
|
- 이미지 에셋 URL (CDN 업로드 필요)
|
||||||
|
- CTA 링크 (레이어 설명 필드에서 추출)
|
||||||
|
|
||||||
|
### Figma MCP 없이 진행 시
|
||||||
|
사용자에게 다음 정보를 요청하거나 스크린샷으로 파악하세요.
|
||||||
|
|
||||||
|
**필수 확인 항목:**
|
||||||
|
- 전체 이메일 너비 (권장: **600px**)
|
||||||
|
- 각 섹션 배경색, 텍스트 색상 (HEX)
|
||||||
|
- 폰트: 패밀리, 사이즈(px), 굵기, 줄간격
|
||||||
|
- 이미지: 가로×세로(px)
|
||||||
|
- 여백: 섹션 간 간격, 좌우 패딩
|
||||||
|
- CTA 버튼: 크기, 색상, 텍스트, 링크 URL
|
||||||
|
- 푸터: 회사 정보, 수신거부 링크
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 2: HTML table 마크업
|
||||||
|
|
||||||
|
### 절대 원칙
|
||||||
|
|
||||||
|
이메일 HTML에서 반드시 지켜야 하는 규칙들입니다. 이 규칙을 어기면 특정 클라이언트에서 레이아웃이 무너집니다:
|
||||||
|
|
||||||
|
| 규칙 | 이유 |
|
||||||
|
|------|------|
|
||||||
|
| `table`, `tr`, `td`만 레이아웃에 사용 | div는 Outlook 등에서 무시됨 |
|
||||||
|
| inline CSS 우선 | Gmail이 `<head>` style 태그를 제거함 |
|
||||||
|
| `width`/`height` 속성 필수 | CSS만으론 Outlook이 무시함 |
|
||||||
|
| `margin` 사용 금지 | 빈 `<tr>`행이나 `padding`으로 대체 |
|
||||||
|
| `padding` 개별 속성 사용 | 단축 속성(`padding: 10px 20px`)은 일부 클라이언트 미지원 |
|
||||||
|
| 모든 `<table>`에 `cellpadding="0" cellspacing="0" border="0"` | 브라우저 기본 스타일 초기화 |
|
||||||
|
|
||||||
|
### 기본 템플릿
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="ko">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="format-detection" content="telephone=no, date=no, address=no">
|
||||||
|
<title>이메일 제목</title>
|
||||||
|
<style type="text/css">
|
||||||
|
body { margin: 0; padding: 0; width: 100%; background-color: #f5f5f5; }
|
||||||
|
table { border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; }
|
||||||
|
img { display: block; border: 0; outline: none; text-decoration: none; }
|
||||||
|
|
||||||
|
/* 미디어쿼리는 여기서만 (Outlook은 무시하지만 Gmail/Apple Mail에서 적용) */
|
||||||
|
@media only screen and (max-width: 600px) {
|
||||||
|
.mobile-full { width: 100% !important; display: block !important; }
|
||||||
|
.mobile-padding { padding-left: 16px !important; padding-right: 16px !important; }
|
||||||
|
.mobile-center { text-align: center !important; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body style="margin: 0; padding: 0; background-color: #f5f5f5;">
|
||||||
|
|
||||||
|
<!-- 외부 래퍼: 배경색과 수평 중앙 정렬 -->
|
||||||
|
<table width="100%" cellpadding="0" cellspacing="0" border="0" bgcolor="#f5f5f5">
|
||||||
|
<tr>
|
||||||
|
<td align="center" style="padding-top: 20px; padding-bottom: 20px;">
|
||||||
|
|
||||||
|
<!-- 600px 컨테이너 -->
|
||||||
|
<table width="600" cellpadding="0" cellspacing="0" border="0"
|
||||||
|
style="width: 600px; max-width: 100%; background-color: #ffffff;">
|
||||||
|
|
||||||
|
<!-- 헤더 -->
|
||||||
|
<tr>
|
||||||
|
<td style="padding-top: 0;">
|
||||||
|
<!-- 로고 이미지 등 -->
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- 본문 -->
|
||||||
|
<tr>
|
||||||
|
<td style="padding-top: 30px; padding-bottom: 30px;
|
||||||
|
padding-left: 30px; padding-right: 30px;">
|
||||||
|
<!-- 메인 콘텐츠 -->
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- 푸터 -->
|
||||||
|
<tr>
|
||||||
|
<td bgcolor="#f5f5f5"
|
||||||
|
style="background-color: #f5f5f5;
|
||||||
|
padding-top: 20px; padding-bottom: 20px;
|
||||||
|
padding-left: 20px; padding-right: 20px;
|
||||||
|
text-align: center;">
|
||||||
|
<!-- 회사 정보 + 수신거부 링크 (필수) -->
|
||||||
|
<p style="font-family: Arial, sans-serif; font-size: 12px;
|
||||||
|
color: #999999; margin: 0; line-height: 1.5;">
|
||||||
|
회사명 | 주소<br>
|
||||||
|
<a href="[수신거부URL]"
|
||||||
|
style="color: #999999; text-decoration: underline;">
|
||||||
|
수신거부
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 안전한 폰트
|
||||||
|
|
||||||
|
웹폰트(`@font-face`, Google Fonts)는 대부분의 이메일 클라이언트에서 지원하지 않습니다. Pretendard, Noto Sans KR 같은 폰트를 Figma에서 사용했어도 이메일에서는 안전 폰트로 대체해야 합니다.
|
||||||
|
|
||||||
|
```css
|
||||||
|
/* 권장 스택 (한국어 이메일) */
|
||||||
|
font-family: -apple-system, Arial, 'Helvetica Neue', Helvetica, sans-serif;
|
||||||
|
|
||||||
|
/* Outlook 전용 (MSO 조건부 주석 내) */
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 3: 아웃룩 호환성
|
||||||
|
|
||||||
|
아웃룩 2007~2019는 Word 엔진으로 이메일을 렌더링해서 현대 CSS를 거의 무시합니다. MSO 조건부 주석으로 아웃룩과 그 외 클라이언트를 분리해서 처리하세요.
|
||||||
|
|
||||||
|
### MSO 조건부 주석
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!--[if mso]>
|
||||||
|
<!-- 아웃룩에서만 렌더링 -->
|
||||||
|
<![endif]-->
|
||||||
|
|
||||||
|
<!--[if !mso]><!-->
|
||||||
|
<!-- 아웃룩 제외 클라이언트에서 렌더링 -->
|
||||||
|
<!--<![endif]-->
|
||||||
|
```
|
||||||
|
|
||||||
|
### 아웃룩이 무시하는 주요 속성
|
||||||
|
|
||||||
|
| CSS 속성 | 아웃룩 동작 | 대체 방법 |
|
||||||
|
|----------|-----------|---------|
|
||||||
|
| `background-image` | 미지원 | `<img>` 태그 직접 사용 |
|
||||||
|
| `border-radius` | 무시 | VML 사용 또는 이미지 버튼 |
|
||||||
|
| `margin` | 무시 | `padding` 또는 빈 `<tr>` 행 |
|
||||||
|
| `box-shadow` | 무시 | 포기 또는 이미지로 대체 |
|
||||||
|
| `@media query` | 2007/2010 미지원 | 테이블 고정폭으로 데스크톱 설계 |
|
||||||
|
|
||||||
|
### VML 버튼 (반드시 사용)
|
||||||
|
|
||||||
|
아웃룩에서 CSS 버튼은 배경색 없는 텍스트 링크로 표시됩니다. CTA 버튼은 항상 VML을 포함하세요:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div style="text-align: center;
|
||||||
|
padding-top: 20px; padding-bottom: 20px;">
|
||||||
|
|
||||||
|
<!--[if mso]>
|
||||||
|
<v:roundrect xmlns:v="urn:schemas-microsoft-com:vml"
|
||||||
|
xmlns:w="urn:schemas-microsoft-com:office:word"
|
||||||
|
href="https://example.com"
|
||||||
|
style="height: 44px; v-text-anchor: middle; width: 200px;"
|
||||||
|
arcsize="5%"
|
||||||
|
stroke="f"
|
||||||
|
fillcolor="#FF6B6B">
|
||||||
|
<w:anchorlock/>
|
||||||
|
<center style="color: #ffffff; font-family: Arial, sans-serif;
|
||||||
|
font-size: 16px; font-weight: bold;">
|
||||||
|
지금 확인하기
|
||||||
|
</center>
|
||||||
|
</v:roundrect>
|
||||||
|
<![endif]-->
|
||||||
|
|
||||||
|
<!--[if !mso]><!-->
|
||||||
|
<a href="https://example.com"
|
||||||
|
style="background-color: #FF6B6B;
|
||||||
|
color: #ffffff;
|
||||||
|
display: inline-block;
|
||||||
|
padding-top: 12px; padding-bottom: 12px;
|
||||||
|
padding-left: 30px; padding-right: 30px;
|
||||||
|
text-decoration: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;">
|
||||||
|
지금 확인하기
|
||||||
|
</a>
|
||||||
|
<!--<![endif]-->
|
||||||
|
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 이미지 처리
|
||||||
|
|
||||||
|
이미지 차단 시에도 레이아웃이 깨지지 않도록 `alt` 텍스트와 배경색을 함께 지정하세요:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<td bgcolor="#FF6B6B" style="background-color: #FF6B6B;">
|
||||||
|
<img src="https://cdn.example.com/banner.jpg"
|
||||||
|
alt="7월 여름 세일 최대 50% 할인"
|
||||||
|
width="600"
|
||||||
|
height="300"
|
||||||
|
style="display: block; width: 100%; max-width: 600px;
|
||||||
|
height: auto; border: 0;">
|
||||||
|
</td>
|
||||||
|
```
|
||||||
|
|
||||||
|
이미지는 반드시 `https://` CDN 절대 경로를 사용하세요. 로컬 경로나 상대 경로는 이메일에서 작동하지 않습니다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 4: 검수 체크리스트
|
||||||
|
|
||||||
|
### 코드 구조 (필수)
|
||||||
|
- [ ] 모든 `<table>`에 `cellpadding="0" cellspacing="0" border="0"`
|
||||||
|
- [ ] 모든 `<img>`에 `width`, `height`, `alt` 속성
|
||||||
|
- [ ] `margin` 미사용 (padding 또는 빈 `<tr>` 행으로 대체)
|
||||||
|
- [ ] `padding` 단축 속성 제거 (개별 속성 사용)
|
||||||
|
- [ ] CTA 버튼에 VML 코드 포함
|
||||||
|
- [ ] 이미지 `src`가 HTTPS 절대 URL
|
||||||
|
|
||||||
|
### 콘텐츠 (필수)
|
||||||
|
- [ ] 푸터에 수신거부 링크 포함
|
||||||
|
- [ ] 모든 링크 href 유효성 확인
|
||||||
|
- [ ] 이미지 alt 텍스트 의미있게 작성 (장식용이면 `alt=""`)
|
||||||
|
|
||||||
|
### Figma 디자인 대비 검수
|
||||||
|
- [ ] 전체 너비 600px
|
||||||
|
- [ ] 색상 HEX값 일치
|
||||||
|
- [ ] 폰트 사이즈, 굵기 일치
|
||||||
|
- [ ] 버튼 크기, 색상 일치
|
||||||
|
- [ ] 섹션 간 여백 일치
|
||||||
|
|
||||||
|
### 테스트 도구
|
||||||
|
|
||||||
|
| 도구 | 용도 | 비용 |
|
||||||
|
|------|------|------|
|
||||||
|
| [Litmus](https://www.litmus.com) | 100+ 클라이언트 렌더링 미리보기 | 유료 |
|
||||||
|
| [Email on Acid](https://www.emailonacid.com) | 크로스 클라이언트 + 접근성 감사 | 유료 |
|
||||||
|
| [Mailtrap](https://mailtrap.io) | 개발 환경 샌드박스, 스팸 점수 | 무료 플랜 |
|
||||||
|
| [SpamTest.io](https://spamtest.io/) | 스팸 점수, SPF/DKIM/DMARC 확인 | 무료 |
|
||||||
|
|
||||||
|
**최소 테스트 클라이언트:** Gmail 웹, Outlook (Windows), Apple Mail, 모바일 Gmail
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2컬럼 레이아웃 예시
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!-- 데스크톱: 2열 | 모바일: 스택 -->
|
||||||
|
<table width="600" cellpadding="0" cellspacing="0" border="0"
|
||||||
|
style="width: 600px;">
|
||||||
|
<tr>
|
||||||
|
<td width="280" valign="top"
|
||||||
|
style="width: 280px; padding-right: 20px;"
|
||||||
|
class="mobile-full">
|
||||||
|
<!-- 왼쪽 -->
|
||||||
|
</td>
|
||||||
|
<td width="280" valign="top"
|
||||||
|
style="width: 280px; padding-left: 20px;"
|
||||||
|
class="mobile-full">
|
||||||
|
<!-- 오른쪽 -->
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 참고 자료
|
||||||
|
|
||||||
|
상세 내용은 references 폴더를 참조하세요:
|
||||||
|
- `references/html-patterns.md` — 헤더/푸터/버튼/이미지 완성 코드 패턴
|
||||||
|
- `references/verification-checklist.md` — 전체 검수 체크리스트 (시각적/기능/스팸)
|
||||||
24
.claude/skills/edm-email-html/assets/example_asset.txt
Normal file
24
.claude/skills/edm-email-html/assets/example_asset.txt
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# Example Asset File
|
||||||
|
|
||||||
|
This placeholder represents where asset files would be stored.
|
||||||
|
Replace with actual asset files (templates, images, fonts, etc.) or delete if not needed.
|
||||||
|
|
||||||
|
Asset files are NOT intended to be loaded into context, but rather used within
|
||||||
|
the output Claude produces.
|
||||||
|
|
||||||
|
Example asset files from other skills:
|
||||||
|
- Brand guidelines: logo.png, slides_template.pptx
|
||||||
|
- Frontend builder: hello-world/ directory with HTML/React boilerplate
|
||||||
|
- Typography: custom-font.ttf, font-family.woff2
|
||||||
|
- Data: sample_data.csv, test_dataset.json
|
||||||
|
|
||||||
|
## Common Asset Types
|
||||||
|
|
||||||
|
- Templates: .pptx, .docx, boilerplate directories
|
||||||
|
- Images: .png, .jpg, .svg, .gif
|
||||||
|
- Fonts: .ttf, .otf, .woff, .woff2
|
||||||
|
- Boilerplate code: Project directories, starter files
|
||||||
|
- Icons: .ico, .svg
|
||||||
|
- Data files: .csv, .json, .xml, .yaml
|
||||||
|
|
||||||
|
Note: This is a text placeholder. Actual assets can be any file type.
|
||||||
34
.claude/skills/edm-email-html/references/api_reference.md
Normal file
34
.claude/skills/edm-email-html/references/api_reference.md
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# Reference Documentation for Edm Email Html
|
||||||
|
|
||||||
|
This is a placeholder for detailed reference documentation.
|
||||||
|
Replace with actual reference content or delete if not needed.
|
||||||
|
|
||||||
|
Example real reference docs from other skills:
|
||||||
|
- product-management/references/communication.md - Comprehensive guide for status updates
|
||||||
|
- product-management/references/context_building.md - Deep-dive on gathering context
|
||||||
|
- bigquery/references/ - API references and query examples
|
||||||
|
|
||||||
|
## When Reference Docs Are Useful
|
||||||
|
|
||||||
|
Reference docs are ideal for:
|
||||||
|
- Comprehensive API documentation
|
||||||
|
- Detailed workflow guides
|
||||||
|
- Complex multi-step processes
|
||||||
|
- Information too lengthy for main SKILL.md
|
||||||
|
- Content that's only needed for specific use cases
|
||||||
|
|
||||||
|
## Structure Suggestions
|
||||||
|
|
||||||
|
### API Reference Example
|
||||||
|
- Overview
|
||||||
|
- Authentication
|
||||||
|
- Endpoints with examples
|
||||||
|
- Error codes
|
||||||
|
- Rate limits
|
||||||
|
|
||||||
|
### Workflow Guide Example
|
||||||
|
- Prerequisites
|
||||||
|
- Step-by-step instructions
|
||||||
|
- Common patterns
|
||||||
|
- Troubleshooting
|
||||||
|
- Best practices
|
||||||
327
.claude/skills/edm-email-html/references/html-patterns.md
Normal file
327
.claude/skills/edm-email-html/references/html-patterns.md
Normal file
@@ -0,0 +1,327 @@
|
|||||||
|
# EDM HTML 코드 패턴 모음
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1컬럼 레이아웃 (전체 템플릿)
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="ko">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="format-detection" content="telephone=no, date=no, address=no">
|
||||||
|
<title>이메일 제목</title>
|
||||||
|
<!--[if mso]>
|
||||||
|
<style type="text/css">
|
||||||
|
body, table, td, p, a { font-family: Arial, sans-serif !important; }
|
||||||
|
</style>
|
||||||
|
<![endif]-->
|
||||||
|
<style type="text/css">
|
||||||
|
body { margin: 0; padding: 0; width: 100%; background-color: #f5f5f5; }
|
||||||
|
table { border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; }
|
||||||
|
img { display: block; border: 0; outline: none; text-decoration: none; }
|
||||||
|
a { color: inherit; }
|
||||||
|
|
||||||
|
@media only screen and (max-width: 600px) {
|
||||||
|
.container { width: 100% !important; }
|
||||||
|
.mobile-full { width: 100% !important; display: block !important; }
|
||||||
|
.mobile-padding { padding-left: 16px !important; padding-right: 16px !important; }
|
||||||
|
.mobile-center { text-align: center !important; }
|
||||||
|
.mobile-img { width: 100% !important; height: auto !important; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body style="margin: 0; padding: 0; background-color: #f5f5f5;">
|
||||||
|
|
||||||
|
<table width="100%" cellpadding="0" cellspacing="0" border="0" bgcolor="#f5f5f5">
|
||||||
|
<tr>
|
||||||
|
<td align="center" style="padding-top: 20px; padding-bottom: 20px;">
|
||||||
|
|
||||||
|
<table width="600" cellpadding="0" cellspacing="0" border="0"
|
||||||
|
class="container"
|
||||||
|
style="width: 600px; max-width: 100%; background-color: #ffffff;">
|
||||||
|
|
||||||
|
<!-- 헤더 -->
|
||||||
|
<tr>
|
||||||
|
<td align="center"
|
||||||
|
style="padding-top: 24px; padding-bottom: 24px;
|
||||||
|
padding-left: 30px; padding-right: 30px;
|
||||||
|
border-bottom: 1px solid #e5e7eb;">
|
||||||
|
<img src="https://cdn.example.com/logo.png"
|
||||||
|
alt="회사 로고" width="120" height="40"
|
||||||
|
style="display: block; border: 0;">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- 히어로 이미지 -->
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 0; line-height: 0;">
|
||||||
|
<img src="https://cdn.example.com/hero.jpg"
|
||||||
|
alt="이벤트 배너"
|
||||||
|
width="600" height="280"
|
||||||
|
class="mobile-img"
|
||||||
|
style="display: block; width: 100%; max-width: 600px;
|
||||||
|
height: auto; border: 0;">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- 본문 -->
|
||||||
|
<tr>
|
||||||
|
<td style="padding-top: 32px; padding-bottom: 32px;
|
||||||
|
padding-left: 32px; padding-right: 32px;"
|
||||||
|
class="mobile-padding">
|
||||||
|
<h1 style="font-family: Arial, sans-serif;
|
||||||
|
font-size: 24px; font-weight: bold;
|
||||||
|
color: #111827; line-height: 1.3;
|
||||||
|
margin: 0 0 16px 0;">
|
||||||
|
이메일 제목이 여기 들어갑니다
|
||||||
|
</h1>
|
||||||
|
<p style="font-family: Arial, sans-serif;
|
||||||
|
font-size: 15px; color: #374151;
|
||||||
|
line-height: 1.7;
|
||||||
|
margin: 0 0 24px 0;">
|
||||||
|
본문 내용이 여기 들어갑니다. 가독성을 위해 line-height를
|
||||||
|
1.5 이상으로 설정하는 것이 좋습니다.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<!-- CTA 버튼 -->
|
||||||
|
<div style="text-align: center;">
|
||||||
|
<!--[if mso]>
|
||||||
|
<v:roundrect xmlns:v="urn:schemas-microsoft-com:vml"
|
||||||
|
xmlns:w="urn:schemas-microsoft-com:office:word"
|
||||||
|
href="https://example.com"
|
||||||
|
style="height: 48px; v-text-anchor: middle; width: 200px;"
|
||||||
|
arcsize="8%" stroke="f" fillcolor="#1a56db">
|
||||||
|
<w:anchorlock/>
|
||||||
|
<center style="color: #ffffff; font-family: Arial, sans-serif;
|
||||||
|
font-size: 16px; font-weight: bold;">
|
||||||
|
자세히 보기
|
||||||
|
</center>
|
||||||
|
</v:roundrect>
|
||||||
|
<![endif]-->
|
||||||
|
<!--[if !mso]><!-->
|
||||||
|
<a href="https://example.com"
|
||||||
|
style="background-color: #1a56db; color: #ffffff;
|
||||||
|
display: inline-block;
|
||||||
|
padding-top: 14px; padding-bottom: 14px;
|
||||||
|
padding-left: 32px; padding-right: 32px;
|
||||||
|
text-decoration: none; border-radius: 6px;
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
font-size: 16px; font-weight: bold;">
|
||||||
|
자세히 보기
|
||||||
|
</a>
|
||||||
|
<!--<![endif]-->
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- 푸터 -->
|
||||||
|
<tr>
|
||||||
|
<td bgcolor="#f9fafb"
|
||||||
|
style="background-color: #f9fafb;
|
||||||
|
border-top: 1px solid #e5e7eb;
|
||||||
|
padding-top: 24px; padding-bottom: 24px;
|
||||||
|
padding-left: 32px; padding-right: 32px;
|
||||||
|
text-align: center;">
|
||||||
|
<p style="font-family: Arial, sans-serif; font-size: 12px;
|
||||||
|
color: #9ca3af; line-height: 1.6; margin: 0 0 8px 0;">
|
||||||
|
<strong>회사명</strong> | 서울시 강남구 테헤란로 123
|
||||||
|
</p>
|
||||||
|
<p style="font-family: Arial, sans-serif; font-size: 12px;
|
||||||
|
color: #9ca3af; line-height: 1.6; margin: 0;">
|
||||||
|
<a href="https://example.com/unsubscribe"
|
||||||
|
style="color: #9ca3af; text-decoration: underline;">
|
||||||
|
수신거부
|
||||||
|
</a>
|
||||||
|
|
|
||||||
|
<a href="https://example.com/privacy"
|
||||||
|
style="color: #9ca3af; text-decoration: underline;">
|
||||||
|
개인정보처리방침
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2컬럼 이미지 + 텍스트
|
||||||
|
|
||||||
|
```html
|
||||||
|
<table width="600" cellpadding="0" cellspacing="0" border="0"
|
||||||
|
style="width: 600px;">
|
||||||
|
<tr>
|
||||||
|
<!-- 이미지 열 (40%) -->
|
||||||
|
<td width="220" valign="top"
|
||||||
|
style="width: 220px; padding-right: 0;"
|
||||||
|
class="mobile-full">
|
||||||
|
<img src="https://cdn.example.com/product.jpg"
|
||||||
|
alt="상품명" width="220" height="220"
|
||||||
|
class="mobile-img"
|
||||||
|
style="display: block; width: 100%; height: auto; border: 0;">
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<!-- 간격 -->
|
||||||
|
<td width="20" style="width: 20px; min-width: 20px;"> </td>
|
||||||
|
|
||||||
|
<!-- 텍스트 열 (60%) -->
|
||||||
|
<td width="360" valign="top"
|
||||||
|
style="width: 360px; padding-top: 8px;"
|
||||||
|
class="mobile-full mobile-padding">
|
||||||
|
<h2 style="font-family: Arial, sans-serif;
|
||||||
|
font-size: 18px; font-weight: bold;
|
||||||
|
color: #111827; margin: 0 0 8px 0;
|
||||||
|
line-height: 1.3;">
|
||||||
|
상품명
|
||||||
|
</h2>
|
||||||
|
<p style="font-family: Arial, sans-serif; font-size: 14px;
|
||||||
|
color: #6b7280; line-height: 1.6;
|
||||||
|
margin: 0 0 16px 0;">
|
||||||
|
상품 설명이 들어갑니다. 간결하게 핵심만 작성하세요.
|
||||||
|
</p>
|
||||||
|
<p style="font-family: Arial, sans-serif; font-size: 20px;
|
||||||
|
font-weight: bold; color: #ef4444;
|
||||||
|
margin: 0 0 16px 0;">
|
||||||
|
₩29,900
|
||||||
|
</p>
|
||||||
|
<a href="https://example.com/product"
|
||||||
|
style="background-color: #111827; color: #ffffff;
|
||||||
|
display: inline-block;
|
||||||
|
padding-top: 10px; padding-bottom: 10px;
|
||||||
|
padding-left: 20px; padding-right: 20px;
|
||||||
|
text-decoration: none; border-radius: 4px;
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
font-size: 13px; font-weight: bold;">
|
||||||
|
구매하기
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 헤더 배너 (이미지 기반)
|
||||||
|
|
||||||
|
이미지가 차단됐을 때도 배경색이 보이도록 `bgcolor` 속성을 함께 지정합니다:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<table width="600" cellpadding="0" cellspacing="0" border="0"
|
||||||
|
style="width: 600px;">
|
||||||
|
<tr>
|
||||||
|
<td bgcolor="#1a56db" style="background-color: #1a56db; line-height: 0; padding: 0;">
|
||||||
|
<img src="https://cdn.example.com/header-banner.jpg"
|
||||||
|
alt="여름 세일 최대 70% 할인"
|
||||||
|
width="600" height="240"
|
||||||
|
style="display: block; width: 100%; max-width: 600px;
|
||||||
|
height: auto; border: 0;">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 섹션 구분선
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!-- 섹션 간 여백 -->
|
||||||
|
<tr>
|
||||||
|
<td height="32" style="height: 32px; line-height: 32px;"> </td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- 수평선 -->
|
||||||
|
<tr>
|
||||||
|
<td style="padding-left: 32px; padding-right: 32px;">
|
||||||
|
<table width="100%" cellpadding="0" cellspacing="0" border="0">
|
||||||
|
<tr>
|
||||||
|
<td height="1" bgcolor="#e5e7eb"
|
||||||
|
style="height: 1px; background-color: #e5e7eb; line-height: 1px;">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 아웃라인(외곽선) 버튼
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!--[if mso]>
|
||||||
|
<v:roundrect xmlns:v="urn:schemas-microsoft-com:vml"
|
||||||
|
xmlns:w="urn:schemas-microsoft-com:office:word"
|
||||||
|
href="https://example.com"
|
||||||
|
style="height: 44px; v-text-anchor: middle; width: 180px;"
|
||||||
|
arcsize="5%"
|
||||||
|
stroke="t"
|
||||||
|
strokeweight="2px"
|
||||||
|
strokecolor="#1a56db"
|
||||||
|
fillcolor="#ffffff">
|
||||||
|
<w:anchorlock/>
|
||||||
|
<center style="color: #1a56db; font-family: Arial, sans-serif;
|
||||||
|
font-size: 14px; font-weight: bold;">
|
||||||
|
더 알아보기
|
||||||
|
</center>
|
||||||
|
</v:roundrect>
|
||||||
|
<![endif]-->
|
||||||
|
<!--[if !mso]><!-->
|
||||||
|
<a href="https://example.com"
|
||||||
|
style="background-color: #ffffff;
|
||||||
|
color: #1a56db;
|
||||||
|
display: inline-block;
|
||||||
|
padding-top: 12px; padding-bottom: 12px;
|
||||||
|
padding-left: 24px; padding-right: 24px;
|
||||||
|
text-decoration: none;
|
||||||
|
border: 2px solid #1a56db;
|
||||||
|
border-radius: 5px;
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;">
|
||||||
|
더 알아보기
|
||||||
|
</a>
|
||||||
|
<!--<![endif]-->
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 소셜 아이콘 행
|
||||||
|
|
||||||
|
```html
|
||||||
|
<table cellpadding="0" cellspacing="0" border="0">
|
||||||
|
<tr>
|
||||||
|
<td style="padding-right: 8px;">
|
||||||
|
<a href="https://instagram.com/example" style="text-decoration: none;">
|
||||||
|
<img src="https://cdn.example.com/icon-instagram.png"
|
||||||
|
alt="Instagram" width="32" height="32"
|
||||||
|
style="display: block; border: 0;">
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td style="padding-right: 8px;">
|
||||||
|
<a href="https://facebook.com/example" style="text-decoration: none;">
|
||||||
|
<img src="https://cdn.example.com/icon-facebook.png"
|
||||||
|
alt="Facebook" width="32" height="32"
|
||||||
|
style="display: block; border: 0;">
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://youtube.com/example" style="text-decoration: none;">
|
||||||
|
<img src="https://cdn.example.com/icon-youtube.png"
|
||||||
|
alt="YouTube" width="32" height="32"
|
||||||
|
style="display: block; border: 0;">
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
```
|
||||||
19
.claude/skills/edm-email-html/scripts/example.py
Executable file
19
.claude/skills/edm-email-html/scripts/example.py
Executable file
@@ -0,0 +1,19 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Example helper script for edm-email-html
|
||||||
|
|
||||||
|
This is a placeholder script that can be executed directly.
|
||||||
|
Replace with actual implementation or delete if not needed.
|
||||||
|
|
||||||
|
Example real scripts from other skills:
|
||||||
|
- pdf/scripts/fill_fillable_fields.py - Fills PDF form fields
|
||||||
|
- pdf/scripts/convert_pdf_to_images.py - Converts PDF pages to images
|
||||||
|
"""
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print("This is an example script for edm-email-html")
|
||||||
|
# TODO: Add actual script logic here
|
||||||
|
# This could be data processing, file conversion, API calls, etc.
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
87
.claude/skills/vue-component-review/SKILL.md
Normal file
87
.claude/skills/vue-component-review/SKILL.md
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
---
|
||||||
|
name: vue-component-review
|
||||||
|
description: Vue 3 / Nuxt 컴포넌트 파일을 팀 공통 지침(gameservice-fe-agent) 기준으로 리뷰할 때 사용합니다. 사용자가 "이 컴포넌트 리뷰해줘", "컨벤션 맞는지 봐줘", "컴포넌트 체크" 등을 요청하면 트리거됩니다.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Vue 컴포넌트 리뷰
|
||||||
|
|
||||||
|
이 skill 은 `.vue` 파일 하나 또는 여러 개에 대해 팀 공통 지침 기준으로 리뷰 체크리스트를
|
||||||
|
수행합니다. 프로젝트 전용 컨벤션(`.claude/project/conventions.md`)이 있으면 그 규칙을
|
||||||
|
**우선**합니다.
|
||||||
|
|
||||||
|
## 체크리스트
|
||||||
|
|
||||||
|
### 1. 파일 구조
|
||||||
|
|
||||||
|
- [ ] `<script setup lang="ts">` 를 사용하는가? (Options API 금지)
|
||||||
|
- [ ] 파일 길이가 팀/프로젝트 제한을 넘지 않는가? (공통 200줄, 프로젝트별 오버라이드 확인)
|
||||||
|
- [ ] 하나의 컴포넌트가 단일 책임을 지키는가?
|
||||||
|
|
||||||
|
### 2. Props / Emits
|
||||||
|
|
||||||
|
- [ ] `defineProps<T>()` 제네릭 형태로 타입을 명시했는가?
|
||||||
|
- [ ] `defineEmits<{ ... }>()` 제네릭 형태로 선언했는가?
|
||||||
|
- [ ] Props 개수가 많다면 객체 props 로 묶여 있는가?
|
||||||
|
- [ ] 불리언 prop 은 `is`/`has`/`can`/`should` 로 시작하는가?
|
||||||
|
|
||||||
|
### 3. 반응성
|
||||||
|
|
||||||
|
- [ ] `ref` 와 `reactive` 를 팀 규칙대로 사용하고 있는가?
|
||||||
|
- [ ] 불필요한 `reactive` 래핑이 없는가?
|
||||||
|
- [ ] 계산된 값은 `computed` 로 뽑아냈는가?
|
||||||
|
|
||||||
|
### 4. 스타일 (Tailwind)
|
||||||
|
|
||||||
|
- [ ] 임의값 클래스(`w-[123px]`) 남용이 없는가?
|
||||||
|
- [ ] 색상/간격 토큰을 사용하는가? (임의 색상 금지)
|
||||||
|
- [ ] 조건부 클래스는 `clsx` / `cn` 로 가독성 확보되었는가?
|
||||||
|
- [ ] 클래스 순서는 `prettier-plugin-tailwindcss` 규칙을 따르는가?
|
||||||
|
|
||||||
|
### 5. 네이밍
|
||||||
|
|
||||||
|
- [ ] 파일명: `PascalCase.vue`
|
||||||
|
- [ ] 이벤트 핸들러: `handle*` 또는 `on*` 접두사
|
||||||
|
- [ ] 상수: `UPPER_SNAKE_CASE`
|
||||||
|
|
||||||
|
### 6. 의존성 / 로직
|
||||||
|
|
||||||
|
- [ ] 비즈니스 로직이 컴포넌트에 직접 박혀있지 않고 composable 로 추출되었는가?
|
||||||
|
- [ ] `$fetch` / `fetch` 직접 호출이 없는가? (프로젝트 규칙에 따라 api wrapper 사용)
|
||||||
|
- [ ] `any` 타입 사용이 없는가?
|
||||||
|
|
||||||
|
## 작업 순서
|
||||||
|
|
||||||
|
1. 리뷰 대상 파일을 읽는다. 여러 파일이면 하나씩 순차 처리한다.
|
||||||
|
2. `.claude/project/conventions.md` 가 있으면 먼저 읽고, 공통 규칙과의 차이를 기억한다.
|
||||||
|
3. 위 체크리스트를 항목별로 점검하고, 위반 사항을 발견하면 **파일명:라인번호** 와
|
||||||
|
함께 문제 요약 + 수정 예시를 제시한다.
|
||||||
|
4. 단순 포맷 이슈는 "Prettier/ESLint 로 자동 해결 가능" 이라고 덧붙인다.
|
||||||
|
5. 마지막에 우선순위별 요약(Critical / Warning / Nit)을 출력한다.
|
||||||
|
|
||||||
|
## 출력 형식
|
||||||
|
|
||||||
|
```
|
||||||
|
## 리뷰 결과: <파일명>
|
||||||
|
|
||||||
|
### 🚨 Critical (반드시 수정)
|
||||||
|
- [라인 23] Props 타입이 `any` 로 선언됨. `defineProps<{ id: string }>()` 로 변경
|
||||||
|
- ...
|
||||||
|
|
||||||
|
### ⚠️ Warning (수정 권장)
|
||||||
|
- [라인 45] 파일 길이 210줄. 하위 컴포넌트 2개로 분리 검토
|
||||||
|
- ...
|
||||||
|
|
||||||
|
### 💡 Nit (선택)
|
||||||
|
- [라인 12] 클래스 순서가 Tailwind 프리셋과 다름
|
||||||
|
- ...
|
||||||
|
|
||||||
|
### ✅ 좋은 점
|
||||||
|
- 간단한 컴포넌트에 잘 맞는 단일 책임 구조
|
||||||
|
- ...
|
||||||
|
```
|
||||||
|
|
||||||
|
## 주의사항
|
||||||
|
|
||||||
|
- 사용자가 리팩토링을 **요청하지 않은 경우** 코드를 직접 수정하지 말고 리뷰만 수행한다.
|
||||||
|
- 프로젝트 지침과 공통 지침이 충돌하면 프로젝트 지침을 따르되, 차이를 사용자에게 알린다.
|
||||||
|
- 실제 코드 동작 변경(기능 수정)은 리뷰 범위가 아니다. 별도 작업으로 분리 제안한다.
|
||||||
9
.claude/templates/CLAUDE.md.tpl
Normal file
9
.claude/templates/CLAUDE.md.tpl
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# <프로젝트 이름>
|
||||||
|
|
||||||
|
## 공통 지침
|
||||||
|
@.claude/common/CLAUDE.md
|
||||||
|
|
||||||
|
## 프로젝트 지침
|
||||||
|
@.claude/project/overview.md
|
||||||
|
@.claude/project/conventions.md
|
||||||
|
@.claude/project/architecture.md
|
||||||
46
.claude/templates/project/architecture.md
Normal file
46
.claude/templates/project/architecture.md
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
# 아키텍처
|
||||||
|
|
||||||
|
> 이 파일은 `gameservice-fe-agent/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 정책이 있다면 함께 기술
|
||||||
44
.claude/templates/project/conventions.md
Normal file
44
.claude/templates/project/conventions.md
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
# 프로젝트 전용 컨벤션
|
||||||
|
|
||||||
|
> 이 파일은 `gameservice-fe-agent/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 타입 사용 금지>
|
||||||
|
|
||||||
|
## 테스트
|
||||||
|
|
||||||
|
- 테스트 러너: <Vitest / Jest 등>
|
||||||
|
- 테스트 파일 위치: <소스 옆 / __tests__ 폴더>
|
||||||
|
- 최소 커버리지: <숫자>
|
||||||
39
.claude/templates/project/overview.md
Normal file
39
.claude/templates/project/overview.md
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# 프로젝트 개요
|
||||||
|
|
||||||
|
> 이 파일은 `gameservice-fe-agent/templates/project/overview.md` 에서 복사된 양식입니다.
|
||||||
|
> 프로젝트 세팅 후 실제 내용으로 채워주세요.
|
||||||
|
|
||||||
|
## 서비스
|
||||||
|
|
||||||
|
- **이름**: <프로젝트 이름>
|
||||||
|
- **설명**: <한 줄 설명>
|
||||||
|
- **배포 환경**: <dev / staging / production URL 또는 환경>
|
||||||
|
- **저장소**: <git 주소>
|
||||||
|
|
||||||
|
## 기술 스택
|
||||||
|
|
||||||
|
- **Framework**: <예: Nuxt 4 / Next 15 / ...>
|
||||||
|
- **UI**: <예: Vue 3 <script setup> / React 19 / ...>
|
||||||
|
- **Language**: TypeScript (strict)
|
||||||
|
- **Styling**: <예: Tailwind CSS / styled-components / ...>
|
||||||
|
- **상태관리**: <예: Pinia / Zustand / Redux Toolkit / ...>
|
||||||
|
- **테스트**: <예: Vitest + Playwright / Jest + RTL / ...>
|
||||||
|
- **패키지매니저**: <pnpm / npm / yarn>
|
||||||
|
|
||||||
|
## 주요 기능
|
||||||
|
|
||||||
|
- <기능 1>
|
||||||
|
- <기능 2>
|
||||||
|
- <기능 3>
|
||||||
|
|
||||||
|
## 팀 / 오너
|
||||||
|
|
||||||
|
- 오너: <팀 또는 담당자>
|
||||||
|
- 문의 채널: <Slack 채널 / 이메일>
|
||||||
|
- 온콜/긴급 연락: <필요 시>
|
||||||
|
|
||||||
|
## 참고 문서
|
||||||
|
|
||||||
|
- 기획 문서: <링크>
|
||||||
|
- 디자인 시스템: <링크>
|
||||||
|
- API 스펙: <링크>
|
||||||
70
.cursorrules
Normal file
70
.cursorrules
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
# Nuxt 프로젝트 — Cursor 규칙
|
||||||
|
|
||||||
|
## 언어
|
||||||
|
|
||||||
|
- 사용자와의 대화·설명·커밋 메시지 본문은 **한국어**를 사용한다.
|
||||||
|
|
||||||
|
## Git 커밋 메시지 (필수)
|
||||||
|
|
||||||
|
- **제목은 한 줄**, [Conventional Commits](https://www.conventionalcommits.org/) + **이모지**를 함께 쓴다.
|
||||||
|
- 형식: `<이모지> <type>: <한글 설명>` (이모지·타입·콜론 뒤 공백 한 칸)
|
||||||
|
- **설명(제목 본문)은 반드시 한글**로 작성한다. 영어 제목만 단독으로 쓰지 않는다.
|
||||||
|
- **명령형** 어조 (`추가`, `수정` — `추가됨`, `수정함` 지양).
|
||||||
|
- **첫 줄(제목)은 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·문서 파일은 새로 쓰거나 크게 늘리지 않는다.
|
||||||
|
|
||||||
8
.env.secret
Normal file
8
.env.secret
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
GITLAB_ACCESS_TOKEN='glpat-i5ieRfgoyoX8Xgesitxo'
|
||||||
|
|
||||||
|
JIRA_ACCESS_TOKEN='NTQyNzA1NTExNDE5OhaoBIzIf77H3l/QMb1FvqNV2KaG'
|
||||||
|
|
||||||
|
WIKI_ACCESS_TOKEN='MTc4NzA5NDk3NjQzOvasDn2DxP6nPWj4rWVZx6i4r4CU'
|
||||||
|
WIKI_DAILY_WORK_LOG_URL='https://wiki.smilegate.net/pages/viewpage.action?pageId=684252757'
|
||||||
|
|
||||||
|
FIGMA_ACCESS_TOKEN='figd_FFh7QQz9yJzf2-X-QIoJg2lhLLd_8vCYuu-sVsT6'
|
||||||
1
.git copy/COMMIT_EDITMSG
Normal file
1
.git copy/COMMIT_EDITMSG
Normal file
@@ -0,0 +1 @@
|
|||||||
|
🔧 chore: pre-commit 훅 추가하여 .claude/common 변경 방지
|
||||||
6
.git copy/FETCH_HEAD
Normal file
6
.git copy/FETCH_HEAD
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
518884e472c00404a4e94112d3103f3b8401d78b not-for-merge branch 'dev' of https://git.sginfra.net/sgp-web-d/gameservice-fe-agent
|
||||||
|
8260e959df8725ccf396fc30004fdb79cc7178f4 not-for-merge branch 'fe-agent_20260407_anto_validate' of https://git.sginfra.net/sgp-web-d/gameservice-fe-agent
|
||||||
|
3487fa20c1cc0520b8716cc89dec097a85acbb4b not-for-merge branch 'feature/mr' of https://git.sginfra.net/sgp-web-d/gameservice-fe-agent
|
||||||
|
2f4532815e800742b8ebfaf3d7fdf8a4887c3db1 not-for-merge branch 'main' of https://git.sginfra.net/sgp-web-d/gameservice-fe-agent
|
||||||
|
fb31c8d7e52e7992a05ac2a0163b1a78f04c656b not-for-merge branch 'master' of https://git.sginfra.net/sgp-web-d/gameservice-fe-agent
|
||||||
|
d4bf89ec028715943f4cc66e1a2ee7f56f555eea not-for-merge branch 'sandbox' of https://git.sginfra.net/sgp-web-d/gameservice-fe-agent
|
||||||
1
.git copy/HEAD
Normal file
1
.git copy/HEAD
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ref: refs/heads/feature/gil-claude
|
||||||
1
.git copy/ORIG_HEAD
Normal file
1
.git copy/ORIG_HEAD
Normal file
@@ -0,0 +1 @@
|
|||||||
|
fb31c8d7e52e7992a05ac2a0163b1a78f04c656b
|
||||||
29
.git copy/config
Normal file
29
.git copy/config
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
[core]
|
||||||
|
repositoryformatversion = 0
|
||||||
|
filemode = true
|
||||||
|
bare = false
|
||||||
|
logallrefupdates = true
|
||||||
|
ignorecase = true
|
||||||
|
precomposeunicode = true
|
||||||
|
[remote "origin"]
|
||||||
|
url = https://git.sginfra.net/sgp-web-d/gameservice-fe-agent.git
|
||||||
|
fetch = +refs/heads/*:refs/remotes/origin/*
|
||||||
|
[branch "main"]
|
||||||
|
remote = origin
|
||||||
|
merge = refs/heads/main
|
||||||
|
vscode-merge-base = origin/main
|
||||||
|
vscode-merge-base = origin/main
|
||||||
|
[branch "feature/mr"]
|
||||||
|
vscode-merge-base = origin/main
|
||||||
|
remote = origin
|
||||||
|
merge = refs/heads/feature/mr
|
||||||
|
[branch "dev"]
|
||||||
|
remote = origin
|
||||||
|
merge = refs/heads/dev
|
||||||
|
vscode-merge-base = origin/dev
|
||||||
|
[branch "master"]
|
||||||
|
vscode-merge-base = origin/main
|
||||||
|
remote = origin
|
||||||
|
merge = refs/heads/master
|
||||||
|
[branch "feature/gil-claude"]
|
||||||
|
vscode-merge-base = origin/master
|
||||||
Binary file not shown.
@@ -0,0 +1 @@
|
|||||||
|
{"version":4,"git_revision":1}
|
||||||
Binary file not shown.
1
.git copy/description
Normal file
1
.git copy/description
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Unnamed repository; edit this file 'description' to name the repository.
|
||||||
14
.git copy/gk/config
Normal file
14
.git copy/gk/config
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
[branch "main"]
|
||||||
|
gk-last-accessed = 2026-03-19T05:28:40.093Z
|
||||||
|
[branch "feature/mr"]
|
||||||
|
gk-last-accessed = 2026-04-07T06:24:39.691Z
|
||||||
|
gk-last-modified = 2026-04-07T06:24:49.079Z
|
||||||
|
[branch "dev"]
|
||||||
|
gk-last-accessed = 2026-04-10T07:12:51.509Z
|
||||||
|
gk-last-modified = 2026-04-07T09:17:02.914Z
|
||||||
|
[branch "master"]
|
||||||
|
gk-last-accessed = 2026-04-13T05:24:28.704Z
|
||||||
|
gk-last-modified = 2026-04-13T05:24:28.704Z
|
||||||
|
[branch "feature/gil-claude"]
|
||||||
|
gk-last-accessed = 2026-04-17T03:15:23.500Z
|
||||||
|
gk-last-modified = 2026-04-17T03:15:23.500Z
|
||||||
15
.git copy/hooks/applypatch-msg.sample
Executable file
15
.git copy/hooks/applypatch-msg.sample
Executable file
@@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# An example hook script to check the commit log message taken by
|
||||||
|
# applypatch from an e-mail message.
|
||||||
|
#
|
||||||
|
# The hook should exit with non-zero status after issuing an
|
||||||
|
# appropriate message if it wants to stop the commit. The hook is
|
||||||
|
# allowed to edit the commit message file.
|
||||||
|
#
|
||||||
|
# To enable this hook, rename this file to "applypatch-msg".
|
||||||
|
|
||||||
|
. git-sh-setup
|
||||||
|
commitmsg="$(git rev-parse --git-path hooks/commit-msg)"
|
||||||
|
test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"}
|
||||||
|
:
|
||||||
24
.git copy/hooks/commit-msg.sample
Executable file
24
.git copy/hooks/commit-msg.sample
Executable file
@@ -0,0 +1,24 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# An example hook script to check the commit log message.
|
||||||
|
# Called by "git commit" with one argument, the name of the file
|
||||||
|
# that has the commit message. The hook should exit with non-zero
|
||||||
|
# status after issuing an appropriate message if it wants to stop the
|
||||||
|
# commit. The hook is allowed to edit the commit message file.
|
||||||
|
#
|
||||||
|
# To enable this hook, rename this file to "commit-msg".
|
||||||
|
|
||||||
|
# Uncomment the below to add a Signed-off-by line to the message.
|
||||||
|
# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
|
||||||
|
# hook is more suited to it.
|
||||||
|
#
|
||||||
|
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
|
||||||
|
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
|
||||||
|
|
||||||
|
# This example catches duplicate Signed-off-by lines.
|
||||||
|
|
||||||
|
test "" = "$(grep '^Signed-off-by: ' "$1" |
|
||||||
|
sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
|
||||||
|
echo >&2 Duplicate Signed-off-by lines.
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
174
.git copy/hooks/fsmonitor-watchman.sample
Executable file
174
.git copy/hooks/fsmonitor-watchman.sample
Executable file
@@ -0,0 +1,174 @@
|
|||||||
|
#!/usr/bin/perl
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use IPC::Open2;
|
||||||
|
|
||||||
|
# An example hook script to integrate Watchman
|
||||||
|
# (https://facebook.github.io/watchman/) with git to speed up detecting
|
||||||
|
# new and modified files.
|
||||||
|
#
|
||||||
|
# The hook is passed a version (currently 2) and last update token
|
||||||
|
# formatted as a string and outputs to stdout a new update token and
|
||||||
|
# all files that have been modified since the update token. Paths must
|
||||||
|
# be relative to the root of the working tree and separated by a single NUL.
|
||||||
|
#
|
||||||
|
# To enable this hook, rename this file to "query-watchman" and set
|
||||||
|
# 'git config core.fsmonitor .git/hooks/query-watchman'
|
||||||
|
#
|
||||||
|
my ($version, $last_update_token) = @ARGV;
|
||||||
|
|
||||||
|
# Uncomment for debugging
|
||||||
|
# print STDERR "$0 $version $last_update_token\n";
|
||||||
|
|
||||||
|
# Check the hook interface version
|
||||||
|
if ($version ne 2) {
|
||||||
|
die "Unsupported query-fsmonitor hook version '$version'.\n" .
|
||||||
|
"Falling back to scanning...\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
my $git_work_tree = get_working_dir();
|
||||||
|
|
||||||
|
my $retry = 1;
|
||||||
|
|
||||||
|
my $json_pkg;
|
||||||
|
eval {
|
||||||
|
require JSON::XS;
|
||||||
|
$json_pkg = "JSON::XS";
|
||||||
|
1;
|
||||||
|
} or do {
|
||||||
|
require JSON::PP;
|
||||||
|
$json_pkg = "JSON::PP";
|
||||||
|
};
|
||||||
|
|
||||||
|
launch_watchman();
|
||||||
|
|
||||||
|
sub launch_watchman {
|
||||||
|
my $o = watchman_query();
|
||||||
|
if (is_work_tree_watched($o)) {
|
||||||
|
output_result($o->{clock}, @{$o->{files}});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub output_result {
|
||||||
|
my ($clockid, @files) = @_;
|
||||||
|
|
||||||
|
# Uncomment for debugging watchman output
|
||||||
|
# open (my $fh, ">", ".git/watchman-output.out");
|
||||||
|
# binmode $fh, ":utf8";
|
||||||
|
# print $fh "$clockid\n@files\n";
|
||||||
|
# close $fh;
|
||||||
|
|
||||||
|
binmode STDOUT, ":utf8";
|
||||||
|
print $clockid;
|
||||||
|
print "\0";
|
||||||
|
local $, = "\0";
|
||||||
|
print @files;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub watchman_clock {
|
||||||
|
my $response = qx/watchman clock "$git_work_tree"/;
|
||||||
|
die "Failed to get clock id on '$git_work_tree'.\n" .
|
||||||
|
"Falling back to scanning...\n" if $? != 0;
|
||||||
|
|
||||||
|
return $json_pkg->new->utf8->decode($response);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub watchman_query {
|
||||||
|
my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'watchman -j --no-pretty')
|
||||||
|
or die "open2() failed: $!\n" .
|
||||||
|
"Falling back to scanning...\n";
|
||||||
|
|
||||||
|
# In the query expression below we're asking for names of files that
|
||||||
|
# changed since $last_update_token but not from the .git folder.
|
||||||
|
#
|
||||||
|
# To accomplish this, we're using the "since" generator to use the
|
||||||
|
# recency index to select candidate nodes and "fields" to limit the
|
||||||
|
# output to file names only. Then we're using the "expression" term to
|
||||||
|
# further constrain the results.
|
||||||
|
my $last_update_line = "";
|
||||||
|
if (substr($last_update_token, 0, 1) eq "c") {
|
||||||
|
$last_update_token = "\"$last_update_token\"";
|
||||||
|
$last_update_line = qq[\n"since": $last_update_token,];
|
||||||
|
}
|
||||||
|
my $query = <<" END";
|
||||||
|
["query", "$git_work_tree", {$last_update_line
|
||||||
|
"fields": ["name"],
|
||||||
|
"expression": ["not", ["dirname", ".git"]]
|
||||||
|
}]
|
||||||
|
END
|
||||||
|
|
||||||
|
# Uncomment for debugging the watchman query
|
||||||
|
# open (my $fh, ">", ".git/watchman-query.json");
|
||||||
|
# print $fh $query;
|
||||||
|
# close $fh;
|
||||||
|
|
||||||
|
print CHLD_IN $query;
|
||||||
|
close CHLD_IN;
|
||||||
|
my $response = do {local $/; <CHLD_OUT>};
|
||||||
|
|
||||||
|
# Uncomment for debugging the watch response
|
||||||
|
# open ($fh, ">", ".git/watchman-response.json");
|
||||||
|
# print $fh $response;
|
||||||
|
# close $fh;
|
||||||
|
|
||||||
|
die "Watchman: command returned no output.\n" .
|
||||||
|
"Falling back to scanning...\n" if $response eq "";
|
||||||
|
die "Watchman: command returned invalid output: $response\n" .
|
||||||
|
"Falling back to scanning...\n" unless $response =~ /^\{/;
|
||||||
|
|
||||||
|
return $json_pkg->new->utf8->decode($response);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub is_work_tree_watched {
|
||||||
|
my ($output) = @_;
|
||||||
|
my $error = $output->{error};
|
||||||
|
if ($retry > 0 and $error and $error =~ m/unable to resolve root .* directory (.*) is not watched/) {
|
||||||
|
$retry--;
|
||||||
|
my $response = qx/watchman watch "$git_work_tree"/;
|
||||||
|
die "Failed to make watchman watch '$git_work_tree'.\n" .
|
||||||
|
"Falling back to scanning...\n" if $? != 0;
|
||||||
|
$output = $json_pkg->new->utf8->decode($response);
|
||||||
|
$error = $output->{error};
|
||||||
|
die "Watchman: $error.\n" .
|
||||||
|
"Falling back to scanning...\n" if $error;
|
||||||
|
|
||||||
|
# Uncomment for debugging watchman output
|
||||||
|
# open (my $fh, ">", ".git/watchman-output.out");
|
||||||
|
# close $fh;
|
||||||
|
|
||||||
|
# Watchman will always return all files on the first query so
|
||||||
|
# return the fast "everything is dirty" flag to git and do the
|
||||||
|
# Watchman query just to get it over with now so we won't pay
|
||||||
|
# the cost in git to look up each individual file.
|
||||||
|
my $o = watchman_clock();
|
||||||
|
$error = $output->{error};
|
||||||
|
|
||||||
|
die "Watchman: $error.\n" .
|
||||||
|
"Falling back to scanning...\n" if $error;
|
||||||
|
|
||||||
|
output_result($o->{clock}, ("/"));
|
||||||
|
$last_update_token = $o->{clock};
|
||||||
|
|
||||||
|
eval { launch_watchman() };
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
die "Watchman: $error.\n" .
|
||||||
|
"Falling back to scanning...\n" if $error;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_working_dir {
|
||||||
|
my $working_dir;
|
||||||
|
if ($^O =~ 'msys' || $^O =~ 'cygwin') {
|
||||||
|
$working_dir = Win32::GetCwd();
|
||||||
|
$working_dir =~ tr/\\/\//;
|
||||||
|
} else {
|
||||||
|
require Cwd;
|
||||||
|
$working_dir = Cwd::cwd();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $working_dir;
|
||||||
|
}
|
||||||
8
.git copy/hooks/post-update.sample
Executable file
8
.git copy/hooks/post-update.sample
Executable file
@@ -0,0 +1,8 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# An example hook script to prepare a packed repository for use over
|
||||||
|
# dumb transports.
|
||||||
|
#
|
||||||
|
# To enable this hook, rename this file to "post-update".
|
||||||
|
|
||||||
|
exec git update-server-info
|
||||||
14
.git copy/hooks/pre-applypatch.sample
Executable file
14
.git copy/hooks/pre-applypatch.sample
Executable file
@@ -0,0 +1,14 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# An example hook script to verify what is about to be committed
|
||||||
|
# by applypatch from an e-mail message.
|
||||||
|
#
|
||||||
|
# The hook should exit with non-zero status after issuing an
|
||||||
|
# appropriate message if it wants to stop the commit.
|
||||||
|
#
|
||||||
|
# To enable this hook, rename this file to "pre-applypatch".
|
||||||
|
|
||||||
|
. git-sh-setup
|
||||||
|
precommit="$(git rev-parse --git-path hooks/pre-commit)"
|
||||||
|
test -x "$precommit" && exec "$precommit" ${1+"$@"}
|
||||||
|
:
|
||||||
49
.git copy/hooks/pre-commit.sample
Executable file
49
.git copy/hooks/pre-commit.sample
Executable file
@@ -0,0 +1,49 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# An example hook script to verify what is about to be committed.
|
||||||
|
# Called by "git commit" with no arguments. The hook should
|
||||||
|
# exit with non-zero status after issuing an appropriate message if
|
||||||
|
# it wants to stop the commit.
|
||||||
|
#
|
||||||
|
# To enable this hook, rename this file to "pre-commit".
|
||||||
|
|
||||||
|
if git rev-parse --verify HEAD >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
against=HEAD
|
||||||
|
else
|
||||||
|
# Initial commit: diff against an empty tree object
|
||||||
|
against=$(git hash-object -t tree /dev/null)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If you want to allow non-ASCII filenames set this variable to true.
|
||||||
|
allownonascii=$(git config --type=bool hooks.allownonascii)
|
||||||
|
|
||||||
|
# Redirect output to stderr.
|
||||||
|
exec 1>&2
|
||||||
|
|
||||||
|
# Cross platform projects tend to avoid non-ASCII filenames; prevent
|
||||||
|
# them from being added to the repository. We exploit the fact that the
|
||||||
|
# printable range starts at the space character and ends with tilde.
|
||||||
|
if [ "$allownonascii" != "true" ] &&
|
||||||
|
# Note that the use of brackets around a tr range is ok here, (it's
|
||||||
|
# even required, for portability to Solaris 10's /usr/bin/tr), since
|
||||||
|
# the square bracket bytes happen to fall in the designated range.
|
||||||
|
test $(git diff-index --cached --name-only --diff-filter=A -z $against |
|
||||||
|
LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
|
||||||
|
then
|
||||||
|
cat <<\EOF
|
||||||
|
Error: Attempt to add a non-ASCII file name.
|
||||||
|
|
||||||
|
This can cause problems if you want to work with people on other platforms.
|
||||||
|
|
||||||
|
To be portable it is advisable to rename the file.
|
||||||
|
|
||||||
|
If you know what you are doing you can disable this check using:
|
||||||
|
|
||||||
|
git config hooks.allownonascii true
|
||||||
|
EOF
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If there are whitespace errors, print the offending file names and fail.
|
||||||
|
exec git diff-index --check --cached $against --
|
||||||
13
.git copy/hooks/pre-merge-commit.sample
Executable file
13
.git copy/hooks/pre-merge-commit.sample
Executable file
@@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# An example hook script to verify what is about to be committed.
|
||||||
|
# Called by "git merge" with no arguments. The hook should
|
||||||
|
# exit with non-zero status after issuing an appropriate message to
|
||||||
|
# stderr if it wants to stop the merge commit.
|
||||||
|
#
|
||||||
|
# To enable this hook, rename this file to "pre-merge-commit".
|
||||||
|
|
||||||
|
. git-sh-setup
|
||||||
|
test -x "$GIT_DIR/hooks/pre-commit" &&
|
||||||
|
exec "$GIT_DIR/hooks/pre-commit"
|
||||||
|
:
|
||||||
53
.git copy/hooks/pre-push.sample
Executable file
53
.git copy/hooks/pre-push.sample
Executable file
@@ -0,0 +1,53 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# An example hook script to verify what is about to be pushed. Called by "git
|
||||||
|
# push" after it has checked the remote status, but before anything has been
|
||||||
|
# pushed. If this script exits with a non-zero status nothing will be pushed.
|
||||||
|
#
|
||||||
|
# This hook is called with the following parameters:
|
||||||
|
#
|
||||||
|
# $1 -- Name of the remote to which the push is being done
|
||||||
|
# $2 -- URL to which the push is being done
|
||||||
|
#
|
||||||
|
# If pushing without using a named remote those arguments will be equal.
|
||||||
|
#
|
||||||
|
# Information about the commits which are being pushed is supplied as lines to
|
||||||
|
# the standard input in the form:
|
||||||
|
#
|
||||||
|
# <local ref> <local oid> <remote ref> <remote oid>
|
||||||
|
#
|
||||||
|
# This sample shows how to prevent push of commits where the log message starts
|
||||||
|
# with "WIP" (work in progress).
|
||||||
|
|
||||||
|
remote="$1"
|
||||||
|
url="$2"
|
||||||
|
|
||||||
|
zero=$(git hash-object --stdin </dev/null | tr '[0-9a-f]' '0')
|
||||||
|
|
||||||
|
while read local_ref local_oid remote_ref remote_oid
|
||||||
|
do
|
||||||
|
if test "$local_oid" = "$zero"
|
||||||
|
then
|
||||||
|
# Handle delete
|
||||||
|
:
|
||||||
|
else
|
||||||
|
if test "$remote_oid" = "$zero"
|
||||||
|
then
|
||||||
|
# New branch, examine all commits
|
||||||
|
range="$local_oid"
|
||||||
|
else
|
||||||
|
# Update to existing branch, examine new commits
|
||||||
|
range="$remote_oid..$local_oid"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for WIP commit
|
||||||
|
commit=$(git rev-list -n 1 --grep '^WIP' "$range")
|
||||||
|
if test -n "$commit"
|
||||||
|
then
|
||||||
|
echo >&2 "Found WIP commit in $local_ref, not pushing"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
exit 0
|
||||||
169
.git copy/hooks/pre-rebase.sample
Executable file
169
.git copy/hooks/pre-rebase.sample
Executable file
@@ -0,0 +1,169 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# Copyright (c) 2006, 2008 Junio C Hamano
|
||||||
|
#
|
||||||
|
# The "pre-rebase" hook is run just before "git rebase" starts doing
|
||||||
|
# its job, and can prevent the command from running by exiting with
|
||||||
|
# non-zero status.
|
||||||
|
#
|
||||||
|
# The hook is called with the following parameters:
|
||||||
|
#
|
||||||
|
# $1 -- the upstream the series was forked from.
|
||||||
|
# $2 -- the branch being rebased (or empty when rebasing the current branch).
|
||||||
|
#
|
||||||
|
# This sample shows how to prevent topic branches that are already
|
||||||
|
# merged to 'next' branch from getting rebased, because allowing it
|
||||||
|
# would result in rebasing already published history.
|
||||||
|
|
||||||
|
publish=next
|
||||||
|
basebranch="$1"
|
||||||
|
if test "$#" = 2
|
||||||
|
then
|
||||||
|
topic="refs/heads/$2"
|
||||||
|
else
|
||||||
|
topic=`git symbolic-ref HEAD` ||
|
||||||
|
exit 0 ;# we do not interrupt rebasing detached HEAD
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$topic" in
|
||||||
|
refs/heads/??/*)
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
exit 0 ;# we do not interrupt others.
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Now we are dealing with a topic branch being rebased
|
||||||
|
# on top of master. Is it OK to rebase it?
|
||||||
|
|
||||||
|
# Does the topic really exist?
|
||||||
|
git show-ref -q "$topic" || {
|
||||||
|
echo >&2 "No such branch $topic"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Is topic fully merged to master?
|
||||||
|
not_in_master=`git rev-list --pretty=oneline ^master "$topic"`
|
||||||
|
if test -z "$not_in_master"
|
||||||
|
then
|
||||||
|
echo >&2 "$topic is fully merged to master; better remove it."
|
||||||
|
exit 1 ;# we could allow it, but there is no point.
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Is topic ever merged to next? If so you should not be rebasing it.
|
||||||
|
only_next_1=`git rev-list ^master "^$topic" ${publish} | sort`
|
||||||
|
only_next_2=`git rev-list ^master ${publish} | sort`
|
||||||
|
if test "$only_next_1" = "$only_next_2"
|
||||||
|
then
|
||||||
|
not_in_topic=`git rev-list "^$topic" master`
|
||||||
|
if test -z "$not_in_topic"
|
||||||
|
then
|
||||||
|
echo >&2 "$topic is already up to date with master"
|
||||||
|
exit 1 ;# we could allow it, but there is no point.
|
||||||
|
else
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"`
|
||||||
|
/usr/bin/perl -e '
|
||||||
|
my $topic = $ARGV[0];
|
||||||
|
my $msg = "* $topic has commits already merged to public branch:\n";
|
||||||
|
my (%not_in_next) = map {
|
||||||
|
/^([0-9a-f]+) /;
|
||||||
|
($1 => 1);
|
||||||
|
} split(/\n/, $ARGV[1]);
|
||||||
|
for my $elem (map {
|
||||||
|
/^([0-9a-f]+) (.*)$/;
|
||||||
|
[$1 => $2];
|
||||||
|
} split(/\n/, $ARGV[2])) {
|
||||||
|
if (!exists $not_in_next{$elem->[0]}) {
|
||||||
|
if ($msg) {
|
||||||
|
print STDERR $msg;
|
||||||
|
undef $msg;
|
||||||
|
}
|
||||||
|
print STDERR " $elem->[1]\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
' "$topic" "$not_in_next" "$not_in_master"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
<<\DOC_END
|
||||||
|
|
||||||
|
This sample hook safeguards topic branches that have been
|
||||||
|
published from being rewound.
|
||||||
|
|
||||||
|
The workflow assumed here is:
|
||||||
|
|
||||||
|
* Once a topic branch forks from "master", "master" is never
|
||||||
|
merged into it again (either directly or indirectly).
|
||||||
|
|
||||||
|
* Once a topic branch is fully cooked and merged into "master",
|
||||||
|
it is deleted. If you need to build on top of it to correct
|
||||||
|
earlier mistakes, a new topic branch is created by forking at
|
||||||
|
the tip of the "master". This is not strictly necessary, but
|
||||||
|
it makes it easier to keep your history simple.
|
||||||
|
|
||||||
|
* Whenever you need to test or publish your changes to topic
|
||||||
|
branches, merge them into "next" branch.
|
||||||
|
|
||||||
|
The script, being an example, hardcodes the publish branch name
|
||||||
|
to be "next", but it is trivial to make it configurable via
|
||||||
|
$GIT_DIR/config mechanism.
|
||||||
|
|
||||||
|
With this workflow, you would want to know:
|
||||||
|
|
||||||
|
(1) ... if a topic branch has ever been merged to "next". Young
|
||||||
|
topic branches can have stupid mistakes you would rather
|
||||||
|
clean up before publishing, and things that have not been
|
||||||
|
merged into other branches can be easily rebased without
|
||||||
|
affecting other people. But once it is published, you would
|
||||||
|
not want to rewind it.
|
||||||
|
|
||||||
|
(2) ... if a topic branch has been fully merged to "master".
|
||||||
|
Then you can delete it. More importantly, you should not
|
||||||
|
build on top of it -- other people may already want to
|
||||||
|
change things related to the topic as patches against your
|
||||||
|
"master", so if you need further changes, it is better to
|
||||||
|
fork the topic (perhaps with the same name) afresh from the
|
||||||
|
tip of "master".
|
||||||
|
|
||||||
|
Let's look at this example:
|
||||||
|
|
||||||
|
o---o---o---o---o---o---o---o---o---o "next"
|
||||||
|
/ / / /
|
||||||
|
/ a---a---b A / /
|
||||||
|
/ / / /
|
||||||
|
/ / c---c---c---c B /
|
||||||
|
/ / / \ /
|
||||||
|
/ / / b---b C \ /
|
||||||
|
/ / / / \ /
|
||||||
|
---o---o---o---o---o---o---o---o---o---o---o "master"
|
||||||
|
|
||||||
|
|
||||||
|
A, B and C are topic branches.
|
||||||
|
|
||||||
|
* A has one fix since it was merged up to "next".
|
||||||
|
|
||||||
|
* B has finished. It has been fully merged up to "master" and "next",
|
||||||
|
and is ready to be deleted.
|
||||||
|
|
||||||
|
* C has not merged to "next" at all.
|
||||||
|
|
||||||
|
We would want to allow C to be rebased, refuse A, and encourage
|
||||||
|
B to be deleted.
|
||||||
|
|
||||||
|
To compute (1):
|
||||||
|
|
||||||
|
git rev-list ^master ^topic next
|
||||||
|
git rev-list ^master next
|
||||||
|
|
||||||
|
if these match, topic has not merged in next at all.
|
||||||
|
|
||||||
|
To compute (2):
|
||||||
|
|
||||||
|
git rev-list master..topic
|
||||||
|
|
||||||
|
if this is empty, it is fully merged to "master".
|
||||||
|
|
||||||
|
DOC_END
|
||||||
24
.git copy/hooks/pre-receive.sample
Executable file
24
.git copy/hooks/pre-receive.sample
Executable file
@@ -0,0 +1,24 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# An example hook script to make use of push options.
|
||||||
|
# The example simply echoes all push options that start with 'echoback='
|
||||||
|
# and rejects all pushes when the "reject" push option is used.
|
||||||
|
#
|
||||||
|
# To enable this hook, rename this file to "pre-receive".
|
||||||
|
|
||||||
|
if test -n "$GIT_PUSH_OPTION_COUNT"
|
||||||
|
then
|
||||||
|
i=0
|
||||||
|
while test "$i" -lt "$GIT_PUSH_OPTION_COUNT"
|
||||||
|
do
|
||||||
|
eval "value=\$GIT_PUSH_OPTION_$i"
|
||||||
|
case "$value" in
|
||||||
|
echoback=*)
|
||||||
|
echo "echo from the pre-receive-hook: ${value#*=}" >&2
|
||||||
|
;;
|
||||||
|
reject)
|
||||||
|
exit 1
|
||||||
|
esac
|
||||||
|
i=$((i + 1))
|
||||||
|
done
|
||||||
|
fi
|
||||||
42
.git copy/hooks/prepare-commit-msg.sample
Executable file
42
.git copy/hooks/prepare-commit-msg.sample
Executable file
@@ -0,0 +1,42 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# An example hook script to prepare the commit log message.
|
||||||
|
# Called by "git commit" with the name of the file that has the
|
||||||
|
# commit message, followed by the description of the commit
|
||||||
|
# message's source. The hook's purpose is to edit the commit
|
||||||
|
# message file. If the hook fails with a non-zero status,
|
||||||
|
# the commit is aborted.
|
||||||
|
#
|
||||||
|
# To enable this hook, rename this file to "prepare-commit-msg".
|
||||||
|
|
||||||
|
# This hook includes three examples. The first one removes the
|
||||||
|
# "# Please enter the commit message..." help message.
|
||||||
|
#
|
||||||
|
# The second includes the output of "git diff --name-status -r"
|
||||||
|
# into the message, just before the "git status" output. It is
|
||||||
|
# commented because it doesn't cope with --amend or with squashed
|
||||||
|
# commits.
|
||||||
|
#
|
||||||
|
# The third example adds a Signed-off-by line to the message, that can
|
||||||
|
# still be edited. This is rarely a good idea.
|
||||||
|
|
||||||
|
COMMIT_MSG_FILE=$1
|
||||||
|
COMMIT_SOURCE=$2
|
||||||
|
SHA1=$3
|
||||||
|
|
||||||
|
/usr/bin/perl -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE"
|
||||||
|
|
||||||
|
# case "$COMMIT_SOURCE,$SHA1" in
|
||||||
|
# ,|template,)
|
||||||
|
# /usr/bin/perl -i.bak -pe '
|
||||||
|
# print "\n" . `git diff --cached --name-status -r`
|
||||||
|
# if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;;
|
||||||
|
# *) ;;
|
||||||
|
# esac
|
||||||
|
|
||||||
|
# SOB=$(git var GIT_COMMITTER_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
|
||||||
|
# git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE"
|
||||||
|
# if test -z "$COMMIT_SOURCE"
|
||||||
|
# then
|
||||||
|
# /usr/bin/perl -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE"
|
||||||
|
# fi
|
||||||
78
.git copy/hooks/push-to-checkout.sample
Executable file
78
.git copy/hooks/push-to-checkout.sample
Executable file
@@ -0,0 +1,78 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# An example hook script to update a checked-out tree on a git push.
|
||||||
|
#
|
||||||
|
# This hook is invoked by git-receive-pack(1) when it reacts to git
|
||||||
|
# push and updates reference(s) in its repository, and when the push
|
||||||
|
# tries to update the branch that is currently checked out and the
|
||||||
|
# receive.denyCurrentBranch configuration variable is set to
|
||||||
|
# updateInstead.
|
||||||
|
#
|
||||||
|
# By default, such a push is refused if the working tree and the index
|
||||||
|
# of the remote repository has any difference from the currently
|
||||||
|
# checked out commit; when both the working tree and the index match
|
||||||
|
# the current commit, they are updated to match the newly pushed tip
|
||||||
|
# of the branch. This hook is to be used to override the default
|
||||||
|
# behaviour; however the code below reimplements the default behaviour
|
||||||
|
# as a starting point for convenient modification.
|
||||||
|
#
|
||||||
|
# The hook receives the commit with which the tip of the current
|
||||||
|
# branch is going to be updated:
|
||||||
|
commit=$1
|
||||||
|
|
||||||
|
# It can exit with a non-zero status to refuse the push (when it does
|
||||||
|
# so, it must not modify the index or the working tree).
|
||||||
|
die () {
|
||||||
|
echo >&2 "$*"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Or it can make any necessary changes to the working tree and to the
|
||||||
|
# index to bring them to the desired state when the tip of the current
|
||||||
|
# branch is updated to the new commit, and exit with a zero status.
|
||||||
|
#
|
||||||
|
# For example, the hook can simply run git read-tree -u -m HEAD "$1"
|
||||||
|
# in order to emulate git fetch that is run in the reverse direction
|
||||||
|
# with git push, as the two-tree form of git read-tree -u -m is
|
||||||
|
# essentially the same as git switch or git checkout that switches
|
||||||
|
# branches while keeping the local changes in the working tree that do
|
||||||
|
# not interfere with the difference between the branches.
|
||||||
|
|
||||||
|
# The below is a more-or-less exact translation to shell of the C code
|
||||||
|
# for the default behaviour for git's push-to-checkout hook defined in
|
||||||
|
# the push_to_deploy() function in builtin/receive-pack.c.
|
||||||
|
#
|
||||||
|
# Note that the hook will be executed from the repository directory,
|
||||||
|
# not from the working tree, so if you want to perform operations on
|
||||||
|
# the working tree, you will have to adapt your code accordingly, e.g.
|
||||||
|
# by adding "cd .." or using relative paths.
|
||||||
|
|
||||||
|
if ! git update-index -q --ignore-submodules --refresh
|
||||||
|
then
|
||||||
|
die "Up-to-date check failed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! git diff-files --quiet --ignore-submodules --
|
||||||
|
then
|
||||||
|
die "Working directory has unstaged changes"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# This is a rough translation of:
|
||||||
|
#
|
||||||
|
# head_has_history() ? "HEAD" : EMPTY_TREE_SHA1_HEX
|
||||||
|
if git cat-file -e HEAD 2>/dev/null
|
||||||
|
then
|
||||||
|
head=HEAD
|
||||||
|
else
|
||||||
|
head=$(git hash-object -t tree --stdin </dev/null)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! git diff-index --quiet --cached --ignore-submodules $head --
|
||||||
|
then
|
||||||
|
die "Working directory has staged changes"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! git read-tree -u -m "$commit"
|
||||||
|
then
|
||||||
|
die "Could not update working tree to new HEAD"
|
||||||
|
fi
|
||||||
77
.git copy/hooks/sendemail-validate.sample
Executable file
77
.git copy/hooks/sendemail-validate.sample
Executable file
@@ -0,0 +1,77 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# An example hook script to validate a patch (and/or patch series) before
|
||||||
|
# sending it via email.
|
||||||
|
#
|
||||||
|
# The hook should exit with non-zero status after issuing an appropriate
|
||||||
|
# message if it wants to prevent the email(s) from being sent.
|
||||||
|
#
|
||||||
|
# To enable this hook, rename this file to "sendemail-validate".
|
||||||
|
#
|
||||||
|
# By default, it will only check that the patch(es) can be applied on top of
|
||||||
|
# the default upstream branch without conflicts in a secondary worktree. After
|
||||||
|
# validation (successful or not) of the last patch of a series, the worktree
|
||||||
|
# will be deleted.
|
||||||
|
#
|
||||||
|
# The following config variables can be set to change the default remote and
|
||||||
|
# remote ref that are used to apply the patches against:
|
||||||
|
#
|
||||||
|
# sendemail.validateRemote (default: origin)
|
||||||
|
# sendemail.validateRemoteRef (default: HEAD)
|
||||||
|
#
|
||||||
|
# Replace the TODO placeholders with appropriate checks according to your
|
||||||
|
# needs.
|
||||||
|
|
||||||
|
validate_cover_letter () {
|
||||||
|
file="$1"
|
||||||
|
# TODO: Replace with appropriate checks (e.g. spell checking).
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_patch () {
|
||||||
|
file="$1"
|
||||||
|
# Ensure that the patch applies without conflicts.
|
||||||
|
git am -3 "$file" || return
|
||||||
|
# TODO: Replace with appropriate checks for this patch
|
||||||
|
# (e.g. checkpatch.pl).
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_series () {
|
||||||
|
# TODO: Replace with appropriate checks for the whole series
|
||||||
|
# (e.g. quick build, coding style checks, etc.).
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
# main -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
if test "$GIT_SENDEMAIL_FILE_COUNTER" = 1
|
||||||
|
then
|
||||||
|
remote=$(git config --default origin --get sendemail.validateRemote) &&
|
||||||
|
ref=$(git config --default HEAD --get sendemail.validateRemoteRef) &&
|
||||||
|
worktree=$(mktemp --tmpdir -d sendemail-validate.XXXXXXX) &&
|
||||||
|
git worktree add -fd --checkout "$worktree" "refs/remotes/$remote/$ref" &&
|
||||||
|
git config --replace-all sendemail.validateWorktree "$worktree"
|
||||||
|
else
|
||||||
|
worktree=$(git config --get sendemail.validateWorktree)
|
||||||
|
fi || {
|
||||||
|
echo "sendemail-validate: error: failed to prepare worktree" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
unset GIT_DIR GIT_WORK_TREE
|
||||||
|
cd "$worktree" &&
|
||||||
|
|
||||||
|
if grep -q "^diff --git " "$1"
|
||||||
|
then
|
||||||
|
validate_patch "$1"
|
||||||
|
else
|
||||||
|
validate_cover_letter "$1"
|
||||||
|
fi &&
|
||||||
|
|
||||||
|
if test "$GIT_SENDEMAIL_FILE_COUNTER" = "$GIT_SENDEMAIL_FILE_TOTAL"
|
||||||
|
then
|
||||||
|
git config --unset-all sendemail.validateWorktree &&
|
||||||
|
trap 'git worktree remove -ff "$worktree"' EXIT &&
|
||||||
|
validate_series
|
||||||
|
fi
|
||||||
128
.git copy/hooks/update.sample
Executable file
128
.git copy/hooks/update.sample
Executable file
@@ -0,0 +1,128 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# An example hook script to block unannotated tags from entering.
|
||||||
|
# Called by "git receive-pack" with arguments: refname sha1-old sha1-new
|
||||||
|
#
|
||||||
|
# To enable this hook, rename this file to "update".
|
||||||
|
#
|
||||||
|
# Config
|
||||||
|
# ------
|
||||||
|
# hooks.allowunannotated
|
||||||
|
# This boolean sets whether unannotated tags will be allowed into the
|
||||||
|
# repository. By default they won't be.
|
||||||
|
# hooks.allowdeletetag
|
||||||
|
# This boolean sets whether deleting tags will be allowed in the
|
||||||
|
# repository. By default they won't be.
|
||||||
|
# hooks.allowmodifytag
|
||||||
|
# This boolean sets whether a tag may be modified after creation. By default
|
||||||
|
# it won't be.
|
||||||
|
# hooks.allowdeletebranch
|
||||||
|
# This boolean sets whether deleting branches will be allowed in the
|
||||||
|
# repository. By default they won't be.
|
||||||
|
# hooks.denycreatebranch
|
||||||
|
# This boolean sets whether remotely creating branches will be denied
|
||||||
|
# in the repository. By default this is allowed.
|
||||||
|
#
|
||||||
|
|
||||||
|
# --- Command line
|
||||||
|
refname="$1"
|
||||||
|
oldrev="$2"
|
||||||
|
newrev="$3"
|
||||||
|
|
||||||
|
# --- Safety check
|
||||||
|
if [ -z "$GIT_DIR" ]; then
|
||||||
|
echo "Don't run this script from the command line." >&2
|
||||||
|
echo " (if you want, you could supply GIT_DIR then run" >&2
|
||||||
|
echo " $0 <ref> <oldrev> <newrev>)" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
|
||||||
|
echo "usage: $0 <ref> <oldrev> <newrev>" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- Config
|
||||||
|
allowunannotated=$(git config --type=bool hooks.allowunannotated)
|
||||||
|
allowdeletebranch=$(git config --type=bool hooks.allowdeletebranch)
|
||||||
|
denycreatebranch=$(git config --type=bool hooks.denycreatebranch)
|
||||||
|
allowdeletetag=$(git config --type=bool hooks.allowdeletetag)
|
||||||
|
allowmodifytag=$(git config --type=bool hooks.allowmodifytag)
|
||||||
|
|
||||||
|
# check for no description
|
||||||
|
projectdesc=$(sed -e '1q' "$GIT_DIR/description")
|
||||||
|
case "$projectdesc" in
|
||||||
|
"Unnamed repository"* | "")
|
||||||
|
echo "*** Project description file hasn't been set" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# --- Check types
|
||||||
|
# if $newrev is 0000...0000, it's a commit to delete a ref.
|
||||||
|
zero=$(git hash-object --stdin </dev/null | tr '[0-9a-f]' '0')
|
||||||
|
if [ "$newrev" = "$zero" ]; then
|
||||||
|
newrev_type=delete
|
||||||
|
else
|
||||||
|
newrev_type=$(git cat-file -t $newrev)
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$refname","$newrev_type" in
|
||||||
|
refs/tags/*,commit)
|
||||||
|
# un-annotated tag
|
||||||
|
short_refname=${refname##refs/tags/}
|
||||||
|
if [ "$allowunannotated" != "true" ]; then
|
||||||
|
echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
|
||||||
|
echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
refs/tags/*,delete)
|
||||||
|
# delete tag
|
||||||
|
if [ "$allowdeletetag" != "true" ]; then
|
||||||
|
echo "*** Deleting a tag is not allowed in this repository" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
refs/tags/*,tag)
|
||||||
|
# annotated tag
|
||||||
|
if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
|
||||||
|
then
|
||||||
|
echo "*** Tag '$refname' already exists." >&2
|
||||||
|
echo "*** Modifying a tag is not allowed in this repository." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
refs/heads/*,commit)
|
||||||
|
# branch
|
||||||
|
if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
|
||||||
|
echo "*** Creating a branch is not allowed in this repository" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
refs/heads/*,delete)
|
||||||
|
# delete branch
|
||||||
|
if [ "$allowdeletebranch" != "true" ]; then
|
||||||
|
echo "*** Deleting a branch is not allowed in this repository" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
refs/remotes/*,commit)
|
||||||
|
# tracking branch
|
||||||
|
;;
|
||||||
|
refs/remotes/*,delete)
|
||||||
|
# delete tracking branch
|
||||||
|
if [ "$allowdeletebranch" != "true" ]; then
|
||||||
|
echo "*** Deleting a tracking branch is not allowed in this repository" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
# Anything else (is there anything else?)
|
||||||
|
echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# --- Finished
|
||||||
|
exit 0
|
||||||
BIN
.git copy/index
Normal file
BIN
.git copy/index
Normal file
Binary file not shown.
6
.git copy/info/exclude
Normal file
6
.git copy/info/exclude
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# git ls-files --others --exclude-from=.git/info/exclude
|
||||||
|
# Lines that start with '#' are comments.
|
||||||
|
# For a project mostly in C, the following would be a good set of
|
||||||
|
# exclude patterns (uncomment them if you want to use them):
|
||||||
|
# *.[oa]
|
||||||
|
# *~
|
||||||
56
.git copy/logs/HEAD
Normal file
56
.git copy/logs/HEAD
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
0000000000000000000000000000000000000000 2b26f76e2fdfbeb9d14c725b82d299374b402905 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1773897879 +0900 clone: from https://git.sginfra.net/sgp-web-d/gameservice-fe-agent.git
|
||||||
|
2b26f76e2fdfbeb9d14c725b82d299374b402905 2b26f76e2fdfbeb9d14c725b82d299374b402905 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1773983657 +0900 checkout: moving from main to feature/mr
|
||||||
|
2b26f76e2fdfbeb9d14c725b82d299374b402905 c3ce56f9934121bda6d271c9cc71c52b700e8213 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1773983669 +0900 commit: Add CLAUDE.md for project guidance and workflow documentation
|
||||||
|
c3ce56f9934121bda6d271c9cc71c52b700e8213 dbccdfc3287e0ed5f5b11c9a2b2ff902d2346073 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1773986257 +0900 commit: feat: 개발 지침 README.md 추가
|
||||||
|
dbccdfc3287e0ed5f5b11c9a2b2ff902d2346073 039532dc7223b0ad448f3be4f966339703bac5a7 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1774265735 +0900 commit: feat: Add CI configuration and various Claude agents for Nuxt development
|
||||||
|
039532dc7223b0ad448f3be4f966339703bac5a7 5680ba2679cd631e4cde8b8e80771a90406b5cf8 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1774265900 +0900 commit: feat: 커밋 메시지 작성 규칙 문서화
|
||||||
|
5680ba2679cd631e4cde8b8e80771a90406b5cf8 ea634db13c0c30072ff93a39971c6168519b7726 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1774267241 +0900 commit: feat: CI 설정에서 Node.js 버전 변경 및 Claude 도구 허용 목록 업데이트
|
||||||
|
ea634db13c0c30072ff93a39971c6168519b7726 ac9aaf5cf918c1d7656e5013c7afa71a6401e1a2 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1774267399 +0900 commit: feat: CI 설정에 glab 설치 및 인증 추가
|
||||||
|
ac9aaf5cf918c1d7656e5013c7afa71a6401e1a2 beca607e133b86ca0af19a1a58bc47f95758e8c3 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1774267525 +0900 commit: feat: CI 스크립트에서 Claude 실행 결과를 파일에 기록하고 종료 코드 처리 추가
|
||||||
|
beca607e133b86ca0af19a1a58bc47f95758e8c3 35e091bcf46f13986f699ed02701a606cf9682ca “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775025939 +0900 commit: 📝 docs: CLAUDE.md 개선 및 Claude 명령어 구조 재정리
|
||||||
|
35e091bcf46f13986f699ed02701a606cf9682ca f377091cf2af1567b9a6120d09bed118e861197f “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775108606 +0900 commit: ✨ feat: Jira 통합 기능 및 SWV 이슈 생성 스킬 추가 [SWV-955]
|
||||||
|
f377091cf2af1567b9a6120d09bed118e861197f 5ff91ac071f3f39cc29194db8407609fd8454bfe “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775108689 +0900 commit (amend): ✨ feat: [SWV-955] Jira 통합 기능 및 SWV 이슈 생성 스킬 추가
|
||||||
|
5ff91ac071f3f39cc29194db8407609fd8454bfe e3a46e022cc220ef47bdbb8a73b92a2920d6b80f “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775110010 +0900 commit: 📝 docs: [SWV-956] Jira 스킬 문서 개선 및 실제 동작 검증
|
||||||
|
e3a46e022cc220ef47bdbb8a73b92a2920d6b80f 8c0bda779a565acc3975001ed39ad54c21759846 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775111878 +0900 commit: ✨ feat: [SWV-955] Confluence 업무일지 작성 스킬 추가
|
||||||
|
8c0bda779a565acc3975001ed39ad54c21759846 5942c2b4500e2356ca226b135c52e07bf467909d “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775540046 +0900 commit: 📝 docs: CLAUDE.md 한글화 및 Nuxt 4 전용 가이드 업데이트
|
||||||
|
5942c2b4500e2356ca226b135c52e07bf467909d d298956a8ee0be1de07fe689e91de1b2ca4b2020 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775540095 +0900 commit: ♻️ refactor: Claude 스킬 및 에이전트 구조 개선
|
||||||
|
d298956a8ee0be1de07fe689e91de1b2ca4b2020 ba6f61aa52bf3a411b5d7e04dcd0136a842f9cb9 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775540102 +0900 commit: 🔧 chore: Claude 설정 권한 및 도구 추가
|
||||||
|
ba6f61aa52bf3a411b5d7e04dcd0136a842f9cb9 4087bcf09dc957d9250341ac14aff85b9953c9c0 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775540163 +0900 commit: 🙈 chore: .gitignore 파일 추가
|
||||||
|
4087bcf09dc957d9250341ac14aff85b9953c9c0 afffbdbf8f55b41d0f97252c112b79de2388bf95 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775540228 +0900 commit: feat: Nuxt FE AI 표준화 로드맵 HTML 파일 추가
|
||||||
|
afffbdbf8f55b41d0f97252c112b79de2388bf95 cec4bb67714f2393d5dee7932807e839a83ff919 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775540245 +0900 checkout: moving from feature/mr to dev
|
||||||
|
cec4bb67714f2393d5dee7932807e839a83ff919 cec4bb67714f2393d5dee7932807e839a83ff919 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775540276 +0900 merge feature/mr: updating HEAD
|
||||||
|
cec4bb67714f2393d5dee7932807e839a83ff919 d399b8d0650df404b4afba6418213dfa8c9d76c0 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775540349 +0900 commit: chore: add environment configuration file with access tokens
|
||||||
|
d399b8d0650df404b4afba6418213dfa8c9d76c0 d3412a082f7fa135e8e5884bae4bef36d8cefe7f “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775540376 +0900 merge feature/mr: Merge made by the 'ort' strategy.
|
||||||
|
d3412a082f7fa135e8e5884bae4bef36d8cefe7f 2b26f76e2fdfbeb9d14c725b82d299374b402905 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775540390 +0900 checkout: moving from dev to main
|
||||||
|
2b26f76e2fdfbeb9d14c725b82d299374b402905 2f4532815e800742b8ebfaf3d7fdf8a4887c3db1 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775540392 +0900 pull --tags origin main: Fast-forward
|
||||||
|
2f4532815e800742b8ebfaf3d7fdf8a4887c3db1 d3412a082f7fa135e8e5884bae4bef36d8cefe7f “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775540409 +0900 checkout: moving from main to dev
|
||||||
|
d3412a082f7fa135e8e5884bae4bef36d8cefe7f afffbdbf8f55b41d0f97252c112b79de2388bf95 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775542700 +0900 checkout: moving from dev to feature/mr
|
||||||
|
afffbdbf8f55b41d0f97252c112b79de2388bf95 d3412a082f7fa135e8e5884bae4bef36d8cefe7f “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775542705 +0900 checkout: moving from feature/mr to dev
|
||||||
|
d3412a082f7fa135e8e5884bae4bef36d8cefe7f afffbdbf8f55b41d0f97252c112b79de2388bf95 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775542713 +0900 checkout: moving from dev to feature/mr
|
||||||
|
afffbdbf8f55b41d0f97252c112b79de2388bf95 d3412a082f7fa135e8e5884bae4bef36d8cefe7f “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775542728 +0900 merge dev: Fast-forward
|
||||||
|
d3412a082f7fa135e8e5884bae4bef36d8cefe7f d3412a082f7fa135e8e5884bae4bef36d8cefe7f “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775542804 +0900 checkout: moving from feature/mr to dev
|
||||||
|
d3412a082f7fa135e8e5884bae4bef36d8cefe7f 59599f3a6f69102e7d4c17a81b776a2c7c822a79 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775542829 +0900 commit: chore: 환경 변수 파일의 액세스 토큰 초기화
|
||||||
|
59599f3a6f69102e7d4c17a81b776a2c7c822a79 59599f3a6f69102e7d4c17a81b776a2c7c822a79 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775542924 +0900 checkout: moving from dev to dev
|
||||||
|
59599f3a6f69102e7d4c17a81b776a2c7c822a79 d3412a082f7fa135e8e5884bae4bef36d8cefe7f “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775542929 +0900 checkout: moving from dev to feature/mr
|
||||||
|
d3412a082f7fa135e8e5884bae4bef36d8cefe7f 3487fa20c1cc0520b8716cc89dec097a85acbb4b “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775543513 +0900 commit: chore: 환경 변수 파일의 액세스 토큰 초기화
|
||||||
|
3487fa20c1cc0520b8716cc89dec097a85acbb4b 59599f3a6f69102e7d4c17a81b776a2c7c822a79 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775543533 +0900 checkout: moving from feature/mr to dev
|
||||||
|
59599f3a6f69102e7d4c17a81b776a2c7c822a79 8260e959df8725ccf396fc30004fdb79cc7178f4 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775543555 +0900 merge feature/mr: Merge made by the 'ort' strategy.
|
||||||
|
8260e959df8725ccf396fc30004fdb79cc7178f4 8260e959df8725ccf396fc30004fdb79cc7178f4 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775544836 +0900 checkout: moving from dev to dev
|
||||||
|
8260e959df8725ccf396fc30004fdb79cc7178f4 8260e959df8725ccf396fc30004fdb79cc7178f4 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775553145 +0900 reset: moving to HEAD
|
||||||
|
8260e959df8725ccf396fc30004fdb79cc7178f4 a7666613f6d963f59550b108203dbfd8066a1053 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775553148 +0900 commit: 🔧 chore: 환경변수 파일명 .env.local에서 .env.secret으로 변경
|
||||||
|
a7666613f6d963f59550b108203dbfd8066a1053 2465c27f6bf68b8254d5bb2984625dc0cb2f0a00 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775553162 +0900 commit: 📝 docs: README.md 전면 개편 - 메타 저장소 정체성 명확화
|
||||||
|
2465c27f6bf68b8254d5bb2984625dc0cb2f0a00 d0202aa8f8d562d15a39c05b9ac1116ff6599892 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775553173 +0900 commit: ✨ feat: Nuxt 4 프로젝트 생성 표준 문서 추가
|
||||||
|
d0202aa8f8d562d15a39c05b9ac1116ff6599892 dc2de13801cbf8fb31dd0107a39c9f24de9727d3 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775553181 +0900 commit: 🔧 chore: Claude 설정 권한 업데이트 - 추가 Git 명령어 허용
|
||||||
|
dc2de13801cbf8fb31dd0107a39c9f24de9727d3 01aea986a2c7986da0be08337df28f8b767f7772 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775553254 +0900 commit: 🔥 chore: 환경변수 파일 삭제 (.env.local)
|
||||||
|
01aea986a2c7986da0be08337df28f8b767f7772 518884e472c00404a4e94112d3103f3b8401d78b “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775553272 +0900 commit: 🔧 chore: Claude 설정에 git rm 명령어 권한 추가
|
||||||
|
518884e472c00404a4e94112d3103f3b8401d78b 2f4532815e800742b8ebfaf3d7fdf8a4887c3db1 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1776045817 +0900 checkout: moving from dev to main
|
||||||
|
2f4532815e800742b8ebfaf3d7fdf8a4887c3db1 2f4532815e800742b8ebfaf3d7fdf8a4887c3db1 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1776045888 +0900 checkout: moving from main to master
|
||||||
|
2f4532815e800742b8ebfaf3d7fdf8a4887c3db1 9e2c7cd1837f24e18d800ad89bca6d7df29e9e3c “hyeonggkim” <“hyeonggkim@smilegate.com”> 1776045956 +0900 commit: ✨ feat: 공통 Claude 지침 및 규칙 문서 추가
|
||||||
|
9e2c7cd1837f24e18d800ad89bca6d7df29e9e3c 615293dae07b44db79344599c6df1b8769533983 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1776052926 +0900 commit: ♻️ refactor: 공통 지침의 저장소 이름을 gameservice-fe-agent로 변경
|
||||||
|
615293dae07b44db79344599c6df1b8769533983 d9fa54eb2e0d1cefbd1946da978a46d7ab28e6f5 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1776055343 +0900 commit: 📝 docs: README.md의 submodule 설치 및 업데이트 지침 수정
|
||||||
|
d9fa54eb2e0d1cefbd1946da978a46d7ab28e6f5 d9fa54eb2e0d1cefbd1946da978a46d7ab28e6f5 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1776055368 +0900 checkout: moving from master to feature/gil-claude
|
||||||
|
d9fa54eb2e0d1cefbd1946da978a46d7ab28e6f5 8226a7bd16853a9140e636f9399db0f904282f36 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1776056184 +0900 commit: ✨ feat: Claude 작업 방식 및 규칙 문서 추가
|
||||||
|
8226a7bd16853a9140e636f9399db0f904282f36 d9fa54eb2e0d1cefbd1946da978a46d7ab28e6f5 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1776056203 +0900 checkout: moving from feature/gil-claude to master
|
||||||
|
d9fa54eb2e0d1cefbd1946da978a46d7ab28e6f5 c58d698df6c7a431125a58ec60c636f541f7d447 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1776056472 +0900 commit: 📝 docs: .gitignore 자동 추가 및 설치 스크립트 수정
|
||||||
|
c58d698df6c7a431125a58ec60c636f541f7d447 fb31c8d7e52e7992a05ac2a0163b1a78f04c656b “hyeonggkim” <“hyeonggkim@smilegate.com”> 1776057718 +0900 commit: 🔧 chore: pre-commit 훅 추가하여 .claude/common 변경 방지
|
||||||
|
fb31c8d7e52e7992a05ac2a0163b1a78f04c656b 8226a7bd16853a9140e636f9399db0f904282f36 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1776067305 +0900 checkout: moving from master to feature/gil-claude
|
||||||
11
.git copy/logs/refs/heads/dev
Normal file
11
.git copy/logs/refs/heads/dev
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
0000000000000000000000000000000000000000 cec4bb67714f2393d5dee7932807e839a83ff919 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775540245 +0900 branch: Created from origin/dev
|
||||||
|
cec4bb67714f2393d5dee7932807e839a83ff919 d399b8d0650df404b4afba6418213dfa8c9d76c0 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775540349 +0900 commit: chore: add environment configuration file with access tokens
|
||||||
|
d399b8d0650df404b4afba6418213dfa8c9d76c0 d3412a082f7fa135e8e5884bae4bef36d8cefe7f “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775540376 +0900 merge feature/mr: Merge made by the 'ort' strategy.
|
||||||
|
d3412a082f7fa135e8e5884bae4bef36d8cefe7f 59599f3a6f69102e7d4c17a81b776a2c7c822a79 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775542829 +0900 commit: chore: 환경 변수 파일의 액세스 토큰 초기화
|
||||||
|
59599f3a6f69102e7d4c17a81b776a2c7c822a79 8260e959df8725ccf396fc30004fdb79cc7178f4 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775543555 +0900 merge feature/mr: Merge made by the 'ort' strategy.
|
||||||
|
8260e959df8725ccf396fc30004fdb79cc7178f4 a7666613f6d963f59550b108203dbfd8066a1053 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775553148 +0900 commit: 🔧 chore: 환경변수 파일명 .env.local에서 .env.secret으로 변경
|
||||||
|
a7666613f6d963f59550b108203dbfd8066a1053 2465c27f6bf68b8254d5bb2984625dc0cb2f0a00 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775553162 +0900 commit: 📝 docs: README.md 전면 개편 - 메타 저장소 정체성 명확화
|
||||||
|
2465c27f6bf68b8254d5bb2984625dc0cb2f0a00 d0202aa8f8d562d15a39c05b9ac1116ff6599892 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775553173 +0900 commit: ✨ feat: Nuxt 4 프로젝트 생성 표준 문서 추가
|
||||||
|
d0202aa8f8d562d15a39c05b9ac1116ff6599892 dc2de13801cbf8fb31dd0107a39c9f24de9727d3 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775553181 +0900 commit: 🔧 chore: Claude 설정 권한 업데이트 - 추가 Git 명령어 허용
|
||||||
|
dc2de13801cbf8fb31dd0107a39c9f24de9727d3 01aea986a2c7986da0be08337df28f8b767f7772 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775553254 +0900 commit: 🔥 chore: 환경변수 파일 삭제 (.env.local)
|
||||||
|
01aea986a2c7986da0be08337df28f8b767f7772 518884e472c00404a4e94112d3103f3b8401d78b “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775553272 +0900 commit: 🔧 chore: Claude 설정에 git rm 명령어 권한 추가
|
||||||
2
.git copy/logs/refs/heads/feature/gil-claude
Normal file
2
.git copy/logs/refs/heads/feature/gil-claude
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
0000000000000000000000000000000000000000 d9fa54eb2e0d1cefbd1946da978a46d7ab28e6f5 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1776055368 +0900 branch: Created from HEAD
|
||||||
|
d9fa54eb2e0d1cefbd1946da978a46d7ab28e6f5 8226a7bd16853a9140e636f9399db0f904282f36 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1776056184 +0900 commit: ✨ feat: Claude 작업 방식 및 규칙 문서 추가
|
||||||
20
.git copy/logs/refs/heads/feature/mr
Normal file
20
.git copy/logs/refs/heads/feature/mr
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
0000000000000000000000000000000000000000 2b26f76e2fdfbeb9d14c725b82d299374b402905 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1773983657 +0900 branch: Created from HEAD
|
||||||
|
2b26f76e2fdfbeb9d14c725b82d299374b402905 c3ce56f9934121bda6d271c9cc71c52b700e8213 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1773983669 +0900 commit: Add CLAUDE.md for project guidance and workflow documentation
|
||||||
|
c3ce56f9934121bda6d271c9cc71c52b700e8213 dbccdfc3287e0ed5f5b11c9a2b2ff902d2346073 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1773986257 +0900 commit: feat: 개발 지침 README.md 추가
|
||||||
|
dbccdfc3287e0ed5f5b11c9a2b2ff902d2346073 039532dc7223b0ad448f3be4f966339703bac5a7 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1774265735 +0900 commit: feat: Add CI configuration and various Claude agents for Nuxt development
|
||||||
|
039532dc7223b0ad448f3be4f966339703bac5a7 5680ba2679cd631e4cde8b8e80771a90406b5cf8 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1774265900 +0900 commit: feat: 커밋 메시지 작성 규칙 문서화
|
||||||
|
5680ba2679cd631e4cde8b8e80771a90406b5cf8 ea634db13c0c30072ff93a39971c6168519b7726 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1774267241 +0900 commit: feat: CI 설정에서 Node.js 버전 변경 및 Claude 도구 허용 목록 업데이트
|
||||||
|
ea634db13c0c30072ff93a39971c6168519b7726 ac9aaf5cf918c1d7656e5013c7afa71a6401e1a2 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1774267399 +0900 commit: feat: CI 설정에 glab 설치 및 인증 추가
|
||||||
|
ac9aaf5cf918c1d7656e5013c7afa71a6401e1a2 beca607e133b86ca0af19a1a58bc47f95758e8c3 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1774267525 +0900 commit: feat: CI 스크립트에서 Claude 실행 결과를 파일에 기록하고 종료 코드 처리 추가
|
||||||
|
beca607e133b86ca0af19a1a58bc47f95758e8c3 35e091bcf46f13986f699ed02701a606cf9682ca “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775025939 +0900 commit: 📝 docs: CLAUDE.md 개선 및 Claude 명령어 구조 재정리
|
||||||
|
35e091bcf46f13986f699ed02701a606cf9682ca f377091cf2af1567b9a6120d09bed118e861197f “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775108606 +0900 commit: ✨ feat: Jira 통합 기능 및 SWV 이슈 생성 스킬 추가 [SWV-955]
|
||||||
|
f377091cf2af1567b9a6120d09bed118e861197f 5ff91ac071f3f39cc29194db8407609fd8454bfe “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775108689 +0900 commit (amend): ✨ feat: [SWV-955] Jira 통합 기능 및 SWV 이슈 생성 스킬 추가
|
||||||
|
5ff91ac071f3f39cc29194db8407609fd8454bfe e3a46e022cc220ef47bdbb8a73b92a2920d6b80f “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775110010 +0900 commit: 📝 docs: [SWV-956] Jira 스킬 문서 개선 및 실제 동작 검증
|
||||||
|
e3a46e022cc220ef47bdbb8a73b92a2920d6b80f 8c0bda779a565acc3975001ed39ad54c21759846 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775111878 +0900 commit: ✨ feat: [SWV-955] Confluence 업무일지 작성 스킬 추가
|
||||||
|
8c0bda779a565acc3975001ed39ad54c21759846 5942c2b4500e2356ca226b135c52e07bf467909d “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775540046 +0900 commit: 📝 docs: CLAUDE.md 한글화 및 Nuxt 4 전용 가이드 업데이트
|
||||||
|
5942c2b4500e2356ca226b135c52e07bf467909d d298956a8ee0be1de07fe689e91de1b2ca4b2020 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775540095 +0900 commit: ♻️ refactor: Claude 스킬 및 에이전트 구조 개선
|
||||||
|
d298956a8ee0be1de07fe689e91de1b2ca4b2020 ba6f61aa52bf3a411b5d7e04dcd0136a842f9cb9 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775540102 +0900 commit: 🔧 chore: Claude 설정 권한 및 도구 추가
|
||||||
|
ba6f61aa52bf3a411b5d7e04dcd0136a842f9cb9 4087bcf09dc957d9250341ac14aff85b9953c9c0 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775540163 +0900 commit: 🙈 chore: .gitignore 파일 추가
|
||||||
|
4087bcf09dc957d9250341ac14aff85b9953c9c0 afffbdbf8f55b41d0f97252c112b79de2388bf95 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775540228 +0900 commit: feat: Nuxt FE AI 표준화 로드맵 HTML 파일 추가
|
||||||
|
afffbdbf8f55b41d0f97252c112b79de2388bf95 d3412a082f7fa135e8e5884bae4bef36d8cefe7f “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775542728 +0900 merge dev: Fast-forward
|
||||||
|
d3412a082f7fa135e8e5884bae4bef36d8cefe7f 3487fa20c1cc0520b8716cc89dec097a85acbb4b “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775543513 +0900 commit: chore: 환경 변수 파일의 액세스 토큰 초기화
|
||||||
2
.git copy/logs/refs/heads/main
Normal file
2
.git copy/logs/refs/heads/main
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
0000000000000000000000000000000000000000 2b26f76e2fdfbeb9d14c725b82d299374b402905 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1773897879 +0900 clone: from https://git.sginfra.net/sgp-web-d/gameservice-fe-agent.git
|
||||||
|
2b26f76e2fdfbeb9d14c725b82d299374b402905 2f4532815e800742b8ebfaf3d7fdf8a4887c3db1 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775540392 +0900 pull --tags origin main: Fast-forward
|
||||||
6
.git copy/logs/refs/heads/master
Normal file
6
.git copy/logs/refs/heads/master
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
0000000000000000000000000000000000000000 2f4532815e800742b8ebfaf3d7fdf8a4887c3db1 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1776045888 +0900 branch: Created from HEAD
|
||||||
|
2f4532815e800742b8ebfaf3d7fdf8a4887c3db1 9e2c7cd1837f24e18d800ad89bca6d7df29e9e3c “hyeonggkim” <“hyeonggkim@smilegate.com”> 1776045956 +0900 commit: ✨ feat: 공통 Claude 지침 및 규칙 문서 추가
|
||||||
|
9e2c7cd1837f24e18d800ad89bca6d7df29e9e3c 615293dae07b44db79344599c6df1b8769533983 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1776052926 +0900 commit: ♻️ refactor: 공통 지침의 저장소 이름을 gameservice-fe-agent로 변경
|
||||||
|
615293dae07b44db79344599c6df1b8769533983 d9fa54eb2e0d1cefbd1946da978a46d7ab28e6f5 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1776055343 +0900 commit: 📝 docs: README.md의 submodule 설치 및 업데이트 지침 수정
|
||||||
|
d9fa54eb2e0d1cefbd1946da978a46d7ab28e6f5 c58d698df6c7a431125a58ec60c636f541f7d447 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1776056472 +0900 commit: 📝 docs: .gitignore 자동 추가 및 설치 스크립트 수정
|
||||||
|
c58d698df6c7a431125a58ec60c636f541f7d447 fb31c8d7e52e7992a05ac2a0163b1a78f04c656b “hyeonggkim” <“hyeonggkim@smilegate.com”> 1776057718 +0900 commit: 🔧 chore: pre-commit 훅 추가하여 .claude/common 변경 방지
|
||||||
1
.git copy/logs/refs/remotes/origin/HEAD
Normal file
1
.git copy/logs/refs/remotes/origin/HEAD
Normal file
@@ -0,0 +1 @@
|
|||||||
|
0000000000000000000000000000000000000000 2b26f76e2fdfbeb9d14c725b82d299374b402905 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1773897879 +0900 clone: from https://git.sginfra.net/sgp-web-d/gameservice-fe-agent.git
|
||||||
6
.git copy/logs/refs/remotes/origin/dev
Normal file
6
.git copy/logs/refs/remotes/origin/dev
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
0000000000000000000000000000000000000000 cec4bb67714f2393d5dee7932807e839a83ff919 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1774265716 +0900 fetch: storing head
|
||||||
|
cec4bb67714f2393d5dee7932807e839a83ff919 d399b8d0650df404b4afba6418213dfa8c9d76c0 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775540353 +0900 update by push
|
||||||
|
d399b8d0650df404b4afba6418213dfa8c9d76c0 d3412a082f7fa135e8e5884bae4bef36d8cefe7f “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775540381 +0900 update by push
|
||||||
|
d3412a082f7fa135e8e5884bae4bef36d8cefe7f 59599f3a6f69102e7d4c17a81b776a2c7c822a79 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775542831 +0900 update by push
|
||||||
|
59599f3a6f69102e7d4c17a81b776a2c7c822a79 8260e959df8725ccf396fc30004fdb79cc7178f4 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775543576 +0900 update by push
|
||||||
|
8260e959df8725ccf396fc30004fdb79cc7178f4 518884e472c00404a4e94112d3103f3b8401d78b “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775553292 +0900 update by push
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
0000000000000000000000000000000000000000 8260e959df8725ccf396fc30004fdb79cc7178f4 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775550920 +0900 fetch: storing head
|
||||||
13
.git copy/logs/refs/remotes/origin/feature/mr
Normal file
13
.git copy/logs/refs/remotes/origin/feature/mr
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
0000000000000000000000000000000000000000 c3ce56f9934121bda6d271c9cc71c52b700e8213 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1773983722 +0900 update by push
|
||||||
|
c3ce56f9934121bda6d271c9cc71c52b700e8213 dbccdfc3287e0ed5f5b11c9a2b2ff902d2346073 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1773986265 +0900 update by push
|
||||||
|
dbccdfc3287e0ed5f5b11c9a2b2ff902d2346073 039532dc7223b0ad448f3be4f966339703bac5a7 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1774265739 +0900 update by push
|
||||||
|
039532dc7223b0ad448f3be4f966339703bac5a7 5680ba2679cd631e4cde8b8e80771a90406b5cf8 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1774265904 +0900 update by push
|
||||||
|
5680ba2679cd631e4cde8b8e80771a90406b5cf8 ea634db13c0c30072ff93a39971c6168519b7726 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1774267244 +0900 update by push
|
||||||
|
ea634db13c0c30072ff93a39971c6168519b7726 ac9aaf5cf918c1d7656e5013c7afa71a6401e1a2 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1774267402 +0900 update by push
|
||||||
|
ac9aaf5cf918c1d7656e5013c7afa71a6401e1a2 beca607e133b86ca0af19a1a58bc47f95758e8c3 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1774267528 +0900 update by push
|
||||||
|
beca607e133b86ca0af19a1a58bc47f95758e8c3 35e091bcf46f13986f699ed02701a606cf9682ca “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775025964 +0900 update by push
|
||||||
|
35e091bcf46f13986f699ed02701a606cf9682ca 5ff91ac071f3f39cc29194db8407609fd8454bfe “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775108765 +0900 update by push
|
||||||
|
5ff91ac071f3f39cc29194db8407609fd8454bfe e3a46e022cc220ef47bdbb8a73b92a2920d6b80f “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775110016 +0900 update by push
|
||||||
|
e3a46e022cc220ef47bdbb8a73b92a2920d6b80f 8c0bda779a565acc3975001ed39ad54c21759846 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775111889 +0900 update by push
|
||||||
|
8c0bda779a565acc3975001ed39ad54c21759846 afffbdbf8f55b41d0f97252c112b79de2388bf95 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775540232 +0900 update by push
|
||||||
|
afffbdbf8f55b41d0f97252c112b79de2388bf95 3487fa20c1cc0520b8716cc89dec097a85acbb4b “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775543516 +0900 update by push
|
||||||
2
.git copy/logs/refs/remotes/origin/main
Normal file
2
.git copy/logs/refs/remotes/origin/main
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
2b26f76e2fdfbeb9d14c725b82d299374b402905 cec4bb67714f2393d5dee7932807e839a83ff919 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1773986743 +0900 fetch: fast-forward
|
||||||
|
cec4bb67714f2393d5dee7932807e839a83ff919 2f4532815e800742b8ebfaf3d7fdf8a4887c3db1 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1774509225 +0900 fetch: fast-forward
|
||||||
6
.git copy/logs/refs/remotes/origin/master
Normal file
6
.git copy/logs/refs/remotes/origin/master
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
0000000000000000000000000000000000000000 cec4bb67714f2393d5dee7932807e839a83ff919 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1774265716 +0900 fetch: storing head
|
||||||
|
cec4bb67714f2393d5dee7932807e839a83ff919 9e2c7cd1837f24e18d800ad89bca6d7df29e9e3c “hyeonggkim” <“hyeonggkim@smilegate.com”> 1776045969 +0900 update by push
|
||||||
|
9e2c7cd1837f24e18d800ad89bca6d7df29e9e3c 615293dae07b44db79344599c6df1b8769533983 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1776052929 +0900 update by push
|
||||||
|
615293dae07b44db79344599c6df1b8769533983 d9fa54eb2e0d1cefbd1946da978a46d7ab28e6f5 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1776055346 +0900 update by push
|
||||||
|
d9fa54eb2e0d1cefbd1946da978a46d7ab28e6f5 c58d698df6c7a431125a58ec60c636f541f7d447 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1776056476 +0900 update by push
|
||||||
|
c58d698df6c7a431125a58ec60c636f541f7d447 fb31c8d7e52e7992a05ac2a0163b1a78f04c656b “hyeonggkim” <“hyeonggkim@smilegate.com”> 1776057721 +0900 update by push
|
||||||
2
.git copy/logs/refs/remotes/origin/sandbox
Normal file
2
.git copy/logs/refs/remotes/origin/sandbox
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
0000000000000000000000000000000000000000 cec4bb67714f2393d5dee7932807e839a83ff919 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1774265716 +0900 fetch: storing head
|
||||||
|
cec4bb67714f2393d5dee7932807e839a83ff919 d4bf89ec028715943f4cc66e1a2ee7f56f555eea “hyeonggkim” <“hyeonggkim@smilegate.com”> 1774315580 +0900 fetch: fast-forward
|
||||||
BIN
.git copy/objects/00/4d0533e0a5fc55bb136d23962858b3a4ad08b4
Normal file
BIN
.git copy/objects/00/4d0533e0a5fc55bb136d23962858b3a4ad08b4
Normal file
Binary file not shown.
BIN
.git copy/objects/01/aea986a2c7986da0be08337df28f8b767f7772
Normal file
BIN
.git copy/objects/01/aea986a2c7986da0be08337df28f8b767f7772
Normal file
Binary file not shown.
BIN
.git copy/objects/01/d04b82b5fdc530859fdad624b0d5f4f198c5e8
Normal file
BIN
.git copy/objects/01/d04b82b5fdc530859fdad624b0d5f4f198c5e8
Normal file
Binary file not shown.
BIN
.git copy/objects/03/9532dc7223b0ad448f3be4f966339703bac5a7
Normal file
BIN
.git copy/objects/03/9532dc7223b0ad448f3be4f966339703bac5a7
Normal file
Binary file not shown.
BIN
.git copy/objects/04/8ba2ddfcaa184374be2c2b0bb4cb509d30ab99
Normal file
BIN
.git copy/objects/04/8ba2ddfcaa184374be2c2b0bb4cb509d30ab99
Normal file
Binary file not shown.
BIN
.git copy/objects/04/cdf07fc2a77394b60269f1cb938a3aa566157f
Normal file
BIN
.git copy/objects/04/cdf07fc2a77394b60269f1cb938a3aa566157f
Normal file
Binary file not shown.
BIN
.git copy/objects/07/71a34554de4f33b8a4aed1895dc2d03942f478
Normal file
BIN
.git copy/objects/07/71a34554de4f33b8a4aed1895dc2d03942f478
Normal file
Binary file not shown.
BIN
.git copy/objects/07/c2bbdddcb3e93a1784bb764da0b413448043ea
Normal file
BIN
.git copy/objects/07/c2bbdddcb3e93a1784bb764da0b413448043ea
Normal file
Binary file not shown.
BIN
.git copy/objects/08/1051ac3ab9000c7dde194e2ffd9d4cf0730018
Normal file
BIN
.git copy/objects/08/1051ac3ab9000c7dde194e2ffd9d4cf0730018
Normal file
Binary file not shown.
BIN
.git copy/objects/09/48b082480995fde784743d5a9e7bb7ddf01595
Normal file
BIN
.git copy/objects/09/48b082480995fde784743d5a9e7bb7ddf01595
Normal file
Binary file not shown.
BIN
.git copy/objects/0f/bbd7a52350610ce51de54f6b10a3ec1c56ac0f
Normal file
BIN
.git copy/objects/0f/bbd7a52350610ce51de54f6b10a3ec1c56ac0f
Normal file
Binary file not shown.
BIN
.git copy/objects/11/0b65ab43d6b654d9dea6d8a594eb79df8b856b
Normal file
BIN
.git copy/objects/11/0b65ab43d6b654d9dea6d8a594eb79df8b856b
Normal file
Binary file not shown.
BIN
.git copy/objects/11/126603e8d603c8637fa102518d72ca8ef06120
Normal file
BIN
.git copy/objects/11/126603e8d603c8637fa102518d72ca8ef06120
Normal file
Binary file not shown.
BIN
.git copy/objects/11/b446bec9d906e9bb0d4c9cb56db51e8da70eea
Normal file
BIN
.git copy/objects/11/b446bec9d906e9bb0d4c9cb56db51e8da70eea
Normal file
Binary file not shown.
BIN
.git copy/objects/12/9ebb102c3cd36b64bbca5b86b2e60b13e13abe
Normal file
BIN
.git copy/objects/12/9ebb102c3cd36b64bbca5b86b2e60b13e13abe
Normal file
Binary file not shown.
BIN
.git copy/objects/13/e1fdd7435187258735e973a5fece5efa37c75f
Normal file
BIN
.git copy/objects/13/e1fdd7435187258735e973a5fece5efa37c75f
Normal file
Binary file not shown.
BIN
.git copy/objects/13/faff7ef44c09c296a2d07120c7dd1fe31cef70
Normal file
BIN
.git copy/objects/13/faff7ef44c09c296a2d07120c7dd1fe31cef70
Normal file
Binary file not shown.
BIN
.git copy/objects/19/06d6fab0971c53be3a603e2f875aee8e6f08a9
Normal file
BIN
.git copy/objects/19/06d6fab0971c53be3a603e2f875aee8e6f08a9
Normal file
Binary file not shown.
BIN
.git copy/objects/19/0fcd75a2c3eadc84b04ccd93532d153c050d08
Normal file
BIN
.git copy/objects/19/0fcd75a2c3eadc84b04ccd93532d153c050d08
Normal file
Binary file not shown.
BIN
.git copy/objects/1b/84b85053855ad4a08afc19c8933ef19f7f6ba0
Normal file
BIN
.git copy/objects/1b/84b85053855ad4a08afc19c8933ef19f7f6ba0
Normal file
Binary file not shown.
BIN
.git copy/objects/1c/05a9ad9922cdf2b5769bd8087bb404f1fc9398
Normal file
BIN
.git copy/objects/1c/05a9ad9922cdf2b5769bd8087bb404f1fc9398
Normal file
Binary file not shown.
BIN
.git copy/objects/1c/64c793def9b1b448bd5a9014aeec070ad98420
Normal file
BIN
.git copy/objects/1c/64c793def9b1b448bd5a9014aeec070ad98420
Normal file
Binary file not shown.
BIN
.git copy/objects/1d/d5f16838eeb8597f1b40c0919d5f0bab787491
Normal file
BIN
.git copy/objects/1d/d5f16838eeb8597f1b40c0919d5f0bab787491
Normal file
Binary file not shown.
BIN
.git copy/objects/1d/de24a9084d5b2f1be8e5c6c823f1f431d9a996
Normal file
BIN
.git copy/objects/1d/de24a9084d5b2f1be8e5c6c823f1f431d9a996
Normal file
Binary file not shown.
BIN
.git copy/objects/1e/2b006d92310b03afc46d67280945dd68053dc5
Normal file
BIN
.git copy/objects/1e/2b006d92310b03afc46d67280945dd68053dc5
Normal file
Binary file not shown.
BIN
.git copy/objects/1e/30d10ab4bacf6579b3335a8b58da74c0dd9821
Normal file
BIN
.git copy/objects/1e/30d10ab4bacf6579b3335a8b58da74c0dd9821
Normal file
Binary file not shown.
BIN
.git copy/objects/1e/cc3472b10131aa1deac18238b728d134b1b340
Normal file
BIN
.git copy/objects/1e/cc3472b10131aa1deac18238b728d134b1b340
Normal file
Binary file not shown.
BIN
.git copy/objects/21/f4d71ceaaab3cab2de4a18903b09659ab8190b
Normal file
BIN
.git copy/objects/21/f4d71ceaaab3cab2de4a18903b09659ab8190b
Normal file
Binary file not shown.
BIN
.git copy/objects/22/0f5108ec48836acba61c5f9a67211491283053
Normal file
BIN
.git copy/objects/22/0f5108ec48836acba61c5f9a67211491283053
Normal file
Binary file not shown.
BIN
.git copy/objects/22/17d9f3c8c6c4ab9085f955eedb11596de9a24d
Normal file
BIN
.git copy/objects/22/17d9f3c8c6c4ab9085f955eedb11596de9a24d
Normal file
Binary file not shown.
BIN
.git copy/objects/22/99cd0e71e5701479b12072d5c4982520e04c85
Normal file
BIN
.git copy/objects/22/99cd0e71e5701479b12072d5c4982520e04c85
Normal file
Binary file not shown.
BIN
.git copy/objects/23/2fcc5e0c05c0424684e3800ae428a6ad33815c
Normal file
BIN
.git copy/objects/23/2fcc5e0c05c0424684e3800ae428a6ad33815c
Normal file
Binary file not shown.
BIN
.git copy/objects/24/65c27f6bf68b8254d5bb2984625dc0cb2f0a00
Normal file
BIN
.git copy/objects/24/65c27f6bf68b8254d5bb2984625dc0cb2f0a00
Normal file
Binary file not shown.
BIN
.git copy/objects/24/af5b25ac433f9f913b72af2af7f3dec82e20bd
Normal file
BIN
.git copy/objects/24/af5b25ac433f9f913b72af2af7f3dec82e20bd
Normal file
Binary file not shown.
BIN
.git copy/objects/28/8fd78ca2cbc10c1e6e6e350d6593da741dc953
Normal file
BIN
.git copy/objects/28/8fd78ca2cbc10c1e6e6e350d6593da741dc953
Normal file
Binary file not shown.
BIN
.git copy/objects/2a/e0191b0a409aa6f98f1326080ab698aa7a760b
Normal file
BIN
.git copy/objects/2a/e0191b0a409aa6f98f1326080ab698aa7a760b
Normal file
Binary file not shown.
BIN
.git copy/objects/2b/341b603911f0df0fe637ddab9b9999dffa31ec
Normal file
BIN
.git copy/objects/2b/341b603911f0df0fe637ddab9b9999dffa31ec
Normal file
Binary file not shown.
BIN
.git copy/objects/2d/ce6fe40b8364b74f8edab2c4cd894a6a7dd113
Normal file
BIN
.git copy/objects/2d/ce6fe40b8364b74f8edab2c4cd894a6a7dd113
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user