🎉 init: Nuxt 프로젝트를 위한 공통 지침 및 스크립트 추가

This commit is contained in:
hyeonggil
2026-04-19 20:44:32 +09:00
commit 5ccb27f86e
337 changed files with 3191 additions and 0 deletions

View 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를 확인할 수 있도록 단계별로 진행합니다.
## 질문이 필요한 상황
다음의 경우 반드시 사용자에게 확인을 요청합니다.
- 요구사항의 일부가 불명확할 때
- 여러 구현 방식이 있고 각각 장단점이 뚜렷할 때
- 공통 지침과 프로젝트 지침이 충돌할 때
- 파괴적 작업(파일 삭제, 데이터 마이그레이션, 스키마 변경 등)이 필요할 때
- 외부 서비스 호출이나 결제 관련 작업일 때

View 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는 각 그룹 내에서 별도 블록으로 분리
그룹 사이에는 빈 줄을 한 줄 둡니다.

View 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 실패가 있어도 괜찮습니다.

View 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
View 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
View 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
View 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
View 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'"

View File

@@ -0,0 +1,8 @@
{
"permissions": {
"allow": [
"mcp__wiki__get_page_by_id",
"mcp__wiki__update_page"
]
}
}

52
.claude/skills/README.md Normal file
View 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` 실행

View 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 는 사용자가 요청할 때만 추가한다.

View 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` — 전체 검수 체크리스트 (시각적/기능/스팸)

View 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.

View 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

View 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>
&nbsp;|&nbsp;
<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;">&nbsp;</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;">&nbsp;</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>
```

View 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()

View 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 프리셋과 다름
- ...
### ✅ 좋은 점
- 간단한 컴포넌트에 잘 맞는 단일 책임 구조
- ...
```
## 주의사항
- 사용자가 리팩토링을 **요청하지 않은 경우** 코드를 직접 수정하지 말고 리뷰만 수행한다.
- 프로젝트 지침과 공통 지침이 충돌하면 프로젝트 지침을 따르되, 차이를 사용자에게 알린다.
- 실제 코드 동작 변경(기능 수정)은 리뷰 범위가 아니다. 별도 작업으로 분리 제안한다.

View File

@@ -0,0 +1,9 @@
# <프로젝트 이름>
## 공통 지침
@.claude/common/CLAUDE.md
## 프로젝트 지침
@.claude/project/overview.md
@.claude/project/conventions.md
@.claude/project/architecture.md

View 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 정책이 있다면 함께 기술

View 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__ 폴더>
- 최소 커버리지: <숫자>

View 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
View 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
View 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
View File

@@ -0,0 +1 @@
🔧 chore: pre-commit 훅 추가하여 .claude/common 변경 방지

6
.git copy/FETCH_HEAD Normal file
View 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
View File

@@ -0,0 +1 @@
ref: refs/heads/feature/gil-claude

1
.git copy/ORIG_HEAD Normal file
View File

@@ -0,0 +1 @@
fb31c8d7e52e7992a05ac2a0163b1a78f04c656b

29
.git copy/config Normal file
View 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

View File

@@ -0,0 +1 @@
{"version":4,"git_revision":1}

1
.git copy/description Normal file
View File

@@ -0,0 +1 @@
Unnamed repository; edit this file 'description' to name the repository.

14
.git copy/gk/config Normal file
View 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

View 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+"$@"}
:

View 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
}

View 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;
}

View 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

View 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+"$@"}
:

View 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 --

View 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
View 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
View 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

View 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

View 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

View 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

View 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
View 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

Binary file not shown.

6
.git copy/info/exclude Normal file
View 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
View 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

View 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 명령어 권한 추가

View 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 작업 방식 및 규칙 문서 추가

View 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: 환경 변수 파일의 액세스 토큰 초기화

View 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

View 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 변경 방지

View 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

View 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

View File

@@ -0,0 +1 @@
0000000000000000000000000000000000000000 8260e959df8725ccf396fc30004fdb79cc7178f4 “hyeonggkim” <“hyeonggkim@smilegate.com”> 1775550920 +0900 fetch: storing head

View 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

View 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

View 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

View 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

Some files were not shown because too many files have changed in this diff Show More