Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
228 commits
Select commit Hold shift + click to select a range
b1ba939
chore: initialize project structure
Ksr-ccb May 28, 2025
459e4fd
chore: initialize project structure
Ksr-ccb May 28, 2025
336c5c8
chore: initialize project structure
Ksr-ccb May 28, 2025
a1d8cc9
fix: 엔티티 오류수정 및 설정파일 오류 수정
Ksr-ccb May 28, 2025
2131310
📝 Add docstrings to `dev` (#3)
coderabbitai[bot] May 28, 2025
2827734
Revert "Create run-test.yaml"
jong-0126 May 29, 2025
d2ae5bc
도커에 레디스 설정파일 추가 (#7)
Ksr-ccb May 29, 2025
c91c506
Feat/6 카카오톡 소셜로그인 + jwt 토큰 발급 (#11)
Ksr-ccb May 30, 2025
67c5cec
Feat/9 (#14)
jong-0126 May 30, 2025
39ab7c9
Feat/15 (#17)
jong-0126 May 30, 2025
4f65009
Feat/8 (#19)
crocusia Jun 2, 2025
90ea1e2
feat: OAuth2 Github 기능추가 및 임시 메인페이지 추가 (#21)
wannabeing Jun 2, 2025
4cf1788
Feat/15 (#18)
jong-0126 Jun 2, 2025
81982f7
Feat/10 (#23)
HeeMang-Lee Jun 2, 2025
c771394
Feat/13 구독 엔티티 구조 정리 및 구독 정보 조회 (#28)
Ksr-ccb Jun 2, 2025
665ad90
Feat/27 (#29)
jong-0126 Jun 2, 2025
e01af5d
Feat/27 (#30)
jong-0126 Jun 2, 2025
2020cd7
Fix logging and import issues (#32)
HeeMang-Lee Jun 4, 2025
522f2a6
feat: 구독정보/구독내역 생성/수정 로직 추가 및 공통응답 수정 (#33)
wannabeing Jun 4, 2025
b62e9dc
Feat/13 로그인 마이페이지 (#35)
Ksr-ccb Jun 4, 2025
8f709c9
Feat/22 인증 코드 이메일 발급 및 검증 (#36)
crocusia Jun 4, 2025
ffb0b26
Feat/31 (#40)
jong-0126 Jun 4, 2025
37442c4
Feat/41 (#42)
jong-0126 Jun 4, 2025
59722ea
Feat/41 (#43)
jong-0126 Jun 5, 2025
29e534b
Feat/39 AI, RAG 및 Chroma 연동 중간 커밋 (#45)
Kimyoonbeom Jun 5, 2025
1153d5a
Feat: OAuth2 Naver 로그인 기능 추가 및 관련 코드 수정 (#48)
wannabeing Jun 7, 2025
136b1d2
Feat/12 오늘의 문제 뽑아주기 & 하루에 한번씩 돌아가는 문제 정답률 계산 (#44)
Ksr-ccb Jun 9, 2025
f3fcb89
chore/50 도커 컴포즈 파일 변경 (#52)
Ksr-ccb Jun 9, 2025
2c519b6
Feat/49 github md파일 크롤링 기능 추가 (#53)
crocusia Jun 9, 2025
89994a4
feat: 답안 체점 로직 구현 (#55)
jong-0126 Jun 10, 2025
4143640
Feat/38 문제풀이 링크 이메일 발송 및 테스트 코드 (#56)
crocusia Jun 11, 2025
a6ec161
Chore/54 중간 테스트, 필요한 예외처리 및 모니터링 도구 설치(그라파나, 프로메테우스) (#59)
Ksr-ccb Jun 11, 2025
abff1c1
feat : 메일 발송 api 추가 (#63)
crocusia Jun 11, 2025
44233d9
Feat/58 문제, 정답, 해설 조회 기능 구현 (#64)
jong-0126 Jun 11, 2025
2e014b1
feat/39 RAG 구조 완성 및 서비스 컨트롤러 리팩토링. (#66)
Kimyoonbeom Jun 11, 2025
238e510
Feat/62 문제 확인 페이지 생성 (#67)
Ksr-ccb Jun 11, 2025
35e179f
Feat/SpringBatch (with Jenkins) 적용 (#70)
wannabeing Jun 11, 2025
2e2a380
Feat/71 (#73)
jong-0126 Jun 12, 2025
49cc5c4
Feat/57 이메일 발송 MQ + 비동기 처리 추가 (#72)
crocusia Jun 12, 2025
61dd151
Fix/프론트엔드 연동을 위한 최소한의 작업 (#75)
wannabeing Jun 12, 2025
a93a633
fix : 예외처리를 위한 조건문 추가 (#79)
crocusia Jun 13, 2025
0887df1
Feat/76 (#80)
jong-0126 Jun 13, 2025
52d8747
chore: forward-header 전략 설정 (#81)
wannabeing Jun 13, 2025
6057919
Merge branch 'main' into dev
jong-0126 Jun 13, 2025
dace8a9
1차 배포
jong-0126 Jun 13, 2025
1fc84be
Merge remote-tracking branch 'origin/dev' into dev
jong-0126 Jun 13, 2025
fde63d0
1차 배포
jong-0126 Jun 13, 2025
dc1a06b
1차 병합 (#83)
crocusia Jun 13, 2025
0a078b3
Merge remote-tracking branch 'origin/dev' into dev
jong-0126 Jun 13, 2025
00747af
fix: aiFeedback 컬럼 데이터길이 수정 (#88)
wannabeing Jun 16, 2025
be882e3
Chore: 메일서비스 링크 도메인 변경 (#89)
Ksr-ccb Jun 16, 2025
3baf85d
Refactor/78 : 문제풀이 링크 발송 흐름 일부 수정, 성능 개선 1차 (#90)
crocusia Jun 16, 2025
76b031b
fix/78 : BatchService Bean 주입 오류 개선 (#93)
crocusia Jun 16, 2025
93a9f29
Feat/68 프롬프팅 적용 방식 리팩토링 및 RAG 문서분류성능평가 테스트 코드 작성 (#94)
HeeMang-Lee Jun 16, 2025
ab69da1
Chore/92 멀티모듈적용 (#97)
Ksr-ccb Jun 17, 2025
37d6728
Chore/92 중복파일제거 (#98)
Ksr-ccb Jun 17, 2025
02f799e
fix: 멀티모듈로 변경 후 벡터DB에 문서 적재 안되는 오류 해결 완료 (#101)
HeeMang-Lee Jun 18, 2025
12e5f37
Feat/96 MailLog CRUD 추가 (#102)
crocusia Jun 18, 2025
95390f7
빌드 오류 트러블 슈팅 (#104)
jong-0126 Jun 18, 2025
5ce05fe
Feat/105 (#106)
jong-0126 Jun 18, 2025
0713c4d
Refactor: 배치모듈 수정 (#110)
wannabeing Jun 19, 2025
95bc72b
Feat/91 (#113)
jong-0126 Jun 19, 2025
5c69146
Feat/95 문제 동적 생성 시 중복 문제 생성 해결 및 문서 임베딩 과정 리팩토링 (#115)
HeeMang-Lee Jun 19, 2025
03180f2
Refactor: 오늘의 문제 프론트 페이지와 연결 로직 수정 (#116)
wannabeing Jun 19, 2025
1361f2e
Refactor: 구독설정(수정) 프론트 페이지와 연결 로직 수정 (#118)
wannabeing Jun 20, 2025
90e89ad
Feat/108 관리자 퀴즈 CRU, 로그인 토큰값 쿠키저장 (#120)
Ksr-ccb Jun 20, 2025
5d84aa2
Feat/122 (#123)
jong-0126 Jun 20, 2025
9b45723
Chore: 오늘의문제 정답률 응답로직 및 주관식/객관식 구분 로직 추가 (#129)
wannabeing Jun 20, 2025
814faf9
Feat/100 : 심화 기능 추가에 따른 QuizCategory 변화 기반 리팩토링 (#125)
crocusia Jun 20, 2025
12b29ae
fix: QuizFormatType Enum 클래스 경로 수정 (#130)
wannabeing Jun 20, 2025
26760b1
Feat/131: 사용자 프로필 조회(점수 부여, 랭킹) (#136)
jong-0126 Jun 20, 2025
1d13f88
Feat/121 관리자 유저 CRUD, Oauth2 로그인 예외 분기 추가 (#135)
Ksr-ccb Jun 20, 2025
9226662
Refactor/132 문제 동적 생성 시 Ai가 소분류 구분할 수 있게 리팩토링 (#137)
HeeMang-Lee Jun 20, 2025
9b1e26a
Feat/124 OpenAi 호출 실패 시 Claude Api 호출하는 Fallback구조 도입 (#142)
HeeMang-Lee Jun 23, 2025
3f71f42
Refactor: 오늘의 문제 응답할 때 문제분야 대분류/소분류, 난이도 필드 추가 (#134)
wannabeing Jun 23, 2025
7a0161a
Refactor/140 : Admin 권한이 필요한 api에 대한 권한 검증 로직 추가, 유저의 카테고리별 정답률 api 위…
crocusia Jun 23, 2025
12eac38
Refactor/143 : Ai Service 채점 시 스트리밍 기반 SSE 방식으로 리팩토링 (#144)
HeeMang-Lee Jun 23, 2025
df9e3f9
Feat/138: 주관식, 서술형 문제 체점 및 점수 부여 (#146)
jong-0126 Jun 23, 2025
27acc2d
Feat/121 (#139) 노출되는 id값을 UUID 로 변경 (#145)
Ksr-ccb Jun 23, 2025
df096d9
feat: 유저 권한 바꾸기 관리자용 (#149)
Ksr-ccb Jun 23, 2025
1ff09fa
Feat/128 : AWS SES 적용, 메일 발송 로그에 실패 원인 컬럼 추가 (#152)
crocusia Jun 23, 2025
9948ef0
feat: (#156)
jong-0126 Jun 23, 2025
f71d79d
Feat/150 오늘의 문제뽑기 알고리즘 변경 (#154)
Ksr-ccb Jun 23, 2025
97840af
Feat/148 인메모리 기반 Blocking 큐잉 구조 도입 (#155)
HeeMang-Lee Jun 23, 2025
c426db7
test: (#159)
jong-0126 Jun 24, 2025
b9e638f
Chore/160 테스트 코드 및 개선할 부분 api 분리를 위해서 서비스 모듈 이동 (#161)
Ksr-ccb Jun 24, 2025
59388ed
Feat/162: aiService user 조회, 점수 부여 수정 / 구독하기 카테고리 대분류 검증 ! 제거 (#163)
jong-0126 Jun 24, 2025
c3e1cd4
Fix: AI 피드백 응답 SSE에서 기존 방식으로, 카테고리 대분류/소분류 추출 로직 반대로 된거 수정 (#164)
wannabeing Jun 24, 2025
272e29c
refactor: (#166)
jong-0126 Jun 25, 2025
1523163
Feat/170 : 로컬 k6 기반 부하 테스트 환경 구성 및 테스트 스크립트 작성 Ai 피드백 처리 멀티 워커 구조 도입 …
HeeMang-Lee Jun 25, 2025
2d7d7d4
Feat/174: 틀린문제 다시보기 페이징 처리 (#175)
jong-0126 Jun 25, 2025
11547ad
Feat/169: 프로필 테스트코드 작성 (#176)
jong-0126 Jun 25, 2025
985c025
chore: 오늘의 문제뽑기 성능 개선 (#173)
Ksr-ccb Jun 25, 2025
a109ff4
Feat/157 : 퀴즈 & 퀴즈 카테고리 RUD 추가, 퀴즈 & 퀴즈 카테고리 & 메일 로그 테스트 코드 추가 (#177)
crocusia Jun 25, 2025
b694483
Refactor/172 BlockingQueue 기반 SSE 큐잉 구조를 Redis Stream 기반 구조로 전환 (#183)
HeeMang-Lee Jun 26, 2025
9c7427b
Chore: Profile 프론트와 연동에서 필요한 부분 수정 (#182)
wannabeing Jun 26, 2025
8be4bf2
fix: AiFeedbackQueueServiceTest 구조 변경으로 인해 삭제 (#185)
HeeMang-Lee Jun 26, 2025
65e6af1
Refactor/186 Redis Stream 기반 Ai 테스트 코드 리팩토링 (#187)
HeeMang-Lee Jun 27, 2025
370e5f1
Test: Subscription(구독) 도메인 테스트코드 작성 (#168)
wannabeing Jun 27, 2025
6975d59
Refactor/189 : AI 피드백 SSE 토큰 단위로 실시간 전송하는 스트리밍 기능으로 리팩토링 (#190)
HeeMang-Lee Jun 27, 2025
26fffd4
test: getUserQuizAnswerCorrectRate 테스트코드 (#188)
Ksr-ccb Jun 27, 2025
ab48c1d
Feat/180: CI/CD 2차 배포 (#193)
jong-0126 Jun 27, 2025
253e6bf
feat: 배치모듈 배포 자동화 코드 추가 (#194)
wannabeing Jun 27, 2025
96fe597
refactor/179 : 스프링 배치 리팩토링, 자바 메일 Sender 배치에 추가 (#191)
crocusia Jun 27, 2025
1a3ee89
Conflict (#198)
Ksr-ccb Jun 27, 2025
6632ecf
Merge branch 'main' into dev
Ksr-ccb Jun 27, 2025
161d4db
chore: delete src directory
Ksr-ccb Jun 27, 2025
71d3edc
chore: ci 설정 변경
Ksr-ccb Jun 27, 2025
9d71ba3
Merge branch 'main' into dev
wannabeing Jun 27, 2025
44a10a4
fix: deploy-service.yml
Ksr-ccb Jun 27, 2025
b379ebf
Merge remote-tracking branch 'origin/dev' into dev
Ksr-ccb Jun 27, 2025
e1839ca
Chore: 메일 템플릿을 인라인 스타일과 테이블 기반 레이아웃으로 수정 (#202)
wannabeing Jun 28, 2025
bd2d44f
Chore: 문제 정답제출 시 발생하는 오류 수정 (#204)
wannabeing Jun 30, 2025
1080b5d
Refactor/205: 문장 단위 혹은 단어 단위 테스트용 SSE 리팩토링 (#212)
HeeMang-Lee Jun 30, 2025
d94217e
Feat/207 로그인 상태에서 구독 신청 구조 변경 (#214)
Ksr-ccb Jun 30, 2025
376cf7c
Chore: 특정 퀴즈 선택률 계산 API 파라미터 수정 및 각 메서드명 변경 및 주석 추가 (#215)
wannabeing Jun 30, 2025
4ac4f51
feat/210: String으로 변경하면서 Long타입의 quizId로 받고 있는 테스트코드 수정 (#211)
jong-0126 Jun 30, 2025
eb90071
Refactor/208 : 중복된 API 제거 및 관리자 API 분리 (#213)
crocusia Jun 30, 2025
d4c20ce
Chore: 3차 배포 이후 프론트 연동 문제점 해결 (#222)
wannabeing Jul 1, 2025
c8e2a47
refactor: SSE 방식 sentence기반 리팩토링 (#225)
HeeMang-Lee Jul 1, 2025
457e712
Feat/224: userQuizAnswer 컨트롤러 테스트 코드 작성 (#227)
jong-0126 Jul 1, 2025
da7113f
Test/218 Verification, Users, Security 도메인 테스트 코드 (#226)
Ksr-ccb Jul 1, 2025
e894ec0
Feat/224: userQuizAnswer 컨트롤러 테스트 (#228)
jong-0126 Jul 1, 2025
b48506c
Merge branch 'main' into dev
jong-0126 Jul 1, 2025
df52746
fix: ai 컨트롤러, 서비스 수정
jong-0126 Jul 1, 2025
0c91a25
refactor: 틀린문제 다시보기 페이징 처리 수정 (#236)
jong-0126 Jul 1, 2025
dcecfd9
fix: 구독있는 회원은 새로운 구독 못만들게 설정 (#234)
Ksr-ccb Jul 1, 2025
fe64452
Chore: 채점 API 주소 변경 (#237)
wannabeing Jul 1, 2025
f820108
Fix/233 단답형 퀴즈 뽑는 수 제거 / 오늘의 문제뽑기 성능개선 버전적용 (#239)
Ksr-ccb Jul 1, 2025
1a8a0f9
Feat/209 : 인증 코드 발송 SES 전략, 인증 코드 발급 개수 제한 추가 (#242)
crocusia Jul 1, 2025
393f319
Fix/240 : Ai 피드백 시 aifeedback,iscorrect 저장 되지 않는 버그 해결 (#241)
HeeMang-Lee Jul 1, 2025
894c648
Refactor: Q 클래스 리빌드, UserQuizAnswer 로직 개선, UserQuizAnswerResponseDto …
wannabeing Jul 1, 2025
b54958b
feat: 1차 백엔드 README 작성. (#232)
Kimyoonbeom Jul 2, 2025
2ed4bff
Chore: 중복 답변일 때, AI 피드백 보이게 수정 (#246)
wannabeing Jul 2, 2025
72ad88b
Test: 퀴즈(Quiz) 도메인 테스트 코드 작성 (#248)
wannabeing Jul 2, 2025
2b62ee2
fix: 마지막 페이지 못 불러오는 이슈 해결 (#256)
jong-0126 Jul 2, 2025
ea10a74
fix: 구독 비활성화 후에 문제 못풀게 설정 (#253)
Ksr-ccb Jul 2, 2025
a75096d
Refactor/250 : 프로필 카테고리별 정답률 집계 안되는 문제 해결, Quiz Json 업로드 Dto 수정 (#257)
crocusia Jul 2, 2025
f5588b6
Feat/258: UserQuizAnswer 테스트코드 수정 (#259)
jong-0126 Jul 2, 2025
ca850f0
Chore: 이메일 최대요청 예외메시지 개선, UserQuizAnswer 필드값 누락 시 예외로직 추가, 전체적인 코드 리팩…
wannabeing Jul 2, 2025
efd49b6
fix: Subscription 테스트코드 에러 수정
wannabeing Jul 2, 2025
37bfd4d
fix: UserQuizAnswer, Profile 테스트 코드 수정 (#261)
jong-0126 Jul 2, 2025
8ac45e9
Feat/249 : 배치 모듈 성공 케이스 테스트 코드 추가 (#262)
crocusia Jul 2, 2025
2af0c96
Feat/264: userQuizAnswer 컨트롤러 테스트 (#265)
jong-0126 Jul 2, 2025
06378eb
Merge branch 'main' into dev
jong-0126 Jul 2, 2025
7278f64
fix: service-deploy.yml 파일 수정
jong-0126 Jul 2, 2025
6a3bb0b
fix: 틀린문제 다시보기에서 전체 사용자의 틀린문제가 보이는 이슈 수정 (#269)
jong-0126 Jul 3, 2025
11a1f6a
Refactor/270 : 안 쓰는 AuthUser 제거 (#272)
crocusia Jul 3, 2025
9df5c05
test: 프로필 컨트롤러 테스트코드 작성 (#274)
jong-0126 Jul 3, 2025
30cf3d2
Test/263 admin 도메인 테스트 코드 (#275)
Ksr-ccb Jul 3, 2025
1825286
Refactor: 풀었던 문제 다시보기 이슈 해결 (#277)
wannabeing Jul 3, 2025
45da619
Fix/279 소셜로그인, 구독 중복이메일 처리 (#280)
Ksr-ccb Jul 3, 2025
19e63d5
refactor: CI 브랜치 범위 변경
jong-0126 Jul 3, 2025
a7aeb97
refactor: CI 브랜치 범위 변경 (#284)
jong-0126 Jul 3, 2025
d4f2bc9
chore: 문제 제출 시, isCorrect 값 설정 오류 개선 (#282)
wannabeing Jul 3, 2025
3dff705
Merge branch 'dev' of https://github.com/NBC-finalProject/CS25 into dev
jong-0126 Jul 3, 2025
a2dfc3b
Merge branch 'main' into dev
jong-0126 Jul 3, 2025
75cc207
refactor: frontURI 수정, fail redirect URI 수정
jong-0126 Jul 3, 2025
7ab5655
Merge branch 'main' into dev
jong-0126 Jul 3, 2025
b8be542
Fix/279 로그인할때랑 같은 이메일 쓰면 연동되어야 하는데 안되던 문제 수정 해야 할 문제 수정 (#288)
Ksr-ccb Jul 3, 2025
caee534
fix: README 수정
Kimyoonbeom Jul 4, 2025
1757410
fix: 쿠키값 필요없어서 삭제, 오류페이지 더미 제작, XSS 방지, JSESSION SECURE 설정 (#291)
Ksr-ccb Jul 5, 2025
bf6c944
Fix/295 xss 적용 후 sse 에 파싱에러 해결 (#296)
Ksr-ccb Jul 5, 2025
0d50d46
Merge branch 'main' into dev
jong-0126 Jul 5, 2025
2963912
Feat/298 : 첫 구독 시, 바로 문제 풀이 링크 발송 (#299)
crocusia Jul 13, 2025
0e5105d
Update README.md
wannabeing Jul 14, 2025
cbdd9a3
chore: (#308)
jong-0126 Jul 15, 2025
8010f71
chore: READMD 수정
Kimyoonbeom Jul 18, 2025
ce1eabb
Feat/285: 무중단 배포 (#316)
jong-0126 Jul 23, 2025
775e584
chore: QuizPageService @Transactional readonly 설정하여 조회성능 향상 (#313)
wannabeing Jul 24, 2025
7fadb7e
Refact/292 XSS RequestBody적용, 정답률 필터링 추가필요 주석 추가 (#317)
Ksr-ccb Jul 24, 2025
adc4e1f
Merge branch 'main' into dev
Ksr-ccb Jul 24, 2025
ac3374f
Fix/319 ConflictingBeanDefinitionException 임시해결 (#320)
Ksr-ccb Jul 24, 2025
86fbc96
Merge branch 'main' into dev
Ksr-ccb Jul 24, 2025
1a7fb83
Fix/319-1 Json 파싱 에러 수정 (#322)
Ksr-ccb Jul 24, 2025
22756be
refactor : 정답 채점 개선 (#325)
crocusia Jul 24, 2025
dda8f2f
Refactor/310 : Ai피드백 Thread Woker 수 오토 스케일링 조절 리팩토링 (#326)
HeeMang-Lee Jul 25, 2025
36b7e7a
Chore/328 퀴즈 산정 로직 정비 1차 (#329)
Ksr-ccb Jul 25, 2025
5c609c0
refactor: AiService 삭제 및 Claude ChatClient에서 실제로 Bean 주입 (#332)
HeeMang-Lee Jul 25, 2025
71538e0
Refactor/314 : 중복처리 방지키TTL 설정 (#333)
HeeMang-Lee Jul 26, 2025
3777783
Refactor/324 : AI 채점 정답 판별 여부 개선 (#334)
crocusia Jul 29, 2025
d2c85b6
Refactor/294 : 전략 패턴 기반 메일 발송 방식 변경에 RateLimiter 설정 변경 추가 (#339)
crocusia Aug 4, 2025
db7b7ae
feat: 사용자 문제 풀때 로그 남기기 (#341)
jong-0126 Aug 6, 2025
89fd291
XssRequestWrapper에 MAX_DEPTH 설정 (#344)
Ksr-ccb Aug 8, 2025
7d6a04b
Feat/335 Brave Search(MCP) 도입 (#336)
HeeMang-Lee Aug 8, 2025
9da93b8
Refactor/345 Ai FeedBack Worker 동적 워커 축소 종료 조건 도입 (#346)
HeeMang-Lee Aug 8, 2025
6e39426
Merge remote-tracking branch 'origin/main' into dev
Ksr-ccb Aug 8, 2025
aa29e60
fix: 문제 제출 로그 코드레빗 수정 (#348)
jong-0126 Aug 8, 2025
38c6075
refactor/ MailLog JPA Distinct 추가 (#352)
Ksr-ccb Aug 8, 2025
261414c
chore : Bucket4J 빌드 수정 (#353)
crocusia Aug 8, 2025
b43fff0
Refactor/349 getTodayQuizBySubscription offset 오류 예외처리 추가 (#354)
Ksr-ccb Aug 8, 2025
1e9228b
chore : import문 추가 (#356)
crocusia Aug 8, 2025
b26cd78
chore : AI 피드백 길이 검증 부분 주석 처리 (#359)
crocusia Aug 8, 2025
980f08c
Revert "chore : AI 피드백 길이 검증 부분 주석 처리 (#359)" (#360)
crocusia Aug 8, 2025
ad8d7aa
chore : AI 피드백 유효성 검증 주석 처리 (#361)
crocusia Aug 8, 2025
b256946
Merge remote-tracking branch 'origin/main' into dev
crocusia Aug 8, 2025
b508652
feat : Long 타입 반환 메서드에 Query 추가 (#364)
crocusia Aug 11, 2025
3e1257c
chore: MCP 도입할 때 필요한 npx 패키지 적용 (#367)
wannabeing Aug 11, 2025
132fe02
chore: 런타임베이스이미지를 Ubuntu 계열로 변경하여 apt-get 명령어가 동작할 수 있게 변경 (#369)
wannabeing Aug 11, 2025
f725ffc
Merge branch 'main' into dev
wannabeing Aug 11, 2025
a7a7759
chore: MCP 설정의 배열 args의 null 예외 방지 (#371)
wannabeing Aug 11, 2025
6cc8a13
chore:자동 등록 비활성화 (#374)
HeeMang-Lee Aug 11, 2025
0742018
refactor: 코드에서 listTools()를 초기화 및 타임아웃 시간 연장 (#377)
HeeMang-Lee Aug 12, 2025
6ea98ba
Merge branch 'main' into dev
HeeMang-Lee Aug 12, 2025
034c3e8
Refactor/376 : 기존 MCP 서비스 사용 및 앱 부팅시 초기화 True 설정 (#379)
HeeMang-Lee Aug 12, 2025
ba63474
Merge branch 'main' into dev
HeeMang-Lee Aug 12, 2025
c362098
Refactor/376 : 도커파일 버젼 명시로 인한 빌드 실패 이슈 해결 (#381)
HeeMang-Lee Aug 12, 2025
b5dece4
Refactor/376 : 빌드시 MCP 스프링부트테스트로 타임아웃 발생 방지 (#383)
HeeMang-Lee Aug 12, 2025
0f992c4
chore:고정 변경사항 추적 (#386)
HeeMang-Lee Aug 12, 2025
d4dd83b
Chore/385 : 10차 배포 시기로 복귀 (#388)
HeeMang-Lee Aug 12, 2025
b411cbf
Chore/385 (#390)
HeeMang-Lee Aug 12, 2025
0d86a8c
Merge branch 'main' into dev
HeeMang-Lee Aug 12, 2025
0879420
chore: MCP 설정 변경 (#392)
wannabeing Aug 12, 2025
55aa066
Fix: MCP Brave Search 서버 경로 변경 (#394)
wannabeing Aug 12, 2025
ec70200
chore: MCP Brave Search 관련 Dockerfile도 롤백 (#396)
wannabeing Aug 12, 2025
c091ecb
chore: MCP 서버 전역설치 및 심볼릭 링크 생성, 빌드타임 확인 명령어 추가 (#398)
wannabeing Aug 12, 2025
ab94b80
Merge branch 'main' into dev
wannabeing Aug 12, 2025
59cba0e
Chore: 서비스모듈 Dockerfile 빌드확인 명령어 추가 (#400)
wannabeing Aug 12, 2025
76a15b3
Merge branch 'main' into dev
wannabeing Aug 12, 2025
8531558
refactor: 래퍼스크립트를 만들어 커맨드명 유지하도록 도커파일 수정 (#403)
HeeMang-Lee Aug 12, 2025
fd120df
Merge branch 'main' into dev
HeeMang-Lee Aug 12, 2025
c2980d6
Refactor/402 : MCP 서버 fix stdio args (#405)
HeeMang-Lee Aug 12, 2025
6dbbb70
Merge branch 'main' into dev
HeeMang-Lee Aug 12, 2025
757b4ec
Refactor : deprecated 패키지 제거, 공식 Brave MCP 서버 설치, 래퍼 스크립트로 server-br…
HeeMang-Lee Aug 12, 2025
ebeb30f
Merge branch 'main' into dev
HeeMang-Lee Aug 12, 2025
36d8b00
Chore: 앱 부팅 시 MCP 초기화 설정 (#409)
HeeMang-Lee Aug 13, 2025
a34fbb6
Refactor: Json파싱 표준화로 MCP Servie 리팩토링 (#412)
HeeMang-Lee Aug 13, 2025
62dde4e
Feat/414 : Ai피드백 Resilence4j를 활용한 CB,Retry 적용 (#415)
HeeMang-Lee Aug 18, 2025
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
52 changes: 21 additions & 31 deletions cs25-service/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -22,37 +22,27 @@ LABEL type="application" module="cs25-service"
# 작업 디렉토리
WORKDIR /apps

# Node.js 22 설치 + 공식 Brave MCP 서버 설치 + 래퍼 스크립트 생성
RUN apt-get update \
&& apt-get install -y --no-install-recommends curl ca-certificates gnupg bash \
&& curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
&& apt-get install -y --no-install-recommends nodejs \
\
# 공식 패키지 설치 (deprecated 패키지 제거)
&& npm install -g @brave/brave-search-mcp-server \
\
# 전역 모듈 경로 계산
&& NPM_PREFIX="$(npm prefix -g)" \
&& SRCDIR="${NPM_PREFIX}/lib/node_modules/@brave/brave-search-mcp-server" \
\
# 실행 래퍼 (args는 전부 "$@"로 위임)
&& { \
echo '#!/bin/sh'; \
echo 'NODE=$(command -v node || echo /usr/bin/node)'; \
echo 'exec "$NODE" "'"$SRCDIR"'/dist/index.js" "$@"'; \
} > /usr/local/bin/server-brave-search \
&& chmod 0755 /usr/local/bin/server-brave-search \
\
# 설치/실행 점검
&& echo "=== which server-brave-search ===" && which server-brave-search \
&& echo "=== server-brave-search --help ===" && server-brave-search --help || (echo "[ERROR] server-brave-search 실행 실패" && exit 1) \
\
# 정리
&& npm cache clean --force \
&& apt-get autoremove -y --purge \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

# Node.js 22 + Brave MCP 서버 설치 + 실행 래퍼 생성
RUN set -eux; \
apt-get update; \
apt-get install -y --no-install-recommends curl ca-certificates gnupg bash; \
curl -fsSL https://deb.nodesource.com/setup_22.x | bash -; \
apt-get install -y --no-install-recommends nodejs; \
npm install -g @brave/brave-search-mcp-server; \
NPM_PREFIX="$(npm prefix -g)"; \
SRCDIR="${NPM_PREFIX}/lib/node_modules/@brave/brave-search-mcp-server"; \
# 실행 래퍼 (전달 인자 전부 위임)
printf '%s\n' '#!/bin/sh' \
'exec node "'"$SRCDIR"'/dist/index.js" "$@"' \
> /usr/local/bin/server-brave-search; \
chmod 0755 /usr/local/bin/server-brave-search; \
# sanity check (없으면 빌드 실패)
/usr/local/bin/server-brave-search --help >/dev/null; \
# 정리
npm cache clean --force; \
apt-get purge -y gnupg; \
apt-get autoremove -y --purge; \
rm -rf /var/lib/apt/lists/*

# jar 복사
COPY --from=builder /build/cs25-service/build/libs/*.jar app.jar
Expand Down
6 changes: 6 additions & 0 deletions cs25-service/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ dependencies {
implementation "org.springframework.ai:spring-ai-starter-mcp-client:1.0.0"
implementation "org.springframework.ai:spring-ai-starter-mcp-client-webflux:1.0.0"

// resilience4j
implementation 'io.github.resilience4j:resilience4j-spring-boot3:2.3.0'
implementation 'io.github.resilience4j:resilience4j-circuitbreaker:2.3.0'
implementation 'io.github.resilience4j:resilience4j-retry:2.3.0'
implementation 'io.github.resilience4j:resilience4j-reactor:2.3.0'

//JavaMailSender
implementation 'jakarta.mail:jakarta.mail-api:2.1.0'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.example.cs25service.domain.ai.exception.AiException;
import com.example.cs25service.domain.ai.exception.AiExceptionCode;
import com.example.cs25service.domain.ai.resilience.AiResilience;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
Expand All @@ -11,18 +12,23 @@
public class ClaudeChatClient implements AiChatClient {

private final ChatClient anthropicChatClient;
private final AiResilience resilience;

public ClaudeChatClient(@Qualifier("anthropicChatClient") ChatClient anthropicChatClient) {
public ClaudeChatClient(@Qualifier("anthropicChatClient") ChatClient anthropicChatClient,
AiResilience resilience) {
this.anthropicChatClient = anthropicChatClient;
this.resilience = resilience;
}

@Override
public String call(String systemPrompt, String userPrompt) {
return anthropicChatClient.prompt()
.system(systemPrompt)
.user(userPrompt)
.call()
.content();
return resilience.executeSync("claude", () ->
anthropicChatClient.prompt()
.system(systemPrompt)
.user(userPrompt)
.call()
.content()
);
}

@Override
Expand All @@ -32,13 +38,12 @@ public ChatClient raw() {

@Override
public Flux<String> stream(String systemPrompt, String userPrompt) {
return anthropicChatClient.prompt()
.system(systemPrompt)
.user(userPrompt)
.stream()
.content()
.onErrorResume(error -> {
throw new AiException(AiExceptionCode.INTERNAL_SERVER_ERROR);
});
return resilience.executeStream("claude", () ->
anthropicChatClient.prompt()
.system(systemPrompt)
.user(userPrompt)
.stream()
.content()
).onErrorMap(e -> new AiException(AiExceptionCode.INTERNAL_SERVER_ERROR));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.example.cs25service.domain.ai.exception.AiException;
import com.example.cs25service.domain.ai.exception.AiExceptionCode;
import com.example.cs25service.domain.ai.resilience.AiResilience;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
Expand All @@ -11,19 +12,25 @@
public class OpenAiChatClient implements AiChatClient {

private final ChatClient openAiChatClient;
private final AiResilience resilience;

public OpenAiChatClient(@Qualifier("openAiChatModelClient") ChatClient openAiChatClient) {
public OpenAiChatClient(
@Qualifier("openAiChatModelClient") ChatClient openAiChatClient,
AiResilience resilience) {
this.openAiChatClient = openAiChatClient;
this.resilience = resilience;
}

@Override
public String call(String systemPrompt, String userPrompt) {
return openAiChatClient.prompt()
.system(systemPrompt)
.user(userPrompt)
.call()
.content()
.trim();
return resilience.executeSync("openai", () ->
openAiChatClient.prompt()
.system(systemPrompt)
.user(userPrompt)
.call()
.content()
.trim()
);
}

@Override
Expand All @@ -33,13 +40,12 @@ public ChatClient raw() {

@Override
public Flux<String> stream(String systemPrompt, String userPrompt) {
return openAiChatClient.prompt()
.system(systemPrompt)
.user(userPrompt)
.stream()
.content()
.onErrorResume(error -> {
throw new AiException(AiExceptionCode.INTERNAL_SERVER_ERROR);
});
return resilience.executeStream("openai", () ->
openAiChatClient.prompt()
.system(systemPrompt)
.user(userPrompt)
.stream()
.content()
).onErrorMap(e -> new AiException(AiExceptionCode.INTERNAL_SERVER_ERROR));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.example.cs25service.domain.ai.resilience;

import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
import io.github.resilience4j.reactor.circuitbreaker.operator.CircuitBreakerOperator;
import io.github.resilience4j.reactor.retry.RetryOperator;
import io.github.resilience4j.retry.Retry;
import io.github.resilience4j.retry.RetryRegistry;
import java.util.function.Supplier;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;

@Component
@RequiredArgsConstructor
public class AiResilience {

private final CircuitBreakerRegistry cbRegistry;
private final RetryRegistry retryRegistry;

/**
* 동기 호출: Retry → CircuitBreaker 순서
*/
public <T> T executeSync(String name, Supplier<T> supplier) {
CircuitBreaker cb = cbRegistry.circuitBreaker(name);
Retry retry = retryRegistry.retry(name);

Supplier<T> withRetry = Retry.decorateSupplier(retry, supplier);
Supplier<T> withCb = CircuitBreaker.decorateSupplier(cb, withRetry);

return withCb.get();
}
Comment on lines +24 to +32
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Sync 조합 순서가 반대입니다 — CircuitBreaker를 안쪽, Retry를 바깥으로 감싸야 각 재시도 시도마다 CB가 평가됩니다

현재 구현은 Retry → CircuitBreaker로 데코레이션되어 CB가 재시도 단건만 기록합니다. 일반적으로는 CB가 각 시도별로 실패/성공을 관찰하도록 CB를 안쪽에 두고 Retry가 바깥에서 재호출하도록 조합합니다. 이렇게 해야 실패율/슬라이딩 윈도우 메트릭이 의도대로 집계되고, 열림/닫힘 판단이 정확해집니다.

-    /**
-     * 동기 호출: Retry → CircuitBreaker 순서
-     */
+    /**
+     * 동기 호출: CircuitBreaker → Retry 순서
+     * (각 재시도 시도마다 CB가 권한 확인 및 성공/실패를 기록하도록 CB를 내부에 둡니다)
+     */
     public <T> T executeSync(String name, Supplier<T> supplier) {
         CircuitBreaker cb = cbRegistry.circuitBreaker(name);
         Retry retry = retryRegistry.retry(name);
 
-        Supplier<T> withRetry = Retry.decorateSupplier(retry, supplier);
-        Supplier<T> withCb = CircuitBreaker.decorateSupplier(cb, withRetry);
-
-        return withCb.get();
+        Supplier<T> withCb = CircuitBreaker.decorateSupplier(cb, supplier);
+        Supplier<T> withRetry = Retry.decorateSupplier(retry, withCb);
+        return withRetry.get();
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public <T> T executeSync(String name, Supplier<T> supplier) {
CircuitBreaker cb = cbRegistry.circuitBreaker(name);
Retry retry = retryRegistry.retry(name);
Supplier<T> withRetry = Retry.decorateSupplier(retry, supplier);
Supplier<T> withCb = CircuitBreaker.decorateSupplier(cb, withRetry);
return withCb.get();
}
/**
* 동기 호출: CircuitBreakerRetry 순서
* ( 재시도 시도마다 CB가 권한 확인 성공/실패를 기록하도록 CB를 내부에 둡니다)
*/
public <T> T executeSync(String name, Supplier<T> supplier) {
CircuitBreaker cb = cbRegistry.circuitBreaker(name);
Retry retry = retryRegistry.retry(name);
Supplier<T> withCb = CircuitBreaker.decorateSupplier(cb, supplier);
Supplier<T> withRetry = Retry.decorateSupplier(retry, withCb);
return withRetry.get();
}
🤖 Prompt for AI Agents
In
cs25-service/src/main/java/com/example/cs25service/domain/ai/resilience/AiResilience.java
around lines 24 to 32, the Supplier decoration order is reversed — currently
Retry wraps CircuitBreaker, so the CB only sees the overall retry result; swap
the order so CircuitBreaker wraps the raw supplier and Retry wraps that
CB-decorated supplier (i.e., apply CircuitBreaker.decorateSupplier(cb, supplier)
first, then Retry.decorateSupplier(retry, <cb-wrapped-supplier>)) so the
CircuitBreaker observes each individual attempt; update variable names
accordingly and keep return as withRetry.get().


/**
* Flux 스트리밍: RetryOperator → CircuitBreakerOperator 순서
*/
public <T> Flux<T> executeStream(String name, Supplier<Flux<T>> supplier) {
CircuitBreaker cb = cbRegistry.circuitBreaker(name);
Retry retry = retryRegistry.retry(name);

return supplier.get()
.transformDeferred(RetryOperator.of(retry))
.transformDeferred(CircuitBreakerOperator.of(cb));
}
Comment on lines +37 to +44
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Reactor 스트림 조합 순서도 반대입니다 — CircuitBreakerOperator 먼저, RetryOperator를 마지막에 적용하세요

지금은 RetryOperator → CircuitBreakerOperator 순서라 CB가 재시도 묶음 전체만 관찰합니다. CB가 각 시도를 관찰하도록 아래처럼 순서를 바꿔 주세요.

     public <T> Flux<T> executeStream(String name, Supplier<Flux<T>> supplier) {
         CircuitBreaker cb = cbRegistry.circuitBreaker(name);
         Retry retry = retryRegistry.retry(name);
 
         return supplier.get()
-            .transformDeferred(RetryOperator.of(retry))
-            .transformDeferred(CircuitBreakerOperator.of(cb));
+            .transformDeferred(CircuitBreakerOperator.of(cb))  // CB를 내부에
+            .transformDeferred(RetryOperator.of(retry));       // Retry를 외부에
     }
🤖 Prompt for AI Agents
In
cs25-service/src/main/java/com/example/cs25service/domain/ai/resilience/AiResilience.java
around lines 37 to 44, the Reactor operator order is reversed: currently
RetryOperator is applied before CircuitBreakerOperator so the CircuitBreaker
observes the whole retry sequence; change the operator application order so the
CircuitBreakerOperator is applied first and the RetryOperator after it (i.e.,
transformDeferred(CircuitBreakerOperator.of(cb)) then
transformDeferred(RetryOperator.of(retry))) so the circuit breaker observes each
individual retry attempt.

}
Loading