-
Notifications
You must be signed in to change notification settings - Fork 0
[REFACTOR] 답변 랭킹 저장이 답변 저장에 영향을 주지 않도록 분리 #91
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| package com.devoops.event; | ||
|
|
||
| import com.devoops.domain.entity.github.answer.Answer; | ||
| import lombok.Getter; | ||
| import org.springframework.context.ApplicationEvent; | ||
|
|
||
| @Getter | ||
| public class UpdateAnswerEvent extends ApplicationEvent { | ||
|
|
||
| private final Answer answer; | ||
| private final long userId; | ||
|
|
||
| public UpdateAnswerEvent(Object source, Answer answer, long userId) { | ||
| super(source); | ||
| this.answer = answer; | ||
| this.userId = userId; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| package com.devoops.event.listener; | ||
|
|
||
| import com.devoops.domain.entity.github.answer.Answer; | ||
| import com.devoops.event.UpdateAnswerEvent; | ||
| import com.devoops.service.answerranking.AnswerRankingService; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.scheduling.annotation.Async; | ||
| import org.springframework.stereotype.Component; | ||
| import org.springframework.transaction.event.TransactionPhase; | ||
| import org.springframework.transaction.event.TransactionalEventListener; | ||
|
|
||
| @Component | ||
| @RequiredArgsConstructor | ||
| public class AnswerEventListener { | ||
|
|
||
| private final AnswerRankingService answerRankingService; | ||
|
|
||
| @Async | ||
| @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) | ||
| public void updateAnswer(UpdateAnswerEvent updateAnswerEvent) { | ||
| Answer answer = updateAnswerEvent.getAnswer(); | ||
| long userId = updateAnswerEvent.getUserId(); | ||
| answerRankingService.push(answer, userId); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -8,6 +8,7 @@ dev-oops: | |||||
| - "summaryDetail"은 변경 내용을 항목별로 요약한 제목(title) + 설명(description) 쌍으로 구성해. | ||||||
| - "category"는 기술적인 관점에서 PR 코드 변경 내용을 반영하여 선택해 (예: 성능, 보안, 확장성, 유지보수성, 테스트 등) | ||||||
| - "question"은 각 category에 대해 기술 면접에서 사용할 수 있는 질문이어야 해. | ||||||
| - "question"은 가능한 255자가 넘지 않도록 짧고 명료하게 질문해. | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chain프롬프트 지시만으로는 255자 제한을 보장하지 못합니다 — 스키마/후처리로 강제하세요 LLM 프롬프트에만 의존하면 간헐적으로 255자를 초과할 수 있어 동일 계열의 제약 위반이 재발할 수 있습니다. JSON 스키마에 maxLength=255를 명시하고(format-message가 주입하는 스키마에 반영), 파서 단계에서 초과 문항은 안전하게 잘라내는 후처리를 추가하는 것을 권장합니다. 라인 문구도 “가능한”이 아닌 “반드시/초과 시 절단”으로 바꿔 의도를 강화해 주세요. Apply this diff to tighten the instruction: - - "question"은 가능한 255자가 넘지 않도록 짧고 명료하게 질문해.
+ - "question"은 반드시 255자 이내로 작성하고, 초과 시 앞 252자만 남기고 '...'로 절단해.다음 스크립트로 레포 내 강제 수단이 있는지 확인해 주세요(스키마 maxLength, DTO @SiZe, DB 컬럼 등): 필요하시면: (1) 스키마에 maxLength 추가, (2) 파서 후처리 유틸(초과 시 안전 절단), (3) 경계 테스트(254/255/256자) 작성까지 패치 드리겠습니다. 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== JSON 스키마에 maxLength 존재 여부 체크 =="
rg -n -C2 -i --type=json --type=yaml 'question"|questions"|prompt.*question|maxLength' || true
echo "== DTO/검증 애노테이션(@Size<=255) 존재 여부 체크 =="
rg -n -C2 -i --type=java --type=kt '@Size\s*\(\s*max\s*=\s*255' || true
rg -n -C2 -i --type=java --type=kt '\bString\s+question\b|\bvar\s+question\b|\bval\s+question\b' || true
echo "== DB 제약(컬럼 길이) 존재 여부 체크 =="
rg -n -C2 -i --type=sql 'question.*varchar\s*\(\s*255\s*\)|varchar\s*\(\s*255\s*\).*question' || trueLength of output: 2225 프롬프트 문구 및 제약 강제 적용
📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
| - 각 질문들은 반드시 PR 코드 변경 내용("diff")을 인용해서 생성해. | ||||||
| - "diff"를 굉장히 자세하게 분석하고 몇몇 질문에는 코드를 반영해서 만들어줘 | ||||||
| - 질문 수는 카테고리마다 3개 이상 만들어. | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,7 +26,7 @@ public class AnswerRankingEntity { | |
| private long questionId; | ||
|
|
||
| @NotBlank | ||
| @Column(name = "content") | ||
| @Column(name = "content", columnDefinition = "TEXT") | ||
| private String questionContent; | ||
|
Comment on lines
+29
to
30
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainDB 컬럼을 TEXT로 고정하면 벤더 종속이 증가합니다. @lob로 매핑하고 마이그레이션을 동반하세요.
선호 diff: - @NotBlank
- @Column(name = "content", columnDefinition = "TEXT")
+ @NotBlank
+ @Lob
+ @Column(name = "content")
private String questionContent;필요 import: import jakarta.persistence.Lob;마이그레이션 존재 여부 확인 스크립트: 주의:
🏁 Script executed: #!/bin/bash
# 1) Answer(사용자 답변) 및 Ranking의 content 컬럼 타입 변경 반영 여부 점검
# AnswerEntity 매핑에서 content 필드와 컬럼 정의 확인
rg -nP -C2 '(class\s+AnswerEntity\b)|(@Column\([^)]*name\s*=\s*"content"[^)]*\))' --g 'gss-**/*.java'
# "TEXT/CLOB" 정의가 어디에 쓰였는지 검색
rg -nP 'columnDefinition\s*=\s*"TEXT"|@Lob' --g 'gss-**/*'
# 마이그레이션 SQL에 content 타입 변경이 있는지 검색
rg -nP -C2 'ALTER\s+TABLE.+content.+(TEXT|CLOB)|MODIFY\s+COLUMN\s+`?content`?.+(TEXT|LONGTEXT)|TYPE\s+TO\s+(TEXT|CLOB)' --g '**/*.sql'Length of output: 1519 🏁 Script executed: #!/bin/bash
# 1) AnswerEntity 소스 파일 경로 찾기
rg -lP 'class\s+AnswerEntity' --glob '*.java'
# 2) AnswerEntity 및 AnswerRankingEntity에서 content 컬럼 어노테이션 확인
rg -n '@Column\([^)]*name\s*=\s*"content"[^)]*\)' --glob '*.java'
# 3) @Lob 어노테이션 사용 여부 확인
rg -n '@Lob' --glob '*.java'
# 4) SQL 마이그레이션에서 content 컬럼 타입 변경 반영 여부 확인
rg -nP -C2 'ALTER\s+TABLE.+content.+(TEXT|CLOB)|MODIFY\s+COLUMN.+content.+(TEXT|LONGTEXT)|TYPE\s+TO\s+(TEXT|CLOB)' --glob '*.sql'Length of output: 652 🏁 Script executed: #!/bin/bash
# 1) AnswerEntity content 필드 매핑 확인
rg -nP -C5 'private\s+String\s+content' gss-domain/src/main/java/com/devoops/jpa/entity/github/answer/AnswerEntity.java
# 2) 프로젝트 내 SQL 파일 목록
find gss-domain -type f -name "*.sql"
# 3) SQL 마이그레이션에서 content 컬럼 변경 반영 검색
rg -nP 'content' --glob 'gss-domain/**/*.sql' -C2Length of output: 578 🏁 Script executed: #!/bin/bash
# 전체 리포지토리에서 SQL 마이그레이션 파일 확인
find . -type f -name '*.sql'
# SQL 파일에서 content 컬럼 변경 반영 여부 검색
rg -nP 'content' --glob '*.sql' -C2Length of output: 215 @lob 매핑 적용 및 마이그레이션 스크립트 추가 필요
|
||
|
|
||
| @Column(name = "pull_request_id") | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
리스너에 트랜잭션 경계를 추가하세요 (특히 @async 환경).
커밋 후 다른 스레드에서 실행되므로, JPA/MyBatis를 사용한다면 쓰기 작업에 트랜잭션이 없어 실패(예:
TransactionRequiredException)할 수 있습니다. 리스너 메서드에REQUIRES_NEW트랜잭션을 부여해 랭킹 저장을 독립적으로 보장하세요.대안:
AnswerRankingService.push(...)자체를@Transactional로 감싸도 됩니다(서비스 계층 표준화).📝 Committable suggestion
🤖 Prompt for AI Agents