Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 132 additions & 0 deletions .claude/agents/code-reviewer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
---
name: code-reviewer
description: 코드 변경사항 리뷰. 보안/버그/성능 이슈만 지적. "코드 리뷰", "code review", "PR 리뷰" 요청 시 적용.
allowed-tools: Read, Grep, Glob, Bash
model: claude-sonnet-4-20250514
---

# Code Reviewer

## 역할

Git diff 기반으로 변경된 코드를 분석하여 실질적 이슈만 지적하는 서브에이전트입니다.
스타일/포맷 이슈는 ESLint/Prettier가 처리하므로 여기서는 다루지 않습니다.

> 패턴 참조: `~/.claude/skills/gstack/review/SKILL.md` (Fix-First, Scope Drift)
> 보안 참조: `~/.claude/skills/security-auditor/SKILL.md` (OWASP 체크리스트)

## 리뷰 프로세스

### Step 1: 변경 범위 파악

```bash
# 베이스 브랜치 감지
BASE=$(gh pr view --json baseRefName -q .baseRefName 2>/dev/null || echo "main")
git fetch origin $BASE --quiet 2>/dev/null || true

# 변경 파일 목록 + 통계
git diff origin/$BASE...HEAD --name-only --diff-filter=ACMR
git diff origin/$BASE...HEAD --stat
```

### Step 2: Scope Drift 감지

커밋 메시지에서 의도를 파악하고 실제 변경과 비교:

```bash
git log origin/$BASE..HEAD --oneline
```

- **DRIFT**: 의도와 무관한 파일 변경
- **MISSING**: 커밋 메시지에 언급된 요구사항이 diff에 없음
- **CLEAN**: 일치

### Step 3: Two-Pass 리뷰

**Pass 1 — CRITICAL (차단)**

| 카테고리 | 검사 항목 |
|----------|----------|
| 보안 | 하드코딩 시크릿/API 키, `dangerouslySetInnerHTML` 미검증, 인증 누락 (API route에서 세션 체크 없음) |
| 타입 안전성 | `any` 타입, unsafe `as` 단언, nullable 미처리 |
| 버그 | 무한 루프/리렌더, useEffect deps 오류, 비동기 에러 미처리, 메모리 누수 (cleanup 없는 listener/timer) |
| 데이터 | Race condition, 동시성 이슈 |

**Pass 2 — INFORMATIONAL (권장)**

| 카테고리 | 검사 항목 |
|----------|----------|
| 성능 | 매 렌더마다 새 객체/배열, 큰 번들 임포트, `'use client'` 남용 |
| 디자인 시스템 | 직접 색상/spacing 값 (토큰 사용), `lib/design-system/` 컴포넌트 미사용 |
| 접근성 | 키보드 접근성 누락, img alt 없음, label 연결 없음 |
| 코드 품질 | console.log 잔존, 주석 처리된 코드, 빈 catch 블록 |

### Step 4: Fix-First 분류

각 이슈를 분류:
- **AUTO-FIX**: 기계적 수정 가능 → 직접 적용, 한 줄 요약
- **ASK**: 판단 필요 → 모아서 일괄 질문, 승인 후 적용

## decoded 전용 규칙

### 디자인 시스템 컴포넌트 확인

변경 파일에서 다음을 확인:
- `lib/design-system/`에 동일 역할 컴포넌트가 있는데 자체 구현했는지
- 디자인 토큰 (`colors`, `spacing`, `typography`) 대신 직접 값 사용했는지

### 네이밍 컨벤션

| 대상 | 규칙 | 예시 |
|------|------|------|
| 컴포넌트 파일 | PascalCase | `UserProfile.tsx` |
| 훅 파일/함수 | `use` 접두사 | `useProfile.ts` |
| 스토어 | `Store` 접미사 | `authStore.ts` |
| API 라우트 | kebab-case | `app/api/v1/posts/route.ts` |
| 상수 | UPPER_SNAKE_CASE | `MAX_UPLOAD_SIZE` |

### Supabase 쿼리 안전성

- RLS 정책 의존 여부 확인
- `.single()` 사용 시 결과 없을 때 에러 처리
- 인증 필요 쿼리에서 세션 체크

## 참조 파일

- `.planning/codebase/CONVENTIONS.md` — 코딩 컨벤션
- `lib/design-system/` — 디자인 시스템 컴포넌트
- `packages/web/eslint.config.mjs` — ESLint 규칙
- `docs/GIT-WORKFLOW.md` — Git 워크플로우

## 출력 형식

```markdown
## Code Review: N issues (X critical, Y informational)

**Scope**: CLEAN / DRIFT / MISSING
**Intent**: {커밋에서 파악한 의도}
**Delivered**: {실제 변경 요약}

### AUTO-FIXED
- [파일:라인] 문제 → 수정 내용

### CRITICAL (확인 필요)
1. **[파일:라인] 이슈**
- 문제: `코드`
- 권장: `수정`
→ A) Fix B) Skip

### INFORMATIONAL
1. **[파일:라인] 이슈** — 설명

### 긍정적 사항
- 잘 된 패턴 언급
```

## 주의사항

- 변경된 코드만 리뷰 (주변은 컨텍스트 참조만)
- ESLint/Prettier가 잡는 건 건너뛰기
- 과도한 지적 금지 — 실질적 문제만
- 증거 기반 — "아마 문제" 대신 구체적 코드/라인 인용
- 긍정적 사항 반드시 포함
68 changes: 68 additions & 0 deletions .claude/skills/git-workflow/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
---
name: git-workflow
description: >
Git 워크플로우 컨벤션 가이드 및 검증.
"브랜치 이름", "commit convention", "PR 준비", "git workflow" 요청 시 적용.
allowed-tools: Read, Grep, Glob, Bash
model: claude-sonnet-4-20250514
---

# Git Workflow

## 개요

`docs/GIT-WORKFLOW.md`를 기반으로 git 컨벤션을 검증하고 안내합니다.

## 트리거 조건

- "브랜치 이름", "branch naming"
- "커밋 컨벤션", "commit convention"
- "PR 준비", "PR readiness"
- "git workflow", "git 규칙"

## 기능

### 1. 브랜치명 검증

```bash
BRANCH=$(git branch --show-current)
```

허용 접두사: `feat/`, `fix/`, `docs/`, `refactor/`, `chore/`, `test/`, `ci/`

### 2. 커밋 메시지 검증

```bash
git log --oneline -10
```

Conventional Commits 형식 확인:
- `type(scope): description`
- 허용 타입: feat, fix, docs, refactor, test, chore, ci, perf, style

### 3. PR 준비 상태 체크

- [ ] 브랜치명 컨벤션 준수
- [ ] 커밋 메시지 형식 준수
- [ ] pre-push 체크 통과 (`bun run ci:local`)
- [ ] `/review` 코드 리뷰 완료
- [ ] P0 이슈 없음

### 4. 워크플로우 안내

`docs/GIT-WORKFLOW.md`를 참조하여 질문에 답변합니다.

## 참조

- `docs/GIT-WORKFLOW.md` — 팀 워크플로우 source of truth
- `scripts/git-pre-push.sh` — pre-push 훅
- `.claude/agents/code-reviewer.md` — 코드 리뷰 에이전트

## 사용 예시

```
> 현재 브랜치 이름이 컨벤션에 맞는지 확인해줘
> PR 만들기 전 준비 상태 체크해줘
> 커밋 메시지 형식 알려줘
> git workflow 규칙이 뭐야?
```
19 changes: 18 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,9 @@ Located in `lib/design-system/`:
| **Stores** | `lib/stores/` | Zustand stores |
| **Rust API** | `packages/api-server/` | Axum REST API, gRPC client to ai-server |
| **AI / gRPC** | `packages/ai-server/` | Inference, metadata, gRPC (Python) |
| **Frontend CI** | `packages/web/scripts/pre-push.sh` | ESLint, Prettier, TypeScript checks |
| **Git Workflow** | `docs/GIT-WORKFLOW.md` | Branch, commit, PR conventions |
| **Code Reviewer** | `.claude/agents/code-reviewer.md` | decoded 전용 코드 리뷰 에이전트 |

## API Routes

Expand Down Expand Up @@ -400,7 +403,7 @@ bun run dev:api-server # Rust API (cargo watch)
bun run dev:ai-server # Python AI server (uv)
bun run build # Production build (via Turborepo)
bun run lint # ESLint (and package scripts where configured)
bun run ci:local # 로컬 CI (pre-push 와 동일: 프론트 슬롯 + api-server; ai-server 는 RUN_AI_SERVER_CI=1 일 때만)
bun run ci:local # 로컬 CI (pre-push 와 동일: web + api-server; ai-server 는 RUN_AI_SERVER_CI=1 일 때만)
# 훅: 저장소 루트에서 `just hook` → core.hooksPath=.githooks

# Split local dev: Meilisearch·Redis·SearXNG = Docker first, then:
Expand All @@ -418,6 +421,11 @@ bun run dev # Next.js dev server
bun run build # Next.js production build
bun run lint # ESLint
bun run format # Prettier formatting
bun run typecheck # TypeScript (tsc --noEmit)

# Frontend CI만 실행
just ci-web # lint + format + tsc
SKIP_FE_CI=1 git push # 긴급 시 web CI 건너뛰기

# API server (Rust)
cd packages/api-server
Expand All @@ -438,6 +446,15 @@ uv run python -m src.main
- ESLint + Prettier applied
- Conventional Commits format

## Git Workflow

자세한 가이드: [docs/GIT-WORKFLOW.md](docs/GIT-WORKFLOW.md)

- **브랜치**: `feat/`, `fix/`, `docs/`, `refactor/`, `chore/`, `test/`, `ci/` 접두사
- **커밋**: Conventional Commits (`type(scope): description`)
- **PR**: pre-push 통과 + 코드 리뷰 (`/review`) 후 생성
- **main 직접 push 금지**: PR로만 머지

## Important Notes

- Uses bun as package manager with Turborepo — use `bun` commands (not yarn/npm)
Expand Down
6 changes: 5 additions & 1 deletion Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ local-deps-down:
hook:
#!/usr/bin/env bash
set -euo pipefail
chmod +x "{{ repo }}/scripts/git-pre-push.sh" "{{ repo }}/.githooks/pre-push" "{{ repo }}/packages/ai-server/scripts/pre-push.sh"
chmod +x "{{ repo }}/scripts/git-pre-push.sh" "{{ repo }}/.githooks/pre-push" "{{ repo }}/packages/ai-server/scripts/pre-push.sh" "{{ repo }}/packages/web/scripts/pre-push.sh"
git -C "{{ repo }}" config core.hooksPath .githooks
echo "OK: git config core.hooksPath=.githooks (repo: {{ repo }})"

Expand All @@ -42,3 +42,7 @@ local-help:
@echo "전체 한 터미널: bun run dev (turbo, 로그 한 스트림)"
@echo "push 전 로컬 CI: just hook 후 bun run ci:local (또는 git push 가 훅 실행)"

# Web 프론트엔드 로컬 CI (lint + format + tsc)
ci-web:
bash "{{ repo }}/packages/web/scripts/pre-push.sh"

124 changes: 124 additions & 0 deletions docs/GIT-WORKFLOW.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# Git Workflow

decoded 팀 git 워크플로우 가이드. 이 문서가 source of truth입니다.

## 브랜치 네이밍

| 접두사 | 용도 | 예시 |
|--------|------|------|
| `feat/` | 새 기능 | `feat/vton-modal` |
| `fix/` | 버그 수정 | `fix/infinite-scroll-crash` |
| `docs/` | 문서 | `docs/api-guide` |
| `refactor/` | 리팩토링 | `refactor/auth-store` |
| `chore/` | 유지보수 | `chore/upgrade-eslint-10` |
| `test/` | 테스트 추가 | `test/usePosts-unit` |
| `ci/` | CI/CD 변경 | `ci/frontend-pre-push` |

## 커밋 컨벤션

Conventional Commits 형식을 사용합니다.

```
type(scope): description
```

### 타입

| 타입 | 설명 |
|------|------|
| `feat` | 새 기능 |
| `fix` | 버그 수정 |
| `docs` | 문서 변경 |
| `refactor` | 리팩토링 (동작 변경 없음) |
| `test` | 테스트 추가/수정 |
| `chore` | 빌드, 의존성, 설정 |
| `ci` | CI/CD 변경 |
| `perf` | 성능 개선 |
| `style` | 포맷팅 (동작 변경 없음) |

### Scope

패키지 또는 기능 이름: `web`, `api-server`, `ai-server`, `shared`, `auth`, `feed`, `vton` 등

### 예시

```
feat(web): add virtual try-on modal with lazy loading
fix(api-server): handle null user_id in badge calculation
docs(shared): update Supabase query usage guide
chore(web): upgrade React Query to v5.90
ci: add frontend pre-push hook with ESLint and tsc
```

## PR 컨벤션

### 제목

커밋 컨벤션과 동일한 형식:
```
type(scope): short description
```

### 설명 템플릿

```markdown
## Summary
- 변경 사항 1-3줄 요약

## Changes
- 구체적 변경 내용 리스트

## Test Plan
- [ ] 테스트 항목 1
- [ ] 테스트 항목 2
```

## Pre-push 체크

### 설치 (최초 1회)

```bash
just hook
# 또는: git config core.hooksPath .githooks
```

### 체크 항목

| 패키지 | 체크 | 기본 동작 |
|--------|------|-----------|
| **web** | ESLint → Prettier → TypeScript | 항상 실행 |
| **api-server** | fmt → clippy → test → deny → tarpaulin → migration-sync | 항상 실행 |
| **ai-server** | flake8 → black → pytest | `RUN_AI_SERVER_CI=1`일 때만 |

### 스킵 (긴급 시)

```bash
SKIP_FE_CI=1 git push # web만 스킵
SKIP_AI_SERVER_CI=1 git push # ai-server만 스킵
SKIP_FE_CI=1 SKIP_AI_SERVER_CI=1 git push # 둘 다 스킵
```

### 수동 실행

```bash
bun run ci:local # 전체 (push 훅과 동일)
just ci-web # web만
```

## Main 브랜치 보호

- **직접 push 금지**: pre-push 훅이 `main`/`master` push를 차단
- **PR 머지만 허용**: 브랜치 → PR → 리뷰 → 머지

## 리뷰 프로세스

1. 브랜치에서 작업 완료
2. `/review` 실행 — Claude code-reviewer로 자동 리뷰
3. P0(차단 이슈) 모두 해결
4. PR 생성
5. 팀원 리뷰
6. 승인 후 머지

## 릴리스 플로우

현재는 main 머지 시 자동 배포 (Vercel). 별도 릴리스 브랜치 없음.
1 change: 1 addition & 0 deletions packages/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"lint": "eslint app lib",
"format": "prettier --write .",
"format:check": "prettier --check .",
"typecheck": "tsc --noEmit",
"test:visual": "playwright test tests/visual-qa.spec.ts"
},
"dependencies": {
Expand Down
Loading