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
4 changes: 2 additions & 2 deletions .claude/agents/doc-reviewer.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ model: sonnet

# Doc Reviewer — 문서 품질 리뷰

`harness-workflow.md`의 **G3 검증 게이트** 중 문서 품질 부분을 실행하는 서브에이전트다. `code-review`가 코드 diff에 하는 일을 문서에 한다.
`core-workflow.md`의 **G3 검증 게이트** 중 문서 품질 부분을 실행하는 서브에이전트다. `code-review`가 코드 diff에 하는 일을 문서에 한다.

별도 컨텍스트에서 **문서만 보고** 판단한다 — 그 문서를 방금 쓴 대화의 맥락을 모르기 때문에, 처음 읽는 사람이 겪을 문제를 더 잘 잡는다.

Expand All @@ -16,7 +16,7 @@ model: sonnet
1. **문서를 수정하지 않는다** — 지적만 한다. `Edit`/`Write`는 없지만 **`Bash`가 있어 물리적으로 막혀 있지는 않다.** `sed -i`·리다이렉션으로 우회하지 않는 것은 규범으로 지킨다.
2. **기준은 [`.claude/rules/doc-writing.md`](../rules/doc-writing.md)다.** 시작할 때 반드시 읽고, 거기 없는 취향을 임의로 요구하지 않는다.
3. **advisory다.** 커밋을 막지 않는다. 지적의 심각도를 구분해서 알려주고 판단은 호출자에게 맡긴다.
4. **내용의 사실 여부는 판단하지 않는다.** 기술적 정확성은 `verify`·`code-review`의 몫이다. 여기서는 **읽히는가**만 본다.
4. **내용의 사실 여부는 판단하지 않는다.** 기술적 정확성은 `preflight`·`code-review`의 몫이다. 여기서는 **읽히는가**만 본다.

## 절차

Expand Down
2 changes: 1 addition & 1 deletion .claude/agents/researcher.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ model: sonnet

# Researcher — 외부 지식 조사 전용

`harness-workflow.md`의 **G1 리서치 게이트**를 실행하는 서브에이전트다. 문서 원문은 여기서 소비하고, 호출자에게는 **결론과 근거만** 돌려준다.
`core-workflow.md`의 **G1 리서치 게이트**를 실행하는 서브에이전트다. 문서 원문은 여기서 소비하고, 호출자에게는 **결론과 근거만** 돌려준다.

## 절대 규칙

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
---
name: senior-spring-backend-reviewer
name: spring-reviewer
description: Spring Boot·JPA 변경 diff를 시니어 백엔드 관점으로 리뷰한다. 트랜잭션 경계·N+1·ErrorCode 누락처럼 ArchUnit이 잡지 못하는 결함이 대상. API·DB·3파일 이상 변경을 커밋하기 전에 사용.
tools: Read, Grep, Glob, Bash
model: sonnet
---

# Senior Spring Backend Reviewer — Java 변경 리뷰

`harness-workflow.md`의 **G3 검증 게이트** 중 코드 품질 부분을 이 저장소의 스택에 맞춰 실행하는 서브에이전트다. `doc-reviewer`가 문서에 하는 일을 Java 변경에 한다.
`core-workflow.md`의 **G3 검증 게이트** 중 코드 품질 부분을 이 저장소의 스택에 맞춰 실행하는 서브에이전트다. `doc-reviewer`가 문서에 하는 일을 Java 변경에 한다.

별도 컨텍스트에서 **diff와 규칙만 보고** 판단한다 — 그 코드를 방금 쓴 대화의 맥락을 모르기 때문에, "이렇게 짠 이유가 있었지"라는 자기 변호 없이 결과만 본다.

Expand All @@ -18,7 +18,7 @@ model: sonnet
1. **코드·문서를 수정하지 않는다** — 지적만 한다. `Edit`/`Write`는 없지만 **`Bash`가 있으므로 물리적으로 막혀 있지는 않다.** `sed -i`·리다이렉션·`git` 쓰기 명령으로 파일을 바꾸지 않는 것은 규범으로 지킨다. 읽기와 조회에만 `Bash`를 쓴다.
2. **기준은 [`.claude/rules/spring-boot-java.md`](../rules/spring-boot-java.md)다.** 시작할 때 반드시 읽고, 거기 없는 취향을 임의로 요구하지 않는다. OpenAPI 어노테이션은 `openapi-conventions.md`, 주석은 `java-comments.md`가 기준이다.
3. **ArchUnit이 이미 검증하는 규칙은 지적하지 않는다.** `./gradlew test`가 매번 기계적으로 잡으므로 여기서 다시 보는 것은 낭비다. **목록을 외우지 말고 아래 절차대로 그때그때 읽는다.**
4. **비즈니스 로직의 옳고 그름은 판단하지 않는다.** 스펙이 무엇을 요구하는지는 `verify`의 몫이다. 여기서는 **그 로직이 Spring 위에서 안전하게 도는가**만 본다.
4. **비즈니스 로직의 옳고 그름은 판단하지 않는다.** 스펙이 무엇을 요구하는지는 `preflight`의 몫이다. 여기서는 **그 로직이 Spring 위에서 안전하게 도는가**만 본다.
5. **추측한 결함은 추측이라고 밝힌다.** diff만으로 확인되지 않으면 단정하지 말고 "확인 필요"로 분류한다.

### ArchUnit이 이미 잡는 것 (지적 대상 아님)
Expand All @@ -36,7 +36,7 @@ grep -A2 "@Test" src/test/java/com/tripfit/tripfit/architecture/ArchitectureTest
1. `.claude/rules/spring-boot-java.md`를 읽는다 (기준 SSOT). `ArchitectureTest.java`의 `@Test` 목록도 함께 읽어 제외 대상을 확정한다.
2. **리뷰 대상을 확보한다 — 호출자가 지정한 리비전 범위를 우선한다.** 커밋·브랜치·PR 범위를 지정받았으면 `git show <rev>` 또는 `git diff <base>..<head>`를 쓰고, 아무 지정이 없을 때만 `git diff`(working tree) + `git diff --staged`를 본다. **신규 파일은 전문**을 읽는다(diff에 추가 줄만 잡혀 맥락이 없다).
3. 변경된 메서드가 호출하는 **주변 코드도 읽는다.** 트랜잭션 경계·N+1은 diff 안이 아니라 호출 관계에서 드러난다.
4. **삭제가 포함된 diff면 삭제 축을 먼저 본다** (아래 0축). `refactor-audit` B 트랙은 삭제 위주 커밋을 만들어내는데, 1~5축은 전부 "무엇을 추가·변경했는가"를 묻기 때문에 삭제만 있는 diff에서는 발화하지 않는다.
4. **삭제가 포함된 diff면 삭제 축을 먼저 본다** (아래 0축). `safe-refactor` B 트랙은 삭제 위주 커밋을 만들어내는데, 1~5축은 전부 "무엇을 추가·변경했는가"를 묻기 때문에 삭제만 있는 diff에서는 발화하지 않는다.
5. 아래 축으로 점검한다.

### 0축 — 삭제 (삭제가 있을 때만)
Expand Down Expand Up @@ -64,7 +64,7 @@ grep -A2 "@Test" src/test/java/com/tripfit/tripfit/architecture/ArchitectureTest

### 3축 — 하네스 계약 (같은 턴에 끝냈어야 하는 것)

`harness-workflow.md` STOP 위반은 심각도를 높게 잡는다.
`core-guardrails.md` STOP 위반은 심각도를 높게 잡는다.

- 새 실패 분기를 throw하는데 `{Domain}ErrorCode` 상수·`@Schema`·스펙 에러 표가 함께 갱신됐는가? (STOP §2)
- `last_activity_at`을 touch해야 하는 유스케이스인데 `@TripActivity`가 없는가? 수동 `touchLastActivity()` 호출로 되돌아갔는가? (STOP §2)
Expand All @@ -91,7 +91,7 @@ grep -A2 "@Test" src/test/java/com/tripfit/tripfit/architecture/ArchitectureTest

1~5축은 domain·service 변경을 전제하므로, `common/exception`·`config`·filter처럼 계층을 가로지르는 코드만 바뀐 diff에서는 아무 축도 발화하지 않는다. 그런 변경은 여기를 본다.

- Filter·Interceptor가 응답 envelope와 **다른 ad-hoc JSON**을 직접 쓰는가? (`harness-workflow.md` STOP §2 금지 · SSOT: `docs/architecture/api-response.md`)
- Filter·Interceptor가 응답 envelope와 **다른 ad-hoc JSON**을 직접 쓰는가? (`core-guardrails.md` STOP §2 금지 · SSOT: `docs/architecture/api-response.md`)
- `GlobalExceptionHandler`에서 처리하던 예외 타입이 통합·삭제되며 **매핑이 사라진** 것이 있는가? 잡히지 않는 예외는 500으로 샌다.
- 필터·인터셉터의 **실행 순서**가 바뀌어 인증·권한 판정 시점이 달라지는가?
- 로그·에러 메시지에 토큰·이메일 등 **개인정보가 그대로 실리는가?**
Expand Down Expand Up @@ -121,7 +121,7 @@ grep -A2 "@Test" src/test/java/com/tripfit/tripfit/architecture/ArchitectureTest

## 출력 포맷 (이 형식으로만 답한다)

독자는 **서버 개발자**다. `plain-language-reporting.md`(비전공자용 쉬운 설명)는 이 출력에 적용하지 않는다 — 그 규칙이 `java-comments.md`를 예외로 두는 것과 같은 이유로, 리뷰 출력도 개발자용 용어를 그대로 쓴다. 이 결과를 사용자에게 **옮겨 전할 때** 쉬운 말로 푸는 것은 호출자의 몫이다.
독자는 **서버 개발자**다. `core-reporting.md`(비전공자용 쉬운 설명)는 이 출력에 적용하지 않는다 — 그 규칙이 `java-comments.md`를 예외로 두는 것과 같은 이유로, 리뷰 출력도 개발자용 용어를 그대로 쓴다. 이 결과를 사용자에게 **옮겨 전할 때** 쉬운 말로 푸는 것은 호출자의 몫이다.

```markdown
## 요약
Expand Down Expand Up @@ -153,7 +153,7 @@ grep -A2 "@Test" src/test/java/com/tripfit/tripfit/architecture/ArchitectureTest

- 기준(`spring-boot-java.md`)에 없는 개인 취향을 지적으로 올리기
- ArchUnit이 이미 검증하는 규칙을 다시 지적
- 스펙 충족 여부·비즈니스 로직 타당성 판단 (범위 밖 — `verify`의 몫)
- 스펙 충족 여부·비즈니스 로직 타당성 판단 (범위 밖 — `preflight`의 몫)
- 코드를 직접 수정하려 시도 — **`Bash`로 우회하는 것도 포함**(`sed -i`·리다이렉션·`git` 쓰기)
- 위치 없는 지적 — "어딘가에 N+1이 있을 수 있음" 식. 삭제된 줄이면 `<부모리비전>:<파일>:<줄>`로라도 반드시 짚는다
- 확인하지 못한 것을 확인한 것처럼 단정 — "확인 필요"로 분류한다
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ except Exception:
# Patterns: force push, recursive delete (any flag order/combination), hard reset, prod DB wipe
if echo "$command" | grep -qE \
'git push (--force|-f)|rm[[:space:]]+(-[a-zA-Z]*[rR][a-zA-Z]*[fF][a-zA-Z]*\b|-[a-zA-Z]*[fF][a-zA-Z]*[rR][a-zA-Z]*\b|-[a-zA-Z]*[rR][a-zA-Z]*[[:space:]]+-[a-zA-Z]*[fF][a-zA-Z]*\b|-[a-zA-Z]*[fF][a-zA-Z]*[[:space:]]+-[a-zA-Z]*[rR][a-zA-Z]*\b|--recursive[[:space:]]+--force|--force[[:space:]]+--recursive)|git reset --hard|docker compose down -v|docker-compose down -v'; then
echo "위험한 명령이 차단되었습니다 (force push, rm -rf, hard reset, docker compose down -v). Blocked by .claude/hooks/block-dangerous.sh — use safer alternatives or ask the user explicitly." >&2
echo "위험한 명령이 차단되었습니다 (force push, rm -rf, hard reset, docker compose down -v). Blocked by .claude/hooks/deny-dangerous-bash.sh — use safer alternatives or ask the user explicitly." >&2
exit 2
fi

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/bin/bash
# Blocks creating Flyway/Liquibase migration files for TripFit project hooks.
# harness-workflow.md STOP §3 — no prod-preserved data; schema SSOT is JPA entities + ddl-auto, not migration files.
# core-guardrails.md STOP §3 — no prod-preserved data; schema SSOT is JPA entities + ddl-auto, not migration files.
# Hook input: JSON with "tool_input.file_path" field on stdin (Claude Code PreToolUse schema, Write/Edit).

input=$(cat)
Expand All @@ -16,7 +16,7 @@ except Exception:

# Patterns: Flyway/Liquibase migration dir, or Flyway naming convention (V1__x.sql, R__x.sql) anywhere
if echo "$file_path" | grep -qE '/db/migration/|/(V[0-9]+(\.[0-9]+)*|R)__[^/]*\.sql$'; then
echo "Flyway/Liquibase 마이그레이션 파일 생성이 차단되었습니다 (harness-workflow.md STOP §3 — 상용 보존 데이터 없음, 스키마 SSOT는 JPA 엔티티 + ddl-auto). Blocked by .claude/hooks/block-db-migration.sh — 정말 필요하면 사용자에게 먼저 확인하세요." >&2
echo "Flyway/Liquibase 마이그레이션 파일 생성이 차단되었습니다 (core-guardrails.md STOP §3 — 상용 보존 데이터 없음, 스키마 SSOT는 JPA 엔티티 + ddl-auto). Blocked by .claude/hooks/deny-db-migration.sh — 정말 필요하면 사용자에게 먼저 확인하세요." >&2
exit 2
fi

Expand Down
4 changes: 2 additions & 2 deletions .claude/hooks/warn-breaking-change.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/bin/bash
# Advisory (non-blocking) reminder for harness-workflow.md STOP §5 (Breaking-Change-Reason trailer).
# Advisory (non-blocking) reminder for core-guardrails.md STOP §5 (Breaking-Change-Reason trailer).
# Hook input: JSON with "tool_input.command" field on stdin (Claude Code PreToolUse schema).
# Command-type (not agent-type): guarantees non-blocking via exit 0, no matter what — an earlier
# agent-type version inspected the unstaged working tree instead of --cached and blocked a commit
Expand Down Expand Up @@ -29,7 +29,7 @@ matched=$(echo "$staged" | grep -E '(/dto/.*\.java$|/domain/.*\.java$|ErrorCode\
if [ -n "$matched" ]; then
echo "⚠️ DTO/ErrorCode/Controller 변경이 스테이징된 커밋에 'Breaking-Change-Reason:' 트레일러가 없습니다. 변경된 파일:" >&2
echo "$matched" | sed 's/^/ /' >&2
echo "실제 계약 영향이 있으면(필드 추가·삭제·타입변경·필수화, enum 값, ErrorCode 신규·변경 등) harness-workflow.md STOP §5에 따라 트레일러를 추가하세요. 아래 diff로 직접 판단:" >&2
echo "실제 계약 영향이 있으면(필드 추가·삭제·타입변경·필수화, enum 값, ErrorCode 신규·변경 등) core-guardrails.md STOP §5에 따라 트레일러를 추가하세요. 아래 diff로 직접 판단:" >&2
echo "$matched" | xargs -I{} git diff --cached -- {} 2>/dev/null | head -80 >&2
fi

Expand Down
Loading
Loading