Skip to content
Open
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
34 changes: 33 additions & 1 deletion .claude/settings.local.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,39 @@
{
"permissions": {
"allow": [
"Bash(git add:*)"
"Bash(git add:*)",
"Bash(./gradlew :apps:commerce-api:test:*)",
"Bash(./gradlew:*)",
"Bash(find /mnt/c/Users/kdj10/Git/loop-pack-be-l2-vol3-java -name \"CacheConfig.java\" -o -name \"*CacheConfig*\" 2>/dev/null | head -20)",
"Bash(JAVA_HOME=\"/mnt/c/Users/kdj10/.jdks/ms-21.0.10\" ./gradlew :apps:commerce-api:compileJava 2>&1 | tail -30)",
"Bash(ls \"/mnt/c/Users/kdj10/.jdks/ms-21.0.10/bin/\" | head -5; \"/mnt/c/Users/kdj10/.jdks/ms-21.0.10/bin/java\" -version 2>&1 | head -3)",
"Read(//home/ubuntu/projects/loop-pack-be-l2-vol3-java/**)",
"Bash(sg docker:*)",
"Bash(cd ~/projects/loop-pack-be-l2-vol3-java && sg docker -c \"./gradlew :apps:commerce-api:test --tests 'com.loopers.domain.brand.BrandServiceTest'\" 2>&1 | grep -A5 \"FAILED\")",
"Bash(cd ~/projects/loop-pack-be-l2-vol3-java && sg docker -c \"./gradlew :apps:commerce-api:test --tests 'com.loopers.domain.*'\" 2>&1 | grep \"FAILED\\\\|tests completed\" | tail -5)",
"Bash(cd ~/projects/loop-pack-be-l2-vol3-java && sg docker -c \"./gradlew :apps:commerce-api:test --tests 'com.loopers.domain.coupon.CouponModelTest'\" 2>&1 | grep -A3 \"FAILED\")",
"Bash(cd ~/projects/loop-pack-be-l2-vol3-java && sg docker -c \"./gradlew :apps:commerce-api:test --tests 'com.loopers.domain.order.OrderCartRestoreIdempotencyTest'\" 2>&1 | grep -A3 \"FAILED\")",
"Bash(cd ~/projects/loop-pack-be-l2-vol3-java && sg docker -c \"./gradlew :apps:commerce-api:test --tests 'com.loopers.infrastructure.*'\" 2>&1 | grep \"FAILED\\\\|tests completed\" | tail -5)",
"Bash(chmod +x /mnt/c/Users/kdj10/Git/loop-pack-be-l2-vol3-java/k6/seed.sh)",
"Bash(docker compose:*)",
"Bash(docker ps:*)",
"Bash(mysql -h 127.0.0.1 -P 3306 -u application -papplication loopers -e \"\nSELECT 'users' AS tbl, COUNT\\(*\\) AS cnt FROM users\nUNION ALL\nSELECT 'brands', COUNT\\(*\\) FROM brands\nUNION ALL\nSELECT 'products', COUNT\\(*\\) FROM products\nUNION ALL\nSELECT 'product_stocks', COUNT\\(*\\) FROM product_stocks;\n\" 2>/dev/null)",
"Bash(docker exec:*)",
"Bash(pip3 install:*)",
"Bash(python3 docs/DDL/seed.py 2>&1)",
"Bash(curl -s -X POST http://localhost:8080/api/v1/users \\\\\n -H \"Content-Type: application/json; charset=UTF-8\" \\\\\n -d '{\"loginId\":\"testuser\",\"password\":\"Test1234!\",\"userName\":\"testuser\",\"birthday\":\"19900101\",\"email\":\"test@loopers.com\",\"address\":\"Seoul\"}' 2>/dev/null)",
"Bash(curl -v -X POST http://localhost:8080/api/v1/users \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\"loginId\":\"testuser\",\"password\":\"Test1234!\",\"userName\":\"testuser\",\"birthday\":\"19900101\",\"email\":\"test@loopers.com\",\"address\":\"Seoul\"}' 2>&1 | tail -20)",
"Bash(curl -s http://localhost:8080/api/v1/products/1 \\\\\n -H \"X-Loopers-LoginId: testuser\" \\\\\n -H \"X-Loopers-LoginPw: Test1234!\" | python3 -m json.tool 2>/dev/null | head -20)",
"Bash(sleep 40 && curl -s -o /dev/null -w \"%{http_code}\" http://localhost:8080/actuator/health 2>/dev/null || echo \"not ready\")",
"Bash(kill 88108 2>/dev/null; sleep 15 && curl -s -o /dev/null -w \"%{http_code}\" http://localhost:8080/actuator/health)",
"Bash(sleep 20 && curl -s -o /dev/null -w \"%{http_code}\" http://localhost:8080/actuator/health)",
"Bash(curl -s -o /dev/null -w \"%{http_code}\" -H \"X-Loopers-LoginId: testuser\" -H \"X-Loopers-LoginPw: Test1234!\" \"http://localhost:8080/api/v1/products/1\")",
"Bash(docker run:*)",
"Bash(find /mnt/c/Users/kdj10/Git/loop-pack-be-l2-vol3-java/apps/commerce-api/src/main/java/com/loopers/infrastructure/cache -type f -name \"*.java\" 2>/dev/null | sort)",
"Bash(find:*)",
"Bash(git checkout:*)",
"Bash(BASE=~/projects/loop-pack-be-l2-vol3-java/apps/commerce-api/src)",
"Read(//mnt/c/Users/kdj10/Git/loop-pack-be-l2-vol3-java/$BASE/main/java/com/loopers/infrastructure/cache/**)"
]
},
"hooks": {
Expand Down
97 changes: 97 additions & 0 deletions .claude/skills/anaylize-query/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
---
name: analyze-query
description:
대상이 되는 코드 범위를 탐색하고, Spring @Transactional, JPA, QueryDSL 기반의 코드에 대해 트랜잭션 범위, 영속성 컨텍스트, 쿼리 실행 시점 관점에서 분석한다.

특히 다음을 중점적으로 점검한다.
- 트랜잭션이 불필요하게 크게 잡혀 있지는 않은지
- 조회/쓰기 로직이 하나의 트랜잭션에 혼합되어 있지는 않은지
- JPA의 지연 로딩, flush 타이밍, 변경 감지로 인해
의도치 않은 쿼리 또는 락이 발생할 가능성은 없는지

단순한 정답 제시가 아니라, 현재 구조의 의도와 trade-off를 드러내고 개선 가능 지점을 선택적으로 판단할 수 있도록 돕는다.
---

### 📌 Analysis Scope
이 스킬은 아래 대상에 대해 분석한다.
- @Transactional 이 선언된 클래스 / 메서드
- Service / Facade / Application Layer 코드
- JPA Entity, Repository, QueryDSL 사용 코드
- 하나의 유즈케이스(요청 흐름) 단위
> 컨트롤러 → 서비스 → 레포지토리 전체 흐름을 기준으로 분석하며 특정 메서드만 떼어내어 판단하지 않는다.

### 🔍 Analysis Checklist
#### 1. Transaction Boundary 분석
다음을 순서대로 확인한다.
- 트랜잭션 시작 지점은 어디인가?
- Service / Facade / 그 외 계층?
- 트랜잭션이 실제로 필요한 작업은 무엇인가?
- 상태 변경 (쓰기)
- 단순 조회
- 트랜잭션 내부에서 수행되는 작업 나열
- 외부 API 호출
- 복잡한 조회(QueryDSL)
- 반복문 기반 처리

**출력 예시**
```markdown
- 현재 트랜잭션 범위:
OrderFacade.placeOrder()
├─ 유저 검증
├─ 상품 조회
├─ 주문 생성
├─ 결제 요청
└─ 재고 차감

- 트랜잭션이 필요한 핵심 작업:
- 주문 생성
- 재고 차감
```

#### 2. 불필요하게 큰 트랜잭션 식별
아래 패턴이 존재하는지 점검한다.
- Controller 에서 Transactional 이 사용되고 있음
- 읽기 전용 로직이 쓰기 트랜잭션에 포함됨
- 외부 시스템 호출이 트랜잭션 내부에 포함됨
- 트랜잭션 내부에서 대량 조회 / 복잡한 QueryDSL 실행
- 상태 변경 이후에도 트랜잭션이 길게 유지됨

**문제 후보 예시**
- 결제 API 호출이 트랜잭션 내부에 포함되어 있음
- 주문 생성 이후 추천 상품 조회 로직까지 동일 트랜잭션에 포함됨

#### 3. JPA / 영속성 컨텍스트 관점 분석
다음을 중심으로 분석한다.
- Entity 변경이 언제 flush 되는지
- 조회용 Entity가 변경 감지 대상이 되는지
- 지연 로딩으로 인해 트랜잭션 후반에 쿼리가 발생할 가능성
- @Transactional(readOnly = true) 미적용 여부

**체크리스트 예시**
```markdown
- 단순 조회인데 Entity 반환 후 변경 가능성 존재?
- DTO Projection 대신 Entity 조회 사용 여부
- QueryDSL 조회 결과가 영속성 컨텍스트에 포함되는지
```

#### 4. Improvement Proposal (선택적 제안)
개선안은 강제하지 않고 선택지로 제시한다.
- 트랜잭션 분리
- 조회 → 쓰기 분리
- Facade에서 orchestration, Service는 최소 트랜잭션
- `@Transactional(readOnly = true)` 적용
- DTO Projection (읽기 전용 모델) 도입
- 외부 호출 / 이벤트 발행을 트랜잭션 외부로 이동
- Application Service / Domain Service 책임 재조정

**개선안 예시**
```markdown
[개선안 1]
- 주문 생성과 결제 요청을 분리
- 주문 생성까지만 트랜잭션 유지
- 결제 요청은 트랜잭션 종료 후 수행

[고려 사항]
- 결제 실패 시 주문 상태 관리 필요
- 보상 트랜잭션 또는 상태 전이 설계 필요
```
72 changes: 72 additions & 0 deletions .claude/skills/anylize-external-integration/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
name: analyze-external-integration
description:
외부 시스템(결제, 재고 시스템, 메시징, 서드파티 API 등)과 연동되는 기능의 설계를 분석한다.
트랜잭션 경계, 상태 일관성, 실패 시나리오, 재시도 및 중복 실행 가능성을 중심으로 리스크를 드러낸다.
설계를 대신 생성하지 않으며, 이미 작성된 설계를 검증하고 개선 선택지를 제시하는 데 사용한다.
외부 시스템 호출이 포함된 기능 구현 전/후 설계 리뷰 목적으로 사용한다.
---

외부 시스템 연동 설계를 분석할 때 반드시 다음 흐름을 따른다.

### 1️⃣ 기능이 아니라 "불확실성" 관점으로 재해석한다
- 단순 호출 순서를 요약하지 않는다.
- 외부 시스템은 항상 다음을 만족한다고 가정한다:
- 지연될 수 있다
- 실패할 수 있다
- 중복 실행될 수 있다
- 성공했지만 응답이 유실될 수 있다
- 현재 설계가 이러한 불확실성을 어떻게 다루는지 설명한다.

---

### 2️⃣ 트랜잭션 경계를 검증한다
- 외부 호출이 트랜잭션 내부에 존재하는지 확인한다.
- 외부 시스템과 내부 DB 상태가 하나의 트랜잭션처럼 다뤄지고 있는지 분석한다.
- 다음 질문을 반드시 포함한다:
- 외부 호출 실패 시 내부 상태는 어떻게 되는가?
- 내부 커밋 이후 외부 호출 실패 시 복구 가능한가?
- 외부 성공 후 내부 실패 시 상태는 어떻게 정합성을 유지하는가?

---

### 3️⃣ 상태 기반으로 구조를 다시 본다
- 호출 흐름이 아니라 상태 전이를 중심으로 설명한다.
- 내부 도메인 상태와 외부 시스템 상태를 분리해서 정리한다.
- 두 상태가 어긋날 수 있는 지점을 명시한다.

---

### 4️⃣ 중복 요청 및 재시도 가능성을 분석한다
- 네트워크 재시도 상황을 가정한다.
- 동일 요청이 두 번 실행될 경우 문제를 설명한다.
- 멱등성(Idempotency) 고려 여부를 확인한다.

---

### 5️⃣ 장애 시나리오를 최소 3가지 이상 생성한다
- 정상 흐름보다 실패 흐름을 우선한다.
- 각 장애 상황에서:
- 데이터 정합성
- 상태 불일치
- 복구 가능성
을 분석한다.

---

### 6️⃣ 해결책은 정답처럼 제시하지 않는다
- 현재 구조의 장점과 리스크를 분리한다.
- 대안 구조가 있다면 선택지 형태로 제시한다.
예:
- 동기 호출 유지
- 상태 기반 단계 분리
- 비동기 이벤트 전환
- 각 선택지의 복잡도와 운영 부담을 함께 설명한다.

---

### 7️⃣ 톤 & 스타일 가이드
- 코드 레벨 수정안을 직접 제시하지 않는다.
- 설계를 비판하지 말고 리스크를 드러내는 리뷰 톤을 유지한다.
- 외부 시스템은 항상 신뢰할 수 없다는 전제를 유지한다.
- 구현보다 책임, 경계, 상태 일관성을 중심으로 분석한다.
5 changes: 5 additions & 0 deletions .venv/pyvenv.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
home = /usr/bin
include-system-site-packages = false
version = 3.12.3
executable = /usr/bin/python3.12
command = /usr/bin/python3 -m venv /mnt/c/Users/kdj10/Git/loop-pack-be-l2-vol3-java/.venv
Loading