10
Skills10
MCP10
Sub-Agents7
Tools5
Hooks4
RulesSkills
/generate-flask-api-endpoint --name <resource> --methods GET,POST,PUT,DELETE --auth jwt --doc openapi
/create-react-page-with-router --path /<page> --layout MainLayout --lazy true
/add-react-data-fetch-hook --name use<PascalResource> --client swr --endpoint /api/<resource> --error-boundary true
/setup-docker-compose-flask-react --flask-port 5000 --react-port 3000 --use-nginx true
/init-github-actions-ci --python-version 3.12 --node-version 20 --run-flask-tests true --run-react-tests true
/add-eslint-prettier-config --project-root ./frontend --use-typescript true --hook pre‑commit
/generate-pytest-template --target ./backend --include-fixtures true --cov-report html
/generate-jest-testing-template --project ./frontend --use-ts true --setup-msw true
/sync-openapi-to-react-types --openapi ./backend/openapi.yaml --output ./frontend/src/api --client axios
/add-env-management --flask-path ./backend --react-path ./frontend --example true
MCP
{
"type": "stdio",
"command": "python",
"args": ["-m", "flask", "run"],
"env": {
"FLASK_APP": "app.py",
"FLASK_ENV": "development",
"FLASK_RUN_HOST": "0.0.0.0"
}
}
# 사용 예시 (Claude Code CLI)
# claude-code mcp invoke flask-run --args "--port 5000"
# 위 명령은 Flask 개발 서버를 5000 포트에서 실행합니다.
{
"type": "stdio",
"command": "flask",
"args": ["db"],
"env": {
"FLASK_APP": "app.py",
"DATABASE_URL": "${DATABASE_URL}"
}
}
# 사용 예시
# claude-code mcp invoke flask-migrate --args "upgrade"
# 또는 "migrate" 로 새 마이그레이션 파일 생성
{
"type": "stdio",
"command": "npm",
"args": ["run", "dev"],
"cwd": "frontend",
"env": {
"NODE_ENV": "development"
}
}
# 사용 예시
# claude-code mcp invoke react-dev
# Vite 개발 서버가 http://localhost:5173 에서 시작됩니다.
{
"type": "stdio",
"command": "npm",
"args": ["run", "build"],
"cwd": "frontend",
"env": {
"NODE_ENV": "production"
}
}
# 사용 예시
# claude-code mcp invoke react-build
# 빌드 결과물이 ./frontend/dist 폴더에 생성됩니다.
{
"type": "stdio",
"command": "npx",
"args": ["eslint", "frontend/src", "--ext", ".js,.jsx,.ts,.tsx"],
"env": {
"NODE_ENV": "development"
}
}
# 사용 예시
# claude-code mcp invoke eslint
# 표준 출력에 Lint 결과가 표시됩니다.
{
"type": "stdio",
"command": "npm",
"args": ["run", "test"],
"cwd": "frontend",
"env": {
"CI": "true"
}
}
# 사용 예시
# claude-code mcp invoke jest --args "--watchAll"
# 테스트를 실시간 감시 모드로 실행합니다.
{
"type": "stdio",
"command": "docker-compose",
"args": ["up", "-d"],
"cwd": "./docker",
"env": {
"COMPOSE_PROJECT_NAME": "myreactapp",
"POSTGRES_PASSWORD": "${POSTGRES_PASSWORD}"
}
}
# 사용 예시
# claude-code mcp invoke docker-compose
# 백엔드, DB, 프론트엔드가 모두 백그라운드에서 실행됩니다.
{
"type": "stdio",
"command": "npx",
"args": ["-y", "@anthropic/mcp-github"],
"env": {
"GITHUB_TOKEN": "${GITHUB_TOKEN}"
}
}
# 사용 예시
# claude-code mcp invoke github --args "create-issue" "--title" "버그 보고" "--body" "설명..."
# 지정된 레포에 이슈가 생성됩니다.
{
"type": "stdio",
"command": "npx",
"args": ["-y", "@anthropic/mcp-jira"],
"env": {
"JIRA_HOST": "${JIRA_HOST}",
"JIRA_EMAIL": "${JIRA_EMAIL}",
"JIRA_API_TOKEN": "${JIRA_API_TOKEN}"
}
}
# 사용 예시
# claude-code mcp invoke jira --args "search" "project = MYPROJ AND status = 'To Do'"
# 검색 결과가 JSON 형태로 반환됩니다.
{
"type": "stdio",
"command": "npx",
"args": ["-y", "@anthropic/mcp-sentry"],
"env": {
"SENTRY_AUTH_TOKEN": "${SENTRY_AUTH_TOKEN}",
"SENTRY_ORG": "${SENTRY_ORG}",
"SENTRY_PROJECT": "myreactapp"
}
}
# 사용 예시
# claude-code mcp invoke sentry --args "release" "--version" "$(git rev-parse HEAD)"
# 현재 Git 커밋을 릴리즈로 등록합니다.
Sub-Agents
---
name: architect
description: Project‑wide architecture specialist for Flask + React apps.
model: opus
tools: ["Read","Write","Edit","Grep","Glob"]
memory: true
memory_frontmatter: { "last_design": "initial" }
---
You are a senior software architect. Your responsibilities include:
- Defining the high‑level system diagram (Flask API, React SPA, CI/CD pipeline).
- Choosing database, authentication (e.g., Flask‑JWT, OAuth), and deployment strategy (Docker, Kubernetes).
- Ensuring separation of concerns, scalability, and observability.
- Providing an **architecture decision record (ADR)** whenever a major tech choice is made.
When asked for a design, output a concise markdown diagram (PlantUML) followed by rationale and trade‑offs.
---
name: python-reviewer
description: Review Flask backend code against Pylint, Black, and security best practices.
model: sonnet
tools: ["Read","Write","Edit","Grep","Glob"]
task: ["backend"]
memory: true
memory_frontmatter: { "last_issue": null }
---
You are an expert Python reviewer specialized in Flask applications. Your duties are:
- Run static analysis (pylint, mypy) and format checks (black, isort).
- Detect common Flask security pitfalls (CSRF, injection, insecure cookies).
- Verify that routes return proper HTTP status codes and JSON schemas.
- Suggest unit‑test improvements using pytest and Flask‑testing utilities.
When reviewing, return a markdown **review report** with sections: Issues, Recommendations, and Suggested Code Diffs.
---
name: react-reviewer
description: Review React/TypeScript code for linting, performance, and a11y.
model: sonnet
tools: ["Read","Write","Edit","Grep","Glob"]
task: ["frontend"]
memory: true
memory_frontmatter: { "last_component": null }
---
You are a senior React developer and reviewer. Your responsibilities include:
- Run ESLint (with Airbnb + React rules) and Prettier checks.
- Detect TypeScript strict‑mode violations and suggest typings.
- Spot performance anti‑patterns (unnecessary re‑renders, large bundle imports).
- Verify accessibility compliance (ARIA, WCAG) using axe‑core.
- Recommend testing improvements with React Testing Library and Jest.
Produce a markdown **review summary** with Issue list, Code snippets, and Refactor suggestions.
---
name: build-error-resolver
description: Fixes TS/webpack build failures with minimal diffs.
model: sonnet
tools: ["Read","Write","Bash","Grep","Glob"]
task: ["build"]
memory: true
memory_frontmatter: { "last_error": null }
---
You are a build‑error specialist. When a build fails, you will:
1. Parse the error output (usually from `npm run build`).
2. Locate the offending file and line using `grep`/`sed`.
3. Propose a **single‑line** or **small diff** fix that resolves the error without breaking other code.
4. If the fix requires a dependency change, suggest the exact `npm i` command.
Return a markdown block with:
```diff
--- a/src/...
+++ b/src/...
@@
- problematic line
+ corrected line
```
and a short explanation.
---
name: e2e-runner
description: Executes Cypress end‑to‑end tests and reports failures.
model: haiku
tools: ["Read","Write","Bash","Glob"]
task: ["e2e"]
memory: false
---
You are an automated E2E test executor. Your job is to:
- Run `npm run cy:run` (or the configured Cypress command).
- Capture stdout/stderr and parse the JSON report.
- Summarize passed/failed specs, showing the first failing test with stack trace.
- If failures are detected, suggest possible causes (e.g., network mock, selector change).
Output a markdown **test report** with a table of results and a bullet list of next steps.
---
name: doc-updater
description: Keeps project documentation (README, OpenAPI) in sync with code.
model: opus
tools: ["Read","Write","Edit","Glob"]
task: ["doc"]
memory: true
memory_frontmatter: { "last_update": "none" }
---
You are a documentation maintainer. When invoked, you will:
- Scan `backend/` for Flask route decorators and generate an OpenAPI snippet.
- Scan `frontend/src/` for exported components and create a component list.
- Update the top‑level `README.md` with sections: Architecture diagram, API reference, and Component map.
- Commit the changes using a conventional commit message: `docs: sync with codebase`.
Return a short markdown **change log** describing what was added/modified.
---
name: security-reviewer
description: Scan Flask and React code for common security issues.
model: opus
tools: ["Read","Write","Edit","Grep","Glob","Bash"]
task: ["security"]
memory: true
memory_frontmatter: { "last_scan": null }
---
You are a security analyst for web applications. Your workflow:
1. Run `bandit` on the `backend/` directory.
2. Run `npm audit` and `npm audit fix --dry-run` on the `frontend/`.
3. Search for insecure patterns (e.g., `eval`, hard‑coded secrets, unsafe CORS settings).
4. Produce a markdown **security report** with severity levels, affected files, and concrete remediation steps.
If a fix is trivial, include a diff patch.
---
name: planner
description: Generates sprint plans, task breakdowns, and estimates.
model: opus
tools: ["Read","Write","Edit","Grep","Glob"]
task: ["plan"]
memory: true
memory_frontmatter: { "current_sprint": 0 }
---
You are an agile planner. When asked to create a sprint, you will:
- Ask for the product goal and target velocity.
- Break down the goal into user stories (INVEST criteria).
- Estimate each story in story points using Fibonacci.
- Output a markdown **sprint board** with columns: Todo, In‑Progress, Review, Done.
- Store the plan in `docs/sprint-<num>.md` for future reference.
---
name: refactor-cleaner
description: Suggests clean‑code refactors for Python and TypeScript.
model: sonnet
tools: ["Read","Write","Edit","Grep","Glob"]
task: ["refactor"]
memory: true
memory_frontmatter: { "last_refactor": null }
---
You are a refactoring guru. Your process:
1. Run static analysis (`pylint`, `eslint --max-warnings=0`).
2. Identify duplicated logic, large functions, and anti‑patterns.
3. Propose a minimal diff that extracts utilities, introduces type aliases, or applies memoization.
4. Explain the **why** (maintainability, performance, testability).
Return a markdown **refactor proposal** with code blocks, before/after snippets, and impact assessment.
---
name: code-reviewer
description: General code reviewer that runs after any commit.
model: opus
tools: ["Read","Write","Edit","Grep","Glob","Bash"]
memory: true
memory_frontmatter: { "last_review": null }
---
You are a senior full‑stack code reviewer. After each change you will:
- Run the appropriate linters for Python and TypeScript.
- Ensure commit messages follow Conventional Commits.
- Verify that unit tests cover new/changed code (minimum 80% coverage).
- Check for cross‑stack consistency (e.g., API contract matches React fetch calls).
- Produce a concise markdown **review summary** with Pass/Fail, Issues, and Action Items.
If failures exist, include a minimal corrective diff.
Tools
{
"name": "create-flask-backend",
"description": "Flask 백엔드 기본 구조와 필수 파일을 생성합니다.",
"inputs": {
"type": "object",
"properties": {
"projectRoot": { "type": "string", "description": "프로젝트 루트 디렉터리 경로" }
},
"required": ["projectRoot"]
},
"outputs": {
"type": "object",
"properties": {
"result": { "type": "string" },
"error": { "type": "string" }
}
},
"command": "bash -c '\nset -euo pipefail\nROOT=\"{{projectRoot}}\"\nBACKEND=$ROOT/backend\nmkdir -p $BACKEND\ncat > $BACKEND/app.py <<'PY'
from flask import Flask, request, jsonify
from flask_cors import CORS
import os\n\napp = Flask(__name__)\nCORS(app)\n\n@app.route(\"/api/generate\", methods=[\"POST\"])\ndef generate():\n data = request.get_json(silent=True) or {}\n prompt = data.get(\"prompt\", \"\")\n # TODO: LLM 호출 로직 삽입\n result = f\"Echo: {prompt}\"\n return jsonify({{\"result\": result}})\n\nif __name__ == \"__main__\":\n port = int(os.getenv(\"PORT\", 5000))\n app.run(host=\"0.0.0.0\", port=port)\nPY\n\ncat > $BACKEND/routes.py <<'PY'
# 추후 라우트 정의를 여기서 추가합니다.\nPY\n\ncat > $BACKEND/requirements.txt <<'REQ'
Flask>=3.0\nFlask-CORS\npython-dotenv\nREQ\n\ncat > $BACKEND/.env <<'ENV'
PORT=5000\nLLM_API_KEY=YOUR_KEY_HERE\nENV\n\necho \"✅ Flask 백엔드가 생성되었습니다: $BACKEND\"'\n"
{
"name": "create-react-frontend",
"description": "React + Vite 프로젝트를 초기화합니다.",
"inputs": {
"type": "object",
"properties": {
"projectRoot": { "type": "string", "description": "프로젝트 루트 디렉터리 경로" }
},
"required": ["projectRoot"]
},
"outputs": {
"type": "object",
"properties": {
"result": { "type": "string" },
"error": { "type": "string" }
}
},
"command": "bash -c '\nset -euo pipefail\nROOT=\"{{projectRoot}}\"\nFRONTEND=$ROOT/frontend\nnpm create vite@latest $FRONTEND -- --template react\ncd $FRONTEND\nnpm install react@19.3 react-dom@19.3\ncat > $FRONTEND/src/App.jsx <<'APP'\nimport React, { useState } from \"react\";\n\nexport default function App() {\n const [prompt, setPrompt] = useState(\"\");\n const [result, setResult] = useState(\"\");\n\n const callApi = async () => {\n const resp = await fetch(\"/api/generate\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ prompt })\n });\n const data = await resp.json();\n setResult(data.result ?? \"error\");\n };\n\n return (\n <div style={{ padding: \"2rem\" }}>\n <h1>Claude‑Code React Demo</h1>\n <input value={prompt} onChange={e=>setPrompt(e.target.value)} placeholder=\"프롬프트 입력\"/>\n <button onClick={callApi}>전송</button>\n <p>결과: {result}</p>\n </div>\n );\n}\nAPP\n\necho \"✅ React 프론트엔드가 생성되었습니다: $FRONTEND\"'\n"
{
"name": "install-backend-deps",
"description": "Flask 백엔드 의존성 설치",
"inputs": {
"type": "object",
"properties": {
"projectRoot": { "type": "string" }
},
"required": ["projectRoot"]
},
"outputs": { "type": "object" },
"command": "bash -c '\nset -euo pipefail\nROOT=\"{{projectRoot}}\"\ncd $ROOT/backend\npython -m pip install --upgrade pip\npython -m pip install -r requirements.txt\necho \"✅ 백엔드 의존성 설치 완료\"'\n"
{
"name": "install-frontend-deps",
"description": "React 프론트엔드 의존성 설치",
"inputs": {
"type": "object",
"properties": {
"projectRoot": { "type": "string" }
},
"required": ["projectRoot"]
},
"outputs": { "type": "object" },
"command": "bash -c '\nset -euo pipefail\nROOT=\"{{projectRoot}}\"\ncd $ROOT/frontend\nnpm install\necho \"✅ 프론트엔드 의존성 설치 완료\"'\n"
{
"name": "run-flask-server",
"description": "Flask 개발 서버 실행",
"inputs": {
"type": "object",
"properties": { "projectRoot": { "type": "string" } },
"required": ["projectRoot"]
},
"outputs": { "type": "object" },
"command": "bash -c '\nset -euo pipefail\nROOT=\"{{projectRoot}}\"\ncd $ROOT/backend\n# .env 로드 후 Flask 실행\nexport $(grep -v ^# .env | xargs)\npython -m flask run --host=0.0.0.0 --port=${PORT:-5000}'\n"
{
"name": "run-react-dev",
"description": "React Vite 개발 서버 실행",
"inputs": {
"type": "object",
"properties": { "projectRoot": { "type": "string" } },
"required": ["projectRoot"]
},
"outputs": { "type": "object" },
"command": "bash -c '\nset -euo pipefail\nROOT=\"{{projectRoot}}\"\ncd $ROOT/frontend\nnpm run dev\n'\n"
{
"name": "search-project",
"description": "프로젝트 파일 내용 검색",
"inputs": {
"type": "object",
"properties": {
"projectRoot": { "type": "string" },
"pattern": { "type": "string", "description": "검색할 문자열 또는 정규식" },
"ignoreCase": { "type": "boolean", "default": false }
},
"required": ["projectRoot", "pattern"]
},
"outputs": {
"type": "object",
"properties": { "matches": { "type": "array", "items": { "type": "string" } } }
},
"command": "bash -c '\nset -euo pipefail\nROOT=\"{{projectRoot}}\"\nFLAGS=\"\"\nif {{ignoreCase}}; then FLAGS=\"-i\"; fi\nRESULT=$(rg $FLAGS --json \"{{pattern}}\" $ROOT || true)\necho \"{\"matches\": $(echo $RESULT | jq -c \"[.path.text, .lines.text]\") }\'\n"
Hooks
#!/usr/bin/env bash
set -euo pipefail
# 프로젝트 루트 경로
PROJECT_ROOT="$CLAUDE_PROJECT_DIR"
cd "$PROJECT_ROOT"
# ---------- Python (Flask) ----------
if [ -f "requirements.txt" ]; then
echo "🛠️ Setting up Python virtual environment..."
python3 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip setuptools wheel
pip install -r requirements.txt
fi
# ---------- JavaScript (React) ----------
if [ -f "package.json" ]; then
echo "🛠️ Installing Node dependencies..."
npm ci
fi
# ---------- 초기 Lint/Formatter 설치 (선택적) ----------
# Python formatter
if command -v black >/dev/null 2>&1; then :; else pip install black; fi
# JavaScript formatter & linter
if command -v prettier >/dev/null 2>&1; then :; else npx prettier --write .; fi
if command -v eslint >/dev/null 2>&1; then :; else npm install --save-dev eslint; fi
echo "✅ Setup completed."
#!/usr/bin/env bash
set -euo pipefail
FILE_PATH="$CLAUDE_TOOL_INPUT_FILE_PATH"
EXT="${FILE_PATH##*.}"
PROJECT_ROOT="$CLAUDE_PROJECT_DIR"
cd "$PROJECT_ROOT"
BLOCK_MSG(){
cat <<EOF >&2
{ "block": true, "message": "$1" }
EOF
exit 2
}
case "$EXT" in
py)
if [ -f ".venv/bin/activate" ]; then source .venv/bin/activate; fi
if ! command -v flake8 >/dev/null 2>&1; then pip install flake8; fi
flake8 "$FILE_PATH" || BLOCK_MSG "Python lint 오류가 발견되었습니다. 파일을 수정해 주세요."
;;
js|jsx|ts|tsx)
if ! command -v eslint >/dev/null 2>&1; then npm install --save-dev eslint; fi
eslint "$FILE_PATH" --max-warnings=0 || BLOCK_MSG "ESLint 오류가 발견되었습니다. 파일을 수정해 주세요."
;;
*)
# 기타 파일은 검사하지 않음
;;
esac
exit 0
#!/usr/bin/env bash
set -euo pipefail
FILE_PATH="$CLAUDE_TOOL_INPUT_FILE_PATH"
EXT="${FILE_PATH##*.}"
PROJECT_ROOT="$CLAUDE_PROJECT_DIR"
cd "$PROJECT_ROOT"
# ---------- 포맷 ----------
case "$EXT" in
py)
if [ -f ".venv/bin/activate" ]; then source .venv/bin/activate; fi
if ! command -v black >/dev/null 2>&1; then pip install black; fi
black "$FILE_PATH"
;;
js|jsx|ts|tsx)
if ! command -v prettier >/dev/null 2>&1; then npm install --save-dev prettier; fi
npx prettier --write "$FILE_PATH"
;;
*)
:
;;
esac
# ---------- 테스트 ----------
# Python 테스트 (pytest)
if [ -f "pytest.ini" ] || [ -d "tests" ]; then
if [ -f ".venv/bin/activate" ]; then source .venv/bin/activate; fi
if ! command -v pytest >/dev/null 2>&1; then pip install pytest; fi
echo "▶️ Running Python tests..."
pytest -q || echo "⚠️ Python 테스트에 실패했습니다."
fi
# JavaScript 테스트 (npm test / jest)
if [ -f "package.json" ]; then
if npm run | grep -q "test"; then
echo "▶️ Running JavaScript tests..."
npm test --silent || echo "⚠️ JavaScript 테스트에 실패했습니다."
fi
fi
exit 0
#!/usr/bin/env bash
set -euo pipefail
PROJECT_ROOT="$CLAUDE_PROJECT_DIR"
cd "$PROJECT_ROOT"
echo "🔄 Checking remote repository status..."
git remote update
LOCAL=$(git rev-parse @)
REMOTE=$(git rev-parse @{u} 2>/dev/null || echo "none")
BASE=$(git merge-base @ @{u} 2>/dev/null || echo "none")
if [ "$REMOTE" != "none" ]; then
if [ "$LOCAL" = "$REMOTE" ]; then
echo "✅ 로컬 브랜치가 최신 상태입니다."
elif [ "$LOCAL" = "$BASE" ]; then
echo "⚠️ 로컬이 뒤처져 있습니다. 'git pull'을 권장합니다."
else
echo "⚠️ 로컬과 원격에 서로 다른 커밋이 있습니다. 수동 병합이 필요합니다."
fi
fi
# ---------- 개발 서버 상태 확인 (React) ----------
if pgrep -f "npm start" >/dev/null 2>&1; then
echo "✅ React 개발 서버가 실행 중입니다."
else
echo "⚠️ React 개발 서버가 실행되지 않았습니다. 필요 시 'npm start'를 실행하세요."
fi
exit 0
#!/usr/bin/env bash
set -euo pipefail
PROJECT_ROOT="$CLAUDE_PROJECT_DIR"
cd "$PROJECT_ROOT"
# ---------- 전체 테스트 실행 ----------
echo "🔧 Running full test suite..."
# Python 전체 테스트
if [ -f "pytest.ini" ] || [ -d "tests" ]; then
if [ -f ".venv/bin/activate" ]; then source .venv/bin/activate; fi
if ! command -v pytest >/dev/null 2>&1; then pip install pytest; fi
pytest || { echo "❌ 전체 Python 테스트 실패"; exit 1; }
fi
# JavaScript 전체 테스트
if [ -f "package.json" ] && npm run | grep -q "test"; then
npm test --silent || { echo "❌ 전체 JavaScript 테스트 실패"; exit 1; }
fi
echo "✅ All tests passed."
# ---------- 자동 커밋 & 푸시 ----------
git add .
COMMIT_MSG="[Claude] 자동 커밋: $(date +'%Y-%m-%d %H:%M:%S')"
if git diff --cached --quiet; then
echo "⚡ No changes to commit."
else
git commit -m "$COMMIT_MSG"
git push || echo "⚠️ 푸시 실패. 수동으로 푸시하세요."
fi
# ---------- 요약 피드백 ----------
cat <<EOF >&2
{ "feedback": "✅ 작업이 완료되었습니다. 전체 테스트를 통과했으며, 변경 사항이 원격 저장소에 푸시되었습니다.", "suppressOutput": true }
EOF
exit 0
Rules
# 공통 코딩 스타일 가이드
## 1️⃣ 코드 가독성
- **줄 길이**: 100자를 초과하지 않으며, 필요 시 라인 분할을 권장합니다.
- **파일 크기**: 하나의 파일은 400줄 이하, 200줄을 넘지 않도록 모듈화합니다.
- **불변성**: 가능한 한 `const`(JS)·`final`(Python)·`Object.freeze`(React) 등을 사용해 데이터 변형을 최소화합니다.
## 2️⃣ 네이밍 규칙
- **Python**: `snake_case` 변수·함수, `PascalCase` 클래스, `UPPER_SNAKE_CASE` 상수.
- **JavaScript/TypeScript**: `camelCase` 변수·함수, `PascalCase` 컴포넌트·클래스, `UPPER_SNAKE_CASE` 상수.
- **파일명**: 기능을 직관적으로 나타내며, React 컴포넌트는 `PascalCase`.
## 3️⃣ 주석·문서화
- **함수·메서드**: 입력·출력 타입과 동작을 간단히 설명하는 docstring (Python) 혹은 JSDoc (JS/TS).
- **복잡 로직**: 왜 그렇게 구현했는지 설계 의도를 주석에 남깁니다.
## 4️⃣ 형식화·정적 분석
- **Python**: `black`, `isort`, `ruff` 자동 포맷·린트 (PreToolUse 훅).
- **React**: `prettier`, `eslint` (Airbnb + React) 자동 포맷·린트.
> **Tip**: `common/hooks.md` 에 정의된 훅이 파일 저장 시 자동으로 위 도구들을 실행합니다.
# Git Workflow & Commit Convention
## 1️⃣ 브랜치 전략 (Git‑Flow)
- `main` : 프로덕션 배포 브랜치 (항상 배포 가능한 상태).
- `develop` : 통합 테스트 브랜치.
- `feature/<name>` : 새로운 기능 개발.
- `bugfix/<name>` : 버그 수정.
- `release/<version>` : 릴리즈 준비.
- `hotfix/<name>` : 급한 프로덕션 수정.
## 2️⃣ 커밋 메시지 형식
```
<type>(<scope>): <subject>
<body>
<footer>
```
- **type**: `feat`, `fix`, `docs`, `style`, `refactor`, `test`, `chore`
- **scope**: `backend`, `frontend`, `auth`, `ui` 등.
- **subject**: 50자 이하, 현재형 사용.
## 3️⃣ PR 템플릿 (`.github/pull_request_template.md`)
- **제목**: `feat(ui): 로그인 페이지 리팩터링`
- **Description**: 변경 내용, 동작 흐름, 테스트 방법, 관련 이슈.
- **Checklist**:
- [ ] 코드 스타일 검사 통과
- [ ] 테스트 추가·통과
- [ ] 문서 업데이트
## 4️⃣ CI 연동 (GitHub Actions)
- PR 생성 시 자동 `lint`, `test`, `coverage` 실행.
- `main` 병합 전 `build` 및 `docker image` 생성 검증.
# Claude Code CLI 훅 설정
Claude Code CLI 2.1.38 은 파일 변경 시 자동으로 도구를 실행할 수 있는 **Hook** 을 지원합니다. 아래는 프로젝트 전반에 적용할 권장 훅 구성 예시(`.claude/hooks.yml`) 입니다.
```yaml
# .claude/hooks.yml
hooks:
# 파일 저장 직후 실행 (PreToolUse)
PreToolUse:
- when: "**/*.py"
run: "black . && isort ."
- when: "**/*.js" | "**/*.jsx" | "**/*.ts" | "**/*.tsx"
run: "prettier --write ."
# 도구 실행 후 결과 검증 (PostToolUse)
PostToolUse:
- when: "**/*.py"
run: "ruff check . && mypy ."
- when: "**/*.js" | "**/*.jsx" | "**/*.ts" | "**/*.tsx"
run: "eslint . --max-warnings=0"
# 테스트 자동 실행 (TaskCompleted)
TaskCompleted:
- when: "**/tests/**/*.py"
run: "pytest --cov=app"
- when: "**/src/**/*.test.{js,ts,tsx}"
run: "npm test -- --watchAll=false"
```
## Hook 설명
- **PreToolUse**: 파일이 저장되면 포맷터(`black`, `prettier`)를 먼저 실행해 코드 일관성을 확보합니다.
- **PostToolUse**: 포맷 이후 린트와 타입 체크(`ruff`, `mypy`, `eslint`)를 수행해 품질을 검증합니다.
- **TaskCompleted**: 테스트 파일이 변경되면 해당 테스트 스위트를 자동으로 실행해 회귀를 방지합니다.
> **주의**: `paths` 패턴은 `**/*` 와 같은 glob 형식을 지원합니다. 필요에 따라 `Setup` 훅을 이용해 프로젝트 초기화 스크립트를 지정할 수 있습니다.
---
paths:
- "**/*.py"
- "**/*.pyi"
---
# Python Coding Style (Flask)
## 1️⃣ 기본 규칙
- **PEP 8** 준수 (indent 4 spaces, trailing commas, etc.)
- **type annotations** 를 모든 함수·메서드에 적용 (`def foo(a: int) -> str:`).
- **Black** (line length 100) 로 자동 포맷, **isort** 로 import 정렬, **ruff** 로 lint.
## 2️⃣ 불변성 & 데이터 구조
- 가능한 경우 `dataclasses.dataclass(frozen=True)` 혹은 `typing.NamedTuple` 사용.
- 컬렉션은 `tuple`, `frozenset` 등 immutable 변형을 우선합니다.
## 3️⃣ 로깅 가이드
- `print` 대신 표준 라이브러리 `logging` 사용.
- 로그 레벨은 `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL` 로 구분.
- 모듈 별 로거 이름: `logger = logging.getLogger(__name__)`.
## 4️⃣ 의존성 관리
- `requirements.txt` 혹은 `pyproject.toml`에 명시하고, `pip-tools` 로 `*.lock` 파일 유지.
- Flask 확장은 `flask-caching`, `flask-migrate`, `flask-talisman` 등 최신 버전 사용.
## 5️⃣ 자동화 (Claude Code Hook 연동)
- `PreToolUse` → `black`, `isort`
- `PostToolUse` → `ruff`, `mypy`
- `TaskCompleted` → `pytest`
> **Tip**: `common/hooks.md` 에 정의된 전체 훅 정책을 그대로 재사용합니다.
설정 파일
설정 파일이 없습니다.