Skip to content
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

[Feat/#613] GPT 생성 컨텐츠 조회 API 추가 #614

Merged
merged 11 commits into from
Mar 18, 2025
Merged

Conversation

hun-ca
Copy link
Member

@hun-ca hun-ca commented Mar 14, 2025

🎫 연관 이슈

resolved #613

💁‍♂️ PR 내용

🙏 작업

  • 컨텐츠 ID 기반 조회 API 구현 (raw content id 기반 조회)
  • JPA 엔티티 기본 생성자 임시 추가
  • gen, provisioning_contents 테이블에 인덱스 추가

🙈 PR 참고 사항

📸 스크린샷

image

Response Example

{
    "data": {
        "rawContents": {
            "id": 3,
            "url": "https://www.wowtv.co.kr/NewsCenter/News/Read?articleId=A202503160014&t=NN",
            "title": "증시 버팀목 연기금 이상기류폭풍매수세 꺾였다 | 한국경제TV",
            "description": "올해 들어 국내 증시 하방 지지 역할을 톡톡히 해온 국민연금 등 연기금의 최근 움직임이 심상치 않다.  지난해 말 부터 이어온 순매수 랠리가 최근 종료됐는데 수급 측면에서 국내 증시 영향 여부는 물론, 향후 재...",
            "thumbnailImageUrl": "https://img.wowtv.co.kr/wowtv_news/dnrs/20250316/B20250316072324483.jpg",
            "rawTexts": "HOME 뉴스 전체뉴스 증시 버팀목 연기금 '이상기류'…폭풍매수세 '꺾였다' 페이스북 노출 0 정경준 기자 입력 2025-03-16 07:26 수정 2025-03-16 07:55 구독 닫기 재미있게 보셨나요?- 구독은 기자에게 큰 힘이 됩니다.\n한경TV는 귀하의 경제 습관에 도움을 드립니다.\n지금 경제 소식 구독하고 소중한 자산을 모으고 불리세요.\n- 지금 보시는 기사의 기자를 구독하세요.\n새로운 뉴스를 이메일로 알려 드립니다.\n한경TV 유튜브 채널 한경TV 네이버 뉴스 홈 한경TV 다음 뉴스 홈 한경TV 카카오 플러스친구 공유 닫기 SNS 보내기 URL복사 페이스북 네이버 블로그 카카오스토리 글자 크기 닫기 글자 크기 설정 크게 작게 인쇄 번역 닫기 번역- G언어 선택 한국어 영어 일본어 중국어(간체) 중국어(번체) 베트남어 증시 버팀목 연기금 '이상기류'…폭풍매수세 '꺾였다' SITE MAP [와우넷 오늘장전략] 금값 최고치 경신, 서울보증보험 신규상장 - 와우넷 오늘장전략 더보기 [굿모닝 주식창] 미국 셧다운 우려 확산 안전 자산 선호 ↑ - [굿모닝 주식창] 더보기 [앱으로 보는 시장] 폴라리스 그룹주, 테슬라 협업 기대감에 상승세- [앱으로 보는 시장] 더보기 '역대 최장' 42일 순매수랠리 '종료' 올해 들어 국내 증시 하방 지지 역할을 톡톡히 해온 국민연금 등 연기금의 최근 움직임이 심상치 않다.\n지난해 말 부터 이어온 순매수 랠리가 최근 종료됐는데 수급 측면에서 국내 증시 영향 여부는 물론, 향후 재개 여부 등을 놓고 관심이 집중되고 있다.\n16일 한국거래소에 따르면, 국민연금 등 연기금은 지난해 12월 27일부터 이달 5일까지 42거래일 연속으로 코스피를 순매수하다 지난 6일 5억원 규모의 순매도를 기록했다.\n이후 11∼13일 3거래일 연속 200∼400억원대의 순매도를 기록하면서 그간의 순매수랠리를 마무리하는 모습을 보였다.\n역대 최장인 42거래일간 연기금의 순매수 규모는 3조5,460억원으로, 일평균 844억원이었다.\n기존 최장 순매수 기록인 32거래일간(2011년 11월 10일∼12월 23일) 총 2조2천23억원, 일평균 688억원 대비 기간은 물론 순매수 규모도 컸다.\n당장 시장의 관심은 올해 들어 연기금이 국내 증시의 하방을 지지하는 역할을 해온 만큼 연기금의 '폭풍매수'가 재개될지다.\n연합뉴스에 따르면, 이경민 대신증권 연구원은 \"연기금의 매수 기조는 유효하다\"며 \"국내 주식 비중확대 여력이 여전히 큰 가운데 올해 상반기 중 10조원 이상 순매수가 가능할 것으로 본다\"고 내다봤다.\n반면 김중원 현대차증권 연구원은 \"올해 국내 주식이 연기금의 다른 자산보다 높은 수익률을 기록하고 있어 TAA(전술적 자산배분) 허용범위 조정이 곧 마무리될 것으로 예상된다\"며 연기금의 영향력이 줄어들 가능성을 언급했다.\n김 연구원은 \"TAA 허용 범위 조정이 마무리되고 이달 말 국내 증시 공매도가 전면 재개되면 외국인 투자자의 영향력이 확대될 것\"이라고 전망했다.\n증권가에선 저점 매수에 집중하는 연기금 자금의 특성상 연기금이 매수한 업종·종목에는 '역발상'으로 접근해야 한다고 조언한다.\n강진혁 신한투자증권 연구원은 \"국민연금 등 연기금은 추세 추종보다는 저점매수에 더욱 집중한다\"며 \"연기금 수급은 얼마나 더 오를지보다 시장의 하단을 추정하고 확인하는 데 의의가 있다\"고 분석했다.\n증시 버팀목 연기금 순매수 국내 와우넷 오늘장전략 좋아요 00 싫어요 00 후속기사 원해요 00 관련뉴스 마이핀 코로나연준AI러시아 tab area 뉴스 기자 방송 파트너 24시클럽 홀짝박사 송재호대표 김경진 와우캐시 와우넷에서 실제 현금과 동일하게 사용되는 사이버머니 캐시충전 서비스 상품 파트너방송 증권·부동산 교육 월정액 서비스 파트너 방송 GOLD 한국경제 TV 실시간 방송 구매하기 이용안내 GOLD PLUS 골드서비스 + VOD 주식강좌 구매하기 이용안내 파트너 방송 파트너방송 + 녹화방송 + 회원전용게시판 +SMS증권정보 + 골드플러스 서비스 구매하기 이용안내 고객센터 강연회·행사 더보기 7일간 등록된 일정이 없습니다.\n이벤트 7일간 등록된 일정이 없습니다.\n공지사항 더보기 [한국경제TV] [공지] 와우넷 사이트 정기 점검 안내 입니다.\n1:1문의하기 시민제보하기 open 인쇄하기 닫기 인쇄하기 인쇄 2025-03-16 07:55 수정 증시 버팀목 연기금 '이상기류'…폭풍매수세 '꺾였다' '역대 최장' 42일 순매수랠리 '종료' 올해 들어 국내 증시 하방 지지 역할을 톡톡히 해온 국민연금 등 연기금의 최근 움직임이 심상치 않다.\n한국경제TV 디지털뉴스부 정경준 기자 [email protected]\n증시 버팀목 연기금 '이상기류'…폭풍매수세 '꺾였다'\n구독은 기자에게 큰 힘이 됩니다.\n한경TV 네이버 뉴스 홈\n한경TV 다음 뉴스 홈\n[와우넷 오늘장전략] 금값 최고치 경신, 서울보증보험 신규상장 - 와우넷 오늘장전략\n[굿모닝 주식창] 미국 셧다운 우려 확산 안전 자산 선호 ↑ - [굿모닝 주식창]\n[앱으로 보는 시장] 폴라리스 그룹주, 테슬라 협업 기대감에 상승세- [앱으로 보는 시장]\n'역대 최장' 42일 순매수랠리 '종료'\n올해 들어 국내 증시 하방 지지 역할을 톡톡히 해온 국민연금 등 연기금의 최근 움직임이 심상치 않다.\n한국경제 TV 실시간 방송\n골드서비스 + VOD 주식강좌\n파트너방송 + 녹화방송 + 회원전용게시판\n+SMS증권정보 + 골드플러스 서비스\n7일간 등록된 일정이 없습니다.\n[한국경제TV] [공지] 와우넷 사이트 정기 점검 안내 입니다.\n증시 버팀목 연기금 '이상기류'…폭풍매수세 '꺾였다'\n증시 버팀목 연기금 순매수 국내 와우넷 오늘장전략 좋아요 00 싫어요 00 후속기사 원해요 00 관련뉴스\n증시 버팀목 연기금 '이상기류'…폭풍매수세 '꺾였다' 페이스북 노출 0 정경준 기자 입력 2025-03-16 07:26 수정 2025-03-16 07:55 구독 닫기 재미있게 보셨나요?- 구독은 기자에게 큰 힘이 됩니다.\n한경TV 유튜브 채널 한경TV 네이버 뉴스 홈 한경TV 다음 뉴스 홈 한경TV 카카오 플러스친구 공유 닫기 SNS 보내기 URL복사 페이스북 네이버 블로그 카카오스토리 글자 크기 닫기 글자 크기 설정 크게 작게 인쇄 번역 닫기 번역- G언어 선택 한국어 영어 일본어 중국어(간체) 중국어(번체) 베트남어\n페이스북 노출 0 정경준 기자 입력 2025-03-16 07:26 수정 2025-03-16 07:55 구독 닫기 재미있게 보셨나요?- 구독은 기자에게 큰 힘이 됩니다.\n페이스북 노출 0 정경준 기자 입력 2025-03-16 07:26 수정 2025-03-16 07:55\n입력 2025-03-16 07:26 수정 2025-03-16 07:55\n구독 닫기 재미있게 보셨나요?- 구독은 기자에게 큰 힘이 됩니다.\n한경TV 유튜브 채널 한경TV 네이버 뉴스 홈 한경TV 다음 뉴스 홈 한경TV 카카오 플러스친구\n닫기 재미있게 보셨나요?- 구독은 기자에게 큰 힘이 됩니다.\n공유 닫기 SNS 보내기 URL복사 페이스북 네이버 블로그 카카오스토리\n닫기 SNS 보내기 URL복사 페이스북 네이버 블로그 카카오스토리\n글자 크기 닫기 글자 크기 설정 크게 작게\n닫기 글자 크기 설정 크게 작게\n번역 닫기 번역- G언어 선택 한국어 영어 일본어 중국어(간체) 중국어(번체) 베트남어\n닫기 번역- G언어 선택 한국어 영어 일본어 중국어(간체) 중국어(번체) 베트남어\n증시 버팀목 연기금 '이상기류'…폭풍매수세 '꺾였다' SITE MAP [와우넷 오늘장전략] 금값 최고치 경신, 서울보증보험 신규상장 - 와우넷 오늘장전략 더보기 [굿모닝 주식창] 미국 셧다운 우려 확산 안전 자산 선호 ↑ - [굿모닝 주식창] 더보기 [앱으로 보는 시장] 폴라리스 그룹주, 테슬라 협업 기대감에 상승세- [앱으로 보는 시장] 더보기\n증시 버팀목 연기금 '이상기류'…폭풍매수세 '꺾였다' SITE MAP\n[와우넷 오늘장전략] 금값 최고치 경신, 서울보증보험 신규상장 - 와우넷 오늘장전략 더보기 [굿모닝 주식창] 미국 셧다운 우려 확산 안전 자산 선호 ↑ - [굿모닝 주식창] 더보기 [앱으로 보는 시장] 폴라리스 그룹주, 테슬라 협업 기대감에 상승세- [앱으로 보는 시장] 더보기\n'역대 최장' 42일 순매수랠리 '종료' 올해 들어 국내 증시 하방 지지 역할을 톡톡히 해온 국민연금 등 연기금의 최근 움직임이 심상치 않다.\n증시 버팀목 연기금 순매수 국내 와우넷 오늘장전략\n좋아요 00 싫어요 00 후속기사 원해요 00\n마이핀 코로나연준AI러시아 tab area 뉴스 기자 방송 파트너 24시클럽 홀짝박사 송재호대표 김경진 와우캐시 와우넷에서 실제 현금과 동일하게 사용되는 사이버머니 캐시충전 서비스 상품 파트너방송 증권·부동산 교육 월정액 서비스 파트너 방송 GOLD 한국경제 TV 실시간 방송 구매하기 이용안내 GOLD PLUS 골드서비스 + VOD 주식강좌 구매하기 이용안내 파트너 방송 파트너방송 + 녹화방송 + 회원전용게시판 +SMS증권정보 + 골드플러스 서비스 구매하기 이용안내 고객센터 강연회·행사 더보기 7일간 등록된 일정이 없습니다.\n마이핀 코로나연준AI러시아 tab area 뉴스 기자 방송 파트너 24시클럽 홀짝박사 송재호대표 김경진\n코로나연준AI러시아 tab area 뉴스 기자 방송 파트너 24시클럽 홀짝박사 송재호대표 김경진\ntab area 뉴스 기자 방송 파트너\n뉴스 기자 방송 파트너\n24시클럽 홀짝박사 송재호대표 김경진\n와우캐시 와우넷에서 실제 현금과 동일하게 사용되는 사이버머니 캐시충전 서비스 상품 파트너방송 증권·부동산 교육 월정액 서비스 파트너 방송 GOLD 한국경제 TV 실시간 방송 구매하기 이용안내 GOLD PLUS 골드서비스 + VOD 주식강좌 구매하기 이용안내 파트너 방송 파트너방송 + 녹화방송 + 회원전용게시판 +SMS증권정보 + 골드플러스 서비스 구매하기 이용안내\n와우넷에서 실제 현금과 동일하게 사용되는 사이버머니 캐시충전 서비스 상품 파트너방송 증권·부동산 교육 월정액 서비스 파트너 방송 GOLD 한국경제 TV 실시간 방송 구매하기 이용안내 GOLD PLUS 골드서비스 + VOD 주식강좌 구매하기 이용안내 파트너 방송 파트너방송 + 녹화방송 + 회원전용게시판 +SMS증권정보 + 골드플러스 서비스 구매하기 이용안내\n와우넷에서 실제 현금과 동일하게 사용되는 사이버머니 캐시충전 서비스 상품 파트너방송 증권·부동산 교육\n와우넷에서 실제 현금과 동일하게 사용되는 사이버머니 캐시충전\n월정액 서비스 파트너 방송 GOLD 한국경제 TV 실시간 방송 구매하기 이용안내 GOLD PLUS 골드서비스 + VOD 주식강좌 구매하기 이용안내 파트너 방송 파트너방송 + 녹화방송 + 회원전용게시판 +SMS증권정보 + 골드플러스 서비스 구매하기 이용안내\nGOLD 한국경제 TV 실시간 방송 구매하기 이용안내 GOLD PLUS 골드서비스 + VOD 주식강좌 구매하기 이용안내 파트너 방송 파트너방송 + 녹화방송 + 회원전용게시판 +SMS증권정보 + 골드플러스 서비스 구매하기 이용안내\nGOLD 한국경제 TV 실시간 방송 구매하기 이용안내\nGOLD 한국경제 TV 실시간 방송\nGOLD PLUS 골드서비스 + VOD 주식강좌 구매하기 이용안내\nGOLD PLUS 골드서비스 + VOD 주식강좌\n파트너 방송 파트너방송 + 녹화방송 + 회원전용게시판 +SMS증권정보 + 골드플러스 서비스 구매하기 이용안내\n파트너 방송 파트너방송 + 녹화방송 + 회원전용게시판 +SMS증권정보 + 골드플러스 서비스\n고객센터 강연회·행사 더보기 7일간 등록된 일정이 없습니다.\n강연회·행사 더보기 7일간 등록된 일정이 없습니다.\n인쇄하기 닫기 인쇄하기 인쇄 2025-03-16 07:55 수정 증시 버팀목 연기금 '이상기류'…폭풍매수세 '꺾였다' '역대 최장' 42일 순매수랠리 '종료' 올해 들어 국내 증시 하방 지지 역할을 톡톡히 해온 국민연금 등 연기금의 최근 움직임이 심상치 않다.\n인쇄하기 인쇄 2025-03-16 07:55 수정 증시 버팀목 연기금 '이상기류'…폭풍매수세 '꺾였다' '역대 최장' 42일 순매수랠리 '종료' 올해 들어 국내 증시 하방 지지 역할을 톡톡히 해온 국민연금 등 연기금의 최근 움직임이 심상치 않다.\n2025-03-16 07:55 수정 증시 버팀목 연기금 '이상기류'…폭풍매수세 '꺾였다' '역대 최장' 42일 순매수랠리 '종료' 올해 들어 국내 증시 하방 지지 역할을 톡톡히 해온 국민연금 등 연기금의 최근 움직임이 심상치 않다.\n2025-03-16 07:55 수정 증시 버팀목 연기금 '이상기류'…폭풍매수세 '꺾였다'",
            "imageUrls": [
                "https://img.wowtv.co.kr/wowtv_news/dnrs/20250316/B20250316072324483.jpg",
                "https://img.wowtv.co.kr/PcStyle/images/common/btn_quick_top.png",
                "https://img.wowtv.co.kr/PcStyle/images/common/btn_quick_01.png",
                "https://img.wowtv.co.kr/PcStyle/images/common/btn_quick_02.png",
                "https://img.wowtv.co.kr/PcStyle/images/common/btn_quick_03.png",
                "https://img.wowtv.co.kr/PcStyle/images/common/btn_quick_04.png",
                "https://img.wowtv.co.kr/PcStyle/images/common/btn_quick_05.png",
                "https://img.wowtv.co.kr/PcStyle/images/common/btn_quick_06.png",
                "https://img.wownet.co.kr//wownet20/partner/thumbnail/P303/13_200x130.png",
                "https://img.wownet.co.kr//wownet20/partner/thumbnail/HI626/13_200x130.png",
                "https://img.wownet.co.kr//front/partner/photo/202205/20220530b8c686204fc447d08336bc0fb8752f15.png"
            ],
            "createdAt": "2025-03-16 21:35:57"
        },
        "provisioningContents": {
            "id": 3,
            "rawContentsId": 3,
            "completionIds": [
                "chatcmpl-BBhVeHLF6ps4mezgAJB0hkLxP830H",
                "chatcmpl-BBhVn5QVHabPSjrvkRMAVjquND5P4"
            ],
            "bodyTextsJson": [
                "올해 들어 국내 증시 하방 지지 역할을 톡톡히 해온 국민연금 등 연기금의 최근 움직임이 심상치 않다.",
                "지난해 말 부터 이어온 순매수 랠리가 최근 종료됐는데 수급 측면에서 국내 증시 영향 여부는 물론, 향후 재개 여부 등을 놓고 관심이 집중되고 있다.",
                "16일 한국거래소에 따르면, 국민연금 등 연기금은 지난해 12월 27일부터 이달 5일까지 42거래일 연속으로 코스피를 순매수하다 지난 6일 5억원 규모의 순매도를 기록했다.",
                "이후 11∼13일 3거래일 연속 200∼400억원대의 순매도를 기록하면서 그간의 순매수랠리를 마무리하는 모습을 보였다.",
                "역대 최장인 42거래일간 연기금의 순매수 규모는 3조5,460억원으로, 일평균 844억원이었다.",
                "기존 최장 순매수 기록인 32거래일간(2011년 11월 10일∼12월 23일) 총 2조2천23억원, 일평균 688억원 대비 기간은 물론 순매수 규모도 컸다.",
                "당장 시장의 관심은 올해 들어 연기금이 국내 증시의 하방을 지지하는 역할을 해온 만큼 연기금의 '폭풍매수'가 재개될지다.",
                "연합뉴스에 따르면, 이경민 대신증권 연구원은 \"연기금의 매수 기조는 유효하다\"\"국내 주식 비중확대 여력이 여전히 큰 가운데 올해 상반기 중 10조원 이상 순매수가 가능할 것으로 본다\"고 내다봤다.",
                "반면 김중원 현대차증권 연구원은 \"올해 국내 주식이 연기금의 다른 자산보다 높은 수익률을 기록하고 있어 TAA(전술적 자산배분) 허용범위 조정이 곧 마무리될 것으로 예상된다\"며 연기금의 영향력이 줄어들 가능성을 언급했다.",
                "김 연구원은 \"TAA 허용 범위 조정이 마무리되고 이달 말 국내 증시 공매도가 전면 재개되면 외국인 투자자의 영향력이 확대될 것\"이라고 전망했다.",
                "증권가에선 저점 매수에 집중하는 연기금 자금의 특성상 연기금이 매수한 업종·종목에는 '역발상'으로 접근해야 한다고 조언한다.",
                "강진혁 신한투자증권 연구원은 \"국민연금 등 연기금은 추세 추종보다는 저점매수에 더욱 집중한다\"\"연기금 수급은 얼마나 더 오를지보다 시장의 하단을 추정하고 확인하는 데 의의가 있다\"고 분석했다."
            ],
            "coreTextsJson": [
                "올해 들어 국내 증시 하방 지지 역할을 톡톡히 해온 국민연금 등 연기금의 최근 움직임이 심상치 않다.",
                "지난해 말 부터 이어온 순매수 랠리가 최근 종료됐는데 수급 측면에서 국내 증시 영향 여부는 물론, 향후 재개 여부 등을 놓고 관심이 집중되고 있다.",
                "16일 한국거래소에 따르면, 국민연금 등 연기금은 지난해 12월 27일부터 이달 5일까지 42거래일 연속으로 코스피를 순매수하다 지난 6일 5억원 규모의 순매도를 기록했다.",
                "이후 11∼13일 3거래일 연속 200∼400억원대의 순매도를 기록하면서 그간의 순매수랠리를 마무리하는 모습을 보였다.",
                "역대 최장인 42거래일간 연기금의 순매수 규모는 3조5,460억원으로, 일평균 844억원이었다.",
                "기존 최장 순매수 기록인 32거래일간(2011년 11월 10일∼12월 23일) 총 2조2천23억원, 일평균 688억원 대비 기간은 물론 순매수 규모도 컸다.",
                "당장 시장의 관심은 올해 들어 연기금이 국내 증시의 하방을 지지하는 역할을 해온 만큼 연기금의 '폭풍매수'가 재개될지다.",
                "연합뉴스에 따르면, 이경민 대신증권 연구원은 \"연기금의 매수 기조는 유효하다\"\"국내 주식 비중확대 여력이 여전히 큰 가운데 올해 상반기 중 10조원 이상 순매수가 가능할 것으로 본다\"고 내다봤다.",
                "반면 김중원 현대차증권 연구원은 \"올해 국내 주식이 연기금의 다른 자산보다 높은 수익률을 기록하고 있어 TAA(전술적 자산배분) 허용범위 조정이 곧 마무리될 것으로 예상된다\"며 연기금의 영향력이 줄어들 가능성을 언급했다.",
                "김 연구원은 \"TAA 허용 범위 조정이 마무리되고 이달 말 국내 증시 공매도가 전면 재개되면 외국인 투자자의 영향력이 확대될 것\"이라고 전망했다."
            ],
            "createdAt": "2025-03-16 21:36:17"
        },
        "gens": [
            {
                "id": 9,
                "provisioningContentsId": 3,
                "completionIds": [
                    "chatcmpl-BBhVyQTVTTZUvi6MoTTUAobwUBcvO",
                    "chatcmpl-BBhVySToY0U8UOWtfM1pHMzWusxUt"
                ],
                "headline": "국민연금의 순매수 종료와 국내 증시의 향후 전망: 연기금의 영향력 감소 가능성 분석",
                "summary": "국내 증시에서 국민연금 등 연기금의 최근 움직임이 주목받고 있다 올해 들어 연기금은 하방 지지 역할을 해왔으나 최근 순매수 랠리가 종료된 것으로 보인다 지난해 12월 27일부터 42거래일 연속으로 코스피를 순매수하다가 최근 5억원 규모의 순매도를 기록하며 매수세가 꺾였다 연기금의 순매수 규모는 3조5,460억원으로 역대 최장 기록을 세웠으나 앞으로의 매수 재개 여부에 대한 관심이 집중되고 있다 전문가들은 연기금의 매수 기조가 여전히 유효하다고 보지만 다른 자산에 비해 국내 주식의 수익률이 높아지면서 연기금의 영향력이 줄어들 가능성도 제기되고 있다",
                "highlightTexts": [],
                "type": "BASIC",
                "createdAt": "2025-03-16 21:36:38"
            },
            {
                "id": 10,
                "provisioningContentsId": 3,
                "completionIds": [
                    "chatcmpl-BBhW18XMCKp2jH8oY8ANa8JzG1uWb",
                    "chatcmpl-BBhW6dFujOVJA9E6VIMZWe3UO1O1p"
                ],
                "headline": "국민연금, 순매수 종료로 증시 영향?",
                "summary": "국민연금 등 연기금의 순매수 랠리가 종료되며 증시 영향이 우려됩니다. 42거래일 연속 순매수 후 최근 5억원 순매도를 기록하며 매수세가 꺾였습니다.\n전문가들은 연기금의 매수 기조가 여전히 유효하다고 보지만, 국내 주식의 수익률 상승으로 영향력이 감소할 가능성도 제기되고 있습니다.",
                "highlightTexts": [],
                "type": "KOREAN",
                "createdAt": "2025-03-16 21:36:38"
            },
            {
                "id": 11,
                "provisioningContentsId": 3,
                "completionIds": [
                    "chatcmpl-BBhW8kRxc419JgI1Jy1ug2ZPqL7iY",
                    "chatcmpl-BBhW9Rbkr1E9FHohPib5rF06D5fUB"
                ],
                "headline": "연기금 순매수 종료, 증시 영향은?",
                "summary": "국민연금 등 연기금의 순매수가 최근 종료되면서 국내 증시에 미치는 영향이 주목받고 있습니다. 지난해 12월 27일부터 42거래일간 3조5,460억원을 순매수한 연기금은 6일 이후 순매도로 전환했습니다. 전문가들은 연기금의 매수 기조가 여전히 유효하다고 보지만, TAA 조정이 마무리되면 외국인 투자자의 영향력이 확대될 것으로 예상하고 있습니다.",
                "highlightTexts": [
                    "연기금은 6일 이후 순매도로 전환했습니다."
                ],
                "type": "KOREAN_QUESTION",
                "createdAt": "2025-03-16 21:36:38"
            },
            {
                "id": 12,
                "provisioningContentsId": 3,
                "completionIds": [
                    "chatcmpl-BBhWBAhgCfwZOpS25rUQnnW7ysCYe",
                    "chatcmpl-BBhWCnDSRUS0nLVb0C7iKBJqBtlci"
                ],
                "headline": "국민연금, 42일 연속 순매수 종료",
                "summary": "국내 증시에서 국민연금 등 연기금의 최근 움직임이 주목받고 있습니다. 올해 들어 연기금은 하방 지지 역할을 해왔으나, 최근 순매수 랠리가 종료된 것으로 보입니다. 지난해 12월 27일부터 42거래일 연속으로 코스피를 순매수하다가 최근 5억원 규모의 순매도를 기록하며 매수세가 꺾였습니다. 연기금의 순매수 규모는 3조5,460억원으로 역대 최장 기록을 세웠으나, 앞으로의 매수 재개 여부에 대한 관심이 집중되고 있습니다.\n\n전문가들은 연기금의 매수 기조가 여전히 유효하다고 보지만, 다른 자산에 비해 국내 주식의 수익률이 높아지면서 연기금의 영향력이 줄어들 가능성도 제기되고 있습니다. 이러한 변화는 향후 증시의 방향성에 중요한 영향을 미칠 것으로 예상되며, 투자자들은 연기금의 움직임을 면밀히 살펴볼 필요가 있습니다.",
                "highlightTexts": [
                    "연기금은 하방 지지 역할을 해왔으나, 최근 순매수 랠리가 종료된 것으로 보입니다.",
                    "전문가들은 연기금의 매수 기조가 여전히 유효하다고 보지만, 다른 자산에 비해 국내 주식의 수익률이 높아지면서 연기금의 영향력이 줄어들 가능성도 제기되고 있습니다."
                ],
                "type": "KOREAN_LONG_QUESTION",
                "createdAt": "2025-03-16 21:36:38"
            }
        ]
    },
    "message": "성공"
}

🚩 추가된 SQL 운영계 실행계획

🤖 테스트 체크리스트

  • 체크 미완료
  • 체크 완료

Summary by CodeRabbit

  • New Features

    • 새 엔드포인트가 추가되어 원시 콘텐츠의 상세 정보를 조회할 수 있습니다.
    • API 요청 및 응답 포맷이 명시적으로 개선되어 데이터 교환의 안정성이 향상되었습니다.
    • 새롭게 구성된 응답 구조로 콘텐츠 관련 정보가 보다 체계적으로 제공됩니다.
    • 보안 설정 업데이트로 특정 경로에 대한 접근이 간소화되었습니다.
  • Refactor

    • 콘텐츠 생성 결과에 타입 코드가 추가되어 출력 데이터의 구분이 명확해졌습니다.
    • 내부 코드 구조가 정리되어 데이터 처리 효율이 개선되었습니다.

@hun-ca hun-ca self-assigned this Mar 14, 2025
Copy link

coderabbitai bot commented Mar 14, 2025

"""

Walkthrough

이번 PR은 생성된 컨텐츠 조회와 관련된 API 엔드포인트 및 내부 로직을 확장합니다.
새로운 /rawcontents/{id} 엔드포인트가 추가되어, 입력받은 ID를 기반으로 RawContents, ProvisioningContents 및 Gen 데이터를 조회하도록 구현되었습니다.
또한, 응답 구조를 위한 새로운 데이터 클래스와 기본 생성자, DB 인덱스 추가, Repository 메서드 확장, 서비스 및 전략 클래스의 상수 참조 변경 등이 포함되어 있습니다.

Changes

File(s) Change Summary
domain/generator/src/main/kotlin/com/few/generator/controller/(ContentsGeneratorController.kt, response/BrowseContentsResponse.kt)
library/web/src/main/kotlin/web/security/config/LocalDelegatedSecurityConfigurer.kt
/rawcontents/{id} 엔드포인트 추가, create 메서드의 consumes/produces 명시, 응답 구조를 위한 새로운 데이터 클래스 도입, 보안 설정에 /api/v1/rawcontents/** 요청 매처 추가.
domain/generator/src/main/kotlin/com/few/generator/domain/(Gen.kt, ProvisioningContents.kt, RawContents.kt)
domain/generator/src/main/kotlin/com/few/generator/repository/(GenRepository.kt, ProvisioningContentsRepository.kt)
DB 인덱스 추가, 기본 생성자 및 새로운 속성(typeCode) 도입, 관련 Repository 메서드(findByProvisioningContentsId, findByRawContentsId) 추가.
domain/generator/src/main/kotlin/com/few/generator/usecase/(RawContentsBrowseContentUseCase.kt, out/BrowseContentsUsecaseOut.kt)
domain/generator/src/main/kotlin/com/few/generator/service/(GenService.kt, strategy/*)
새 UseCase와 응답 아웃풋 클래스 추가, 서비스에서 상수 참조를 Constant.GEN으로 변경 및 전략 클래스들에서 typeCode 속성 추가, 전략 인터페이스의 companion object 제거 및 관련 어노테이션 수정.
domain/generator/src/main/kotlin/com/few/generator/(support/common/Constant.kt, domain/GenType.kt) 새로운 상수 관리용 추상 클래스와 enum 타입(GenType) 도입, 전략명 및 타입 코드를 체계적으로 관리하도록 수정.

Sequence Diagram(s)

sequenceDiagram
    participant C as Client
    participant Ctrl as ContentsGeneratorController
    participant UC as RawContentsBrowseContentUseCase
    participant RCR as RawContentsRepository
    participant PCR as ProvisioningContentsRepository
    participant GR as GenRepository
    participant Resp as ApiResponseGenerator

    C->>Ctrl: GET /rawcontents/{id}
    Ctrl->>UC: execute(rawContentsId)
    UC->>RCR: findById(rawContentsId)
    RCR-->>UC: RawContents 데이터
    UC->>PCR: findByRawContentsId(rawContentsId)
    PCR-->>UC: ProvisioningContents 데이터
    UC->>GR: findByProvisioningContentsId(provisioningContentsId)
    GR-->>UC: List<Gen> 데이터
    UC-->>Ctrl: BrowseContentsUsecaseOut 구성
    Ctrl->>Resp: ApiResponseGenerator.success(결과)
    Resp-->>C: API 응답 반환
Loading

Assessment against linked issues

Objective Addressed Explanation
GET /api/v1/rawcontents/{id} (생성된 컨텐츠 조회 API)
GET /api/v1/provcontents/{id} 및 GET /api/v1/gens/{id} (생성된 컨텐츠 조회 API) 해당 엔드포인트들이 별도로 구현되지 않음.

Poem

나는 깡총깡총 토끼, 코드 숲을 누비네,
새로운 API가 내 당근처럼 빛나네.
응답 구조는 꽃처럼 피어나고,
DB 인덱스는 내 숨은 보물이라네.
전략의 변화에 귀를 기울이며,
한 걸음 한 걸음 코드 춤을 추네.
🐇🥕💕
"""

Tip

⚡🧪 Multi-step agentic review comment chat (experimental)
  • We're introducing multi-step agentic chat in review comments. This experimental feature enhances review discussions with the CodeRabbit agentic chat by enabling advanced interactions, including the ability to create pull requests directly from comments.
    - To enable this feature, set early_access to true under in the settings.
✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (3)
domain/generator/src/main/kotlin/com/few/generator/usecase/RawContentsBrowseContentUseCase.kt (1)

16-70: 유스케이스 구현이 잘 되었습니다만, 예외 처리 방식 개선 필요

컨텐츠 조회 API를 위한 유스케이스가 잘 구현되었습니다. 트랜잭션 설정도 읽기 전용으로 적절하게 설정되어 있습니다. 다만 몇 가지 개선 사항을 제안합니다:

  1. 일반 RuntimeException 대신 더 구체적인 예외 타입을 사용하는 것이 좋습니다.
  2. 널 체크를 위해 !! 연산자를 여러 곳에서 사용하고 있는데, 이는 코드가 실행 중에 예기치 않게 실패할 수 있는 위험이 있습니다.

다음과 같이 개선할 수 있습니다:

- .orElseThrow { RuntimeException("컨텐츠가 존재하지 않습니다.") }
+ .orElseThrow { NoSuchElementException("컨텐츠가 존재하지 않습니다.") }

- provisioningContentsRepository.findByRawContentsId(rawContents.id!!)
-     ?: throw RuntimeException("프로비저닝 컨텐츠가 존재하지 않습니다.")
+ provisioningContentsRepository.findByRawContentsId(rawContents.id)
+     ?: throw NoSuchElementException("프로비저닝 컨텐츠가 존재하지 않습니다.")

그리고 엔티티 ID에 안전하게 접근하는 확장 함수를 만들어 활용하는 것도 고려해보세요:

fun <T> T.requireId(): Long where T : BaseEntity {
    return id ?: throw IllegalStateException("엔티티 ID가 없습니다")
}
domain/generator/src/main/kotlin/com/few/generator/usecase/out/BrowseContentsUsecaseOut.kt (1)

5-39: 응답 클래스와 유스케이스 출력 클래스 간의 중복

BrowseContentsResponseBrowseContentsUsecaseOut 클래스 구조가 매우 유사합니다. 이런 중복은 유지보수 비용이 증가할 수 있습니다. 레이어 간 변환 로직을 간소화하기 위한 방법으로 매퍼 패턴 활용이나 공통 인터페이스 정의를 고려해보세요.

예를 들어, 매퍼 클래스를 도입하거나 확장 함수를 사용할 수 있습니다:

fun BrowseContentsUsecaseOut.toResponse(): BrowseContentsResponse {
    return BrowseContentsResponse(
        rawContents = rawContents.toResponse(),
        provisioningContents = provisioningContents.toResponse(),
        gens = gens.map { it.toResponse() }
    )
}

fun BrowseRawContentsUsecaseOut.toResponse(): BrowseRawContentsResponse {
    return BrowseRawContentsResponse(
        id = id,
        url = url,
        title = title,
        description = description,
        thumbnailImageUrl = thumbnailImageUrl,
        rawTexts = rawTexts,
        imageUrls = imageUrls,
        createdAt = createdAt
    )
}

// 다른 변환 함수들도 유사하게 구현
domain/generator/src/main/kotlin/com/few/generator/controller/ContentsGeneratorController.kt (1)

50-83: 응답 객체 생성 로직 분리 고려

현재 컨트롤러에서 복잡한 응답 객체를 직접 구성하고 있습니다. 이 매핑 로직은 단일 책임 원칙을 준수하기 위해 별도의 매퍼 클래스로 이동하는 것이 좋습니다. 또한 !! 연산자 사용에 주의가 필요합니다.

아래와 같이 매퍼 클래스를 만들어 사용하는 것을 고려해보세요:

// 매퍼 클래스 예시
object BrowseContentsResponseMapper {
    fun toResponse(useCaseOut: RawContentsBrowseContentUseCaseOutput): BrowseContentsResponse {
        return BrowseContentsResponse(
            rawContents = toRawContentsResponse(useCaseOut.rawContents),
            provisioningContents = toProvisioningContentsResponse(useCaseOut.provisioningContents),
            gens = useCaseOut.gens.map { toGenResponse(it) }
        )
    }
    
    private fun toRawContentsResponse(rawContents: RawContents): BrowseRawContentsResponse {
        return BrowseRawContentsResponse(
            id = rawContents.id ?: throw IllegalStateException("Raw contents ID cannot be null"),
            // 나머지 필드들...
        )
    }
    
    // 다른 매핑 메소드들...
}

// 컨트롤러에서 사용
return ApiResponseGenerator.success(
    BrowseContentsResponseMapper.toResponse(useCaseOut),
    HttpStatus.OK
)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fceba2e and 0e3cb96.

📒 Files selected for processing (9)
  • domain/generator/src/main/kotlin/com/few/generator/controller/ContentsGeneratorController.kt (3 hunks)
  • domain/generator/src/main/kotlin/com/few/generator/controller/response/BrowseContentsResponse.kt (1 hunks)
  • domain/generator/src/main/kotlin/com/few/generator/domain/BaseEntity.kt (1 hunks)
  • domain/generator/src/main/kotlin/com/few/generator/domain/Gen.kt (1 hunks)
  • domain/generator/src/main/kotlin/com/few/generator/domain/ProvisioningContents.kt (1 hunks)
  • domain/generator/src/main/kotlin/com/few/generator/repository/GenRepository.kt (1 hunks)
  • domain/generator/src/main/kotlin/com/few/generator/repository/ProvisioningContentsRepository.kt (1 hunks)
  • domain/generator/src/main/kotlin/com/few/generator/usecase/RawContentsBrowseContentUseCase.kt (1 hunks)
  • domain/generator/src/main/kotlin/com/few/generator/usecase/out/BrowseContentsUsecaseOut.kt (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: api-test
  • GitHub Check: lint
  • GitHub Check: docs
🔇 Additional comments (15)
domain/generator/src/main/kotlin/com/few/generator/repository/ProvisioningContentsRepository.kt (1)

6-8: 새로운 메서드 구현이 적절합니다.

rawContentsId로 ProvisioningContents를 조회하는 메서드가 추가되었습니다. 이 메서드는 Spring Data JPA의 명명 규칙을 따르고 있으며, PR 요약에 언급된 "ID로 컨텐츠를 조회하는 API" 구현에 필요한 기능입니다.

domain/generator/src/main/kotlin/com/few/generator/repository/GenRepository.kt (1)

6-8: 리포지토리 메서드 추가가 적절합니다.

provisioningContentsId를 기반으로 Gen 엔티티 목록을 조회하는 메서드가 추가되었습니다. Spring Data JPA 명명 규칙을 잘 따르고 있으며, 컨텐츠 ID를 통한 데이터 조회 기능 구현에 필요한 메서드입니다.

domain/generator/src/main/kotlin/com/few/generator/domain/BaseEntity.kt (1)

15-15: 변경된 필드 불변성이 적절합니다.

createdAt 필드가 var에서 val로 변경되어 불변(immutable)하게 만들어졌습니다. 생성 시간은 생성 후 변경되지 않아야 하므로 이는 좋은 변경사항입니다. 또한 @column(updatable = false) 애노테이션과도 잘 일치합니다.

domain/generator/src/main/kotlin/com/few/generator/domain/Gen.kt (1)

7-10: 인덱스 추가가 적절합니다.

Gen 테이블에 provisioning_contents_id 컬럼에 대한 인덱스를 추가했습니다. PR 요약에 언급된 "gen과 provisioning_contents 테이블에 인덱스 추가"에 해당하는 변경사항으로, GenRepository에 추가된 findByProvisioningContentsId 메서드의 성능을 향상시킬 것입니다.

domain/generator/src/main/kotlin/com/few/generator/domain/ProvisioningContents.kt (1)

7-10: 인덱스 추가로 인한 성능 개선 좋습니다!

raw_contents_id 컬럼에 unique 인덱스를 추가한 것은 쿼리 성능을 향상시키고 데이터 무결성을 보장하는 좋은 변경사항입니다. PR 목표에 언급된 대로 데이터베이스 성능 향상을 위한 인덱스 추가가 적절하게 구현되었습니다.

domain/generator/src/main/kotlin/com/few/generator/controller/response/BrowseContentsResponse.kt (4)

5-9: 응답 데이터 구조가 명확하게 정의되었습니다

BrowseContentsResponse 클래스가 API 응답 구조를 명확하게 정의하고 있습니다. 컨텐츠 조회를 위한 세 가지 주요 데이터(rawContents, provisioningContents, gens)를 포함하고 있어 클라이언트에서 데이터를 쉽게 접근할 수 있습니다.


11-20: 원본 컨텐츠 응답 구조가 잘 정의되었습니다

BrowseRawContentsResponse 클래스의 구조가 적절하게 정의되어 있습니다. 기본값과 널 허용 필드도 논리적으로 설정되어 있습니다.


22-29: 프로비저닝 컨텐츠 응답 구조가 잘 정의되었습니다

BrowseProvisioningContentsResponse 클래스의 구조가 적절하게 정의되어 있습니다. JSON 문자열 필드에 대한 기본값 설정이 잘 되어 있습니다.


31-39: 생성된 컨텐츠 응답 구조가 잘 정의되었습니다

BrowseGenResponse 클래스의 구조가 적절하게 정의되어 있습니다. 필요한 모든 필드가 포함되어 있고 기본값 설정도 잘 되어 있습니다.

domain/generator/src/main/kotlin/com/few/generator/usecase/out/BrowseContentsUsecaseOut.kt (1)

5-9: 유스케이스 출력 구조가 명확하게 정의되었습니다

BrowseContentsUsecaseOut 클래스가 유스케이스의 출력 구조를 명확하게 정의하고 있습니다. 컨트롤러 응답 클래스와 구조적으로 유사하여 매핑이 용이할 것입니다.

domain/generator/src/main/kotlin/com/few/generator/controller/ContentsGeneratorController.kt (5)

4-4: 필요한 클래스들이 올바르게 추가되었습니다!

새로운 기능을 위한 적절한 임포트가 추가되었습니다.

Also applies to: 6-7, 9-9


18-18: 의존성 주입이 올바르게 수행되었습니다.

컨트롤러에 RawContentsBrowseContentUseCase를 추가하여 새 엔드포인트를 지원합니다.


20-24: API 명세가 명확해져 좋습니다.

consumesproduces 속성을 명시적으로 지정하여 API 계약이 더 명확해졌습니다.


42-46: 경로 변수 검증이 잘 구현되었습니다.

@Min 어노테이션을 사용하여 ID 유효성 검사를 올바르게 구현했습니다.


41-85: 새 엔드포인트 구현이 잘 되었습니다.

ID로 컨텐츠를 조회하는 새 엔드포인트가 잘 구현되었습니다. 응답 구조가 명확하며 필요한 모든 데이터를 포함하고 있습니다.

BrowseContentsResponse(
rawContents =
BrowseRawContentsResponse(
id = useCaseOut.rawContents.id!!,
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Null 안전성 확보 필요

여러 곳에서 !! 연산자를 사용하고 있습니다. 이는 런타임에 NullPointerException을 발생시킬 수 있습니다. 데이터베이스에서 가져온 엔티티의 ID나 생성 시간이 null이 아니라고 확신할 수 있다면 문제가 없지만, 가능하면 ?.let 또는 ?: 연산자를 사용하여 null을 더 안전하게 처리하는 것이 좋습니다.

// 예시
id = useCaseOut.rawContents.id ?: throw IllegalStateException("Raw contents ID cannot be null"),
createdAt = useCaseOut.rawContents.createdAt ?: throw IllegalStateException("Created timestamp cannot be null"),

Also applies to: 60-60, 64-64, 69-69, 74-74, 80-80

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (7)
domain/generator/src/main/kotlin/com/few/generator/usecase/RawContentsBrowseContentUseCase.kt (7)

30-34: 예외 처리를 더 구체적으로 개선하는 것이 좋겠습니다.

일반적인 RuntimeException 대신 도메인에 특화된 예외 클래스를 사용하는 것이 좋습니다. 이렇게 하면 예외 처리가 더 명확해지고 호출자가 더 세밀하게 예외를 처리할 수 있습니다.

- .orElseThrow { RuntimeException("컨텐츠가 존재하지 않습니다.") }
+ .orElseThrow { ContentNotFoundException("컨텐츠가 존재하지 않습니다.") }

참고: ContentNotFoundException 클래스를 별도로 정의해야 합니다.


35-38: Null 검사 로직을 개선할 수 있습니다.

현재 코드에서는 null 체크와 예외 발생 로직이 한 줄에 있습니다. 가독성을 위해 로직을 분리하고, 커스텀 예외를 사용하는 것이 좋습니다.

- val provContents: ProvisioningContents =
-     provisioningContentsRepository.findByRawContentsId(rawContents.id!!)
-         ?: throw RuntimeException("프로비저닝 컨텐츠가 존재하지 않습니다.")
+ val provContents: ProvisioningContents = provisioningContentsRepository.findByRawContentsId(rawContents.id!!)
+     ?: throw ProvisioningContentNotFoundException("프로비저닝 컨텐츠가 존재하지 않습니다.")

44-52: null 아님 단언 연산자(!!) 사용에 주의가 필요합니다.

!! 연산자 사용은 코드가 깔끔해 보이지만 잠재적으로 NullPointerException을 발생시킬 수 있습니다. 데이터베이스에서 가져온 엔티티의 ID나 생성 시간이 null이 아닐 것으로 예상되지만, 안전을 위해 requireNotNull()이나 명시적인 null 체크를 고려해 보세요.

- id = rawContents.id!!,
+ id = requireNotNull(rawContents.id) { "Raw contents ID should not be null" },

유사한 변경을 다른 !! 사용 부분에도 적용할 수 있습니다.


50-51: JSON 파싱 성능 최적화를 고려해 보세요.

gson.fromJson을 사용한 JSON 파싱이 여러 곳에서 반복됩니다. 대용량 데이터를 처리할 경우 성능 저하가 발생할 수 있습니다. 재사용 가능한 TypeToken 인스턴스를 클래스 수준에서 정의하는 것이 좋습니다.

@Component
class RawContentsBrowseContentUseCase(
    private val rawContentsRepository: RawContentsRepository,
    private val provisioningContentsRepository: ProvisioningContentsRepository,
    private val genRepository: GenRepository,
    @Qualifier(GSON_BEAN_NAME)
    private val gson: Gson,
) {
+    private val stringListType = object : TypeToken<List<String>>() {}.type
    
    @GeneratorTransactional(readOnly = true)
    fun execute(rawContentsId: Long): BrowseContentsUsecaseOut {
        // ...
        
        return BrowseContentsUsecaseOut(
            rawContents =
                BrowseRawContentsUsecaseOut(
                    // ...
-                    imageUrls = gson.fromJson(rawContents.imageUrls, object : TypeToken<List<String>>() {}.type),
+                    imageUrls = gson.fromJson(rawContents.imageUrls, stringListType),
                    // ...
                ),
            // 다른 gson.fromJson 호출에도 동일하게 적용
        )
    }
}

41-74: 매핑 로직을 분리하여 가독성을 향상시키는 것이 좋습니다.

도메인 엔티티에서 DTO로의 변환 로직이 execute 메서드 내에 직접 구현되어 있습니다. 이 로직을 별도의 메서드나 매퍼 클래스로 분리하면 코드 가독성과 유지보수성이 향상됩니다.

예를 들어, 다음과 같이 매핑 메서드를 추가할 수 있습니다:

private fun mapRawContentsToOut(rawContents: RawContents): BrowseRawContentsUsecaseOut {
    return BrowseRawContentsUsecaseOut(
        id = requireNotNull(rawContents.id),
        url = rawContents.url,
        title = rawContents.title,
        description = rawContents.description,
        thumbnailImageUrl = rawContents.thumbnailImageUrl,
        rawTexts = rawContents.rawTexts,
        imageUrls = gson.fromJson(rawContents.imageUrls, stringListType),
        createdAt = requireNotNull(rawContents.createdAt),
    )
}

// 다른 엔티티에 대해서도 유사한 매핑 메서드 추가

그리고 execute 메서드에서는 이러한 매핑 메서드를 호출하여 코드의 가독성을 높일 수 있습니다.


64-73: Gen 엔티티 매핑 시 성능 최적화를 고려해 보세요.

gens.map { ... } 내부에서 각 Gen 엔티티마다 gson.fromJson을 호출하고 있습니다. Gen 리스트가 큰 경우 성능 저하가 발생할 수 있습니다. 앞서 제안한 stringListType 재사용과 함께, 매핑 로직을 별도 메서드로 분리하면 코드가 더 깔끔해집니다.


1-76: 기능적으로 잘 구현되었으나 코드 품질 향상을 위한 몇 가지 제안이 있습니다.

전반적으로 로직은 명확하게 구현되었으나, 다음 사항을 고려해 보세요:

  1. 구체적인 예외 클래스 사용
  2. Null 안전성 강화
  3. JSON 파싱 성능 최적화
  4. 매핑 로직 분리
  5. 단위 테스트 작성 (현재 파일에 포함되지 않음)

이러한 개선을 통해 코드의 안정성과 유지보수성을 더욱 높일 수 있습니다.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0e3cb96 and fe53f86.

📒 Files selected for processing (3)
  • domain/generator/src/main/kotlin/com/few/generator/controller/response/BrowseContentsResponse.kt (1 hunks)
  • domain/generator/src/main/kotlin/com/few/generator/usecase/RawContentsBrowseContentUseCase.kt (1 hunks)
  • domain/generator/src/main/kotlin/com/few/generator/usecase/out/BrowseContentsUsecaseOut.kt (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • domain/generator/src/main/kotlin/com/few/generator/usecase/out/BrowseContentsUsecaseOut.kt
  • domain/generator/src/main/kotlin/com/few/generator/controller/response/BrowseContentsResponse.kt
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: api-test
  • GitHub Check: docs
  • GitHub Check: lint
🔇 Additional comments (2)
domain/generator/src/main/kotlin/com/few/generator/usecase/RawContentsBrowseContentUseCase.kt (2)

20-27: 클래스 설계가 명확하며 의존성 주입이 잘 이루어졌습니다.

컴포넌트 구조와 의존성 주입이 적절하게 설계되었습니다. @Qualifier 어노테이션을 사용하여 특정 Gson 빈을 명시적으로 주입한 것이 좋습니다.


28-29: 트랜잭션 설정이 적절합니다.

읽기 전용 작업에 @GeneratorTransactional(readOnly = true)를 사용한 것은 좋은 방식입니다. 데이터베이스 성능 최적화에 도움이 됩니다.

@hun-ca hun-ca changed the title [WIP][Feat/#613] GPT 생성 컨텐츠 조회 API 추가 [Feat/#613] GPT 생성 컨텐츠 조회 API 추가 Mar 16, 2025
@hun-ca hun-ca requested a review from belljun3395 March 16, 2025 10:51
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
domain/generator/src/main/kotlin/com/few/generator/domain/ProvisioningContents.kt (1)

24-32: 기본 생성자 필요성 검토 필요

TODO 주석에서 언급하신 것처럼 이 기본 생성자의 필요성을 검토해보세요. JPA에서는 기본 생성자가 필요하지만, 일반적으로 public보다는 protected 접근 제어자를 사용하는 것이 권장됩니다. 또한, rawContentsId를 0L로 초기화하는 것이 비즈니스 로직에 맞는지 확인해주세요.

- constructor() : this( // TODO: 기본 생성자 필요?
+ protected constructor() : this( // JPA를 위한 기본 생성자

또한, 데이터 클래스와 JPA 엔티티 조합 시 프록시 생성과 지연 로딩에 문제가 발생할 수 있으니 주의하세요.

library/web/src/main/kotlin/web/security/config/LocalDelegatedSecurityConfigurer.kt (1)

112-115: 코드 주석 개선 필요

현재 generators 관련 경로에 대한 주석은 있지만, 새로 추가된 rawcontents 경로에 대한 설명이 없습니다. 코드 유지보수와 가독성을 위해 이 새로운 API 엔드포인트의 목적과 사용 사례에 대한 간략한 설명을 주석으로 추가하는 것이 좋습니다.

                    /**
                     * generator
                     */
                    AntPathRequestMatcher("/api/v1/generators/contents"),
+                    /**
+                     * raw contents
+                     * GPT 생성 컨텐츠 조회 API
+                     */
                    AntPathRequestMatcher("/api/v1/rawcontents/**"),
domain/generator/src/main/kotlin/com/few/generator/domain/Gen.kt (1)

27-34: 기본 생성자에 대한 검토 필요

기본 생성자는 JPA 엔티티에서 일반적으로 필요하지만, TODO 주석에서도 언급된 것처럼 이 생성자가 실제로 필요한지 검토가 필요합니다. Kotlin에서는 data class가 자동으로 생성자와 getter/setter를 생성하지만, JPA는 기본 생성자를 필요로 합니다.

JPA가 기본 생성자를 사용할 때에만 필요하므로, 프로덕션 코드에서 이 생성자를 직접 호출하지 않는다면 protected로 선언하는 것이 안전합니다:

-    constructor() : this( // TODO: 기본 생성자 필요?
+    protected constructor() : this( // JPA가 사용하는 기본 생성자
        id = null,
        provisioningContentsId = 0L,
        completionIds = mutableListOf(),
        headline = "",
        summary = "",
        highlightTexts = "[]",
    )

또한 TODO 주석은 코드 리뷰 과정에서 해결하고 제거하는 것이 좋습니다.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ec4ae65 and 063f903.

📒 Files selected for processing (5)
  • domain/generator/src/main/kotlin/com/few/generator/controller/response/BrowseContentsResponse.kt (1 hunks)
  • domain/generator/src/main/kotlin/com/few/generator/domain/Gen.kt (2 hunks)
  • domain/generator/src/main/kotlin/com/few/generator/domain/ProvisioningContents.kt (2 hunks)
  • domain/generator/src/main/kotlin/com/few/generator/domain/RawContents.kt (1 hunks)
  • library/web/src/main/kotlin/web/security/config/LocalDelegatedSecurityConfigurer.kt (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • domain/generator/src/main/kotlin/com/few/generator/controller/response/BrowseContentsResponse.kt
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: api-test
  • GitHub Check: docs
  • GitHub Check: lint
🔇 Additional comments (3)
domain/generator/src/main/kotlin/com/few/generator/domain/ProvisioningContents.kt (1)

7-10: 인덱스 추가 - 좋은 성능 개선!

unique 인덱스 추가는 데이터 무결성과 조회 성능 개선에 도움이 됩니다. 다만, 기존 데이터베이스에 중복된 raw_contents_id 값이 있는 경우 마이그레이션 시 오류가 발생할 수 있으니 이 부분을 고려해주세요.

library/web/src/main/kotlin/web/security/config/LocalDelegatedSecurityConfigurer.kt (1)

115-115: 보안 설정에 추가된 경로 패턴 확인 필요

새로 추가된 /api/v1/rawcontents/** 경로는 인증 및 권한 검사를 우회하게 됩니다. 이 엔드포인트가 공개적으로 접근 가능해야 하는 이유와 민감한 데이터가 노출되지 않는지 확인해주세요. 또한, 가능하다면 /api/v1/rawcontents/**와 같은 와일드카드보다 더 구체적인 경로 패턴(HTTP 메서드 제한 포함)을 사용하는 것이 보안 측면에서 더 안전할 수 있습니다.

-                    AntPathRequestMatcher("/api/v1/rawcontents/**"),
+                    AntPathRequestMatcher("/api/v1/rawcontents/**", HttpMethod.GET.name()),

위 수정안처럼 HTTP 메서드를 명시적으로 제한하는 것이 좋습니다.

domain/generator/src/main/kotlin/com/few/generator/domain/Gen.kt (1)

7-10: 테이블 인덱스 추가는 성능 향상에 도움이 됩니다.

provisioning_contents_id 컬럼에 인덱스를 추가한 것은 PR 목표에 부합하며 조회 성능을 향상시킬 것입니다. 이 필드를 기준으로 Gen 엔티티를 조회하는 쿼리가 최적화되어 콘텐츠 ID 기반 API 조회가 더 효율적으로 동작할 것입니다.

@hun-ca hun-ca linked an issue Mar 16, 2025 that may be closed by this pull request
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (4)
domain/generator/src/main/kotlin/com/few/generator/controller/response/BrowseContentsResponse.kt (2)

28-29: JSON 데이터 타입 고려

bodyTextsJsoncoreTextsJson은 현재 문자열 리스트로 정의되어 있습니다. 이 필드들이 JSON 형태의 데이터를 나타낸다면, 직렬화된 객체 대신 적절한 타입(예: Map 또는 구체적인 데이터 클래스)을 사용하는 것이 타입 안전성을 높일 수 있습니다.

데이터 구조가 명확하다면 다음과 같이 변경을 고려해 보세요:

- val bodyTextsJson: List<String>,
- val coreTextsJson: List<String>,
+ val bodyTexts: List<BodyTextData>,
+ val coreTexts: List<CoreTextData>,

여기서 BodyTextDataCoreTextData는 실제 데이터 구조를 반영하는 별도의 데이터 클래스입니다.


20-21: 날짜 형식 코드 중복 개선 고려

세 개의 클래스에서 동일한 @JsonFormat 어노테이션이 반복되고 있습니다. 이러한 중복을 줄이기 위해 커스텀 어노테이션이나 기본 클래스를 도입하는 것을 고려해 볼 수 있습니다.

// 예시: 커스텀 어노테이션 생성
@Target(AnnotationTarget.FIELD)
@Retention(AnnotationRetention.RUNTIME)
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
annotation class FormattedDateTime

// 사용 예시
@FormattedDateTime
val createdAt: LocalDateTime,

Also applies to: 30-31, 42-43

domain/generator/src/main/kotlin/com/few/generator/domain/GEN_TYPE.kt (1)

1-25: GEN_TYPE 열거형 추가 - 잘 설계된 타입 시스템

새로 추가된 GEN_TYPE 열거형은 다양한 생성 전략을 명확하게 구분하고 코드와 타이틀을 관리하는 잘 설계된 타입 시스템을 제공합니다. 또한 코드 및 타이틀을 통해 열거형을 조회하는 유틸리티 메서드도 제공하고 있습니다.

각 전략 유형에 비트 플래그처럼 보이는 숫자 코드(2, 4, 8, 16)를 사용한 것은 향후 확장성을 고려한 좋은 설계입니다.

다만, 열거형 선언 끝부분에 불필요한 세미콜론이 있으므로 제거를 고려해보세요. Kotlin에서는 필요하지 않습니다.

-    ;
domain/generator/src/main/kotlin/com/few/generator/domain/Gen.kt (1)

29-37: 기본 생성자에 대한 검토가 필요합니다.

코드에 TODO 코멘트로 표시된 것처럼 이 기본 생성자가 정말 필요한지 검토해 보세요. JPA에서는 기본 생성자가 필요하지만, 이를 protected로 설정하거나 Kotlin의 no-arg 플러그인을 사용하는 것이 더 안전할 수 있습니다.

또한 기본값들이 비즈니스 로직에 적합한지 확인하세요. 특히 빈 문자열이나 0 값이 도메인 관점에서 의미가 있는지 검토가 필요합니다.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 063f903 and 9990c78.

📒 Files selected for processing (13)
  • domain/generator/src/main/kotlin/com/few/generator/controller/ContentsGeneratorController.kt (2 hunks)
  • domain/generator/src/main/kotlin/com/few/generator/controller/response/BrowseContentsResponse.kt (1 hunks)
  • domain/generator/src/main/kotlin/com/few/generator/domain/GEN_TYPE.kt (1 hunks)
  • domain/generator/src/main/kotlin/com/few/generator/domain/Gen.kt (2 hunks)
  • domain/generator/src/main/kotlin/com/few/generator/service/GenService.kt (5 hunks)
  • domain/generator/src/main/kotlin/com/few/generator/service/strategy/BasicGenGenerationStrategy.kt (2 hunks)
  • domain/generator/src/main/kotlin/com/few/generator/service/strategy/GenGenerationStrategy.kt (0 hunks)
  • domain/generator/src/main/kotlin/com/few/generator/service/strategy/KoreanGenGenerationStrategy.kt (2 hunks)
  • domain/generator/src/main/kotlin/com/few/generator/service/strategy/KoreanLongQuestionGenGenerationStrategy.kt (2 hunks)
  • domain/generator/src/main/kotlin/com/few/generator/service/strategy/KoreanQuestionGenGenerationStrategy.kt (2 hunks)
  • domain/generator/src/main/kotlin/com/few/generator/support/common/Constant.kt (1 hunks)
  • domain/generator/src/main/kotlin/com/few/generator/usecase/RawContentsBrowseContentUseCase.kt (1 hunks)
  • domain/generator/src/main/kotlin/com/few/generator/usecase/out/BrowseContentsUsecaseOut.kt (1 hunks)
💤 Files with no reviewable changes (1)
  • domain/generator/src/main/kotlin/com/few/generator/service/strategy/GenGenerationStrategy.kt
✅ Files skipped from review due to trivial changes (2)
  • domain/generator/src/main/kotlin/com/few/generator/service/GenService.kt
  • domain/generator/src/main/kotlin/com/few/generator/support/common/Constant.kt
🚧 Files skipped from review as they are similar to previous changes (3)
  • domain/generator/src/main/kotlin/com/few/generator/usecase/RawContentsBrowseContentUseCase.kt
  • domain/generator/src/main/kotlin/com/few/generator/usecase/out/BrowseContentsUsecaseOut.kt
  • domain/generator/src/main/kotlin/com/few/generator/controller/ContentsGeneratorController.kt
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: api-test
  • GitHub Check: docs
  • GitHub Check: lint
🔇 Additional comments (21)
domain/generator/src/main/kotlin/com/few/generator/controller/response/BrowseContentsResponse.kt (6)

6-10: 응답 구조가 잘 설계되어 있습니다.

이 클래스는 컨텐츠 조회 API의 응답 구조를 명확하게 정의하고 있으며, 원시 컨텐츠, 프로비저닝 컨텐츠 및 생성된 컨텐츠 목록을 포함하는 계층적 구조가 잘 구성되어 있습니다.


12-22: 원시 컨텐츠 응답 클래스가 필요한 필드를 모두 포함하고 있습니다.

BrowseRawContentsResponse 클래스는 콘텐츠 ID, URL, 제목, 설명, 썸네일 등 필요한 모든 필드를 적절하게 포함하고 있습니다. 썸네일 이미지 URL을 nullable로 설정한 것은 좋은 접근 방식입니다.

날짜 형식 지정을 위한 @JsonFormat 어노테이션이 적절하게 사용되었습니다.


18-18: rawTexts 필드 타입 확인 필요

현재 rawTexts가 단일 String 타입으로 정의되어 있습니다. 이 필드가 여러 텍스트를 포함해야 한다면 List<String> 타입으로 변경하는 것이 더 적절할 수 있습니다.

이 필드가 실제로 단일 문자열로 사용되는지 확인해 주세요.


24-32: 프로비저닝 컨텐츠 응답 클래스 구조가 적절합니다.

BrowseProvisioningContentsResponse 클래스는 원시 컨텐츠 ID를 참조하고 완성 ID 목록, 본문 및 핵심 텍스트를 포함하여 계층적 관계를 잘 표현하고 있습니다.


34-44: 생성된 컨텐츠 응답 클래스 구조가 적절합니다.

BrowseGenResponse 클래스는 생성된 컨텐츠에 필요한 모든 필드를 포함하고 있으며, 프로비저닝 컨텐츠 ID를 참조하여 계층적 관계를 명확히 표현하고 있습니다.


20-21: 날짜 포맷 일관성이 잘 유지됨

createdAt 필드에 대한 동일한 @JsonFormat 패턴이 모든 응답 클래스에서 일관되게 사용되었습니다. 이는 응답 형식의 일관성을 유지하는 좋은 예입니다.

Also applies to: 30-31, 42-43

domain/generator/src/main/kotlin/com/few/generator/service/strategy/KoreanGenGenerationStrategy.kt (3)

7-7: 새로운 임포트 추가에 대한 긍정적인 변경

GEN_TYPE 및 Constant 클래스를 임포트하여 코드의 일관성과 중앙화된 상수 관리를 개선했습니다.

Also applies to: 9-9


12-12: Component 어노테이션 리팩토링

하드코딩된 문자열 대신 Constant.GEN 클래스의 상수를 사용하도록 변경하여 코드 유지보수성이 향상되었습니다.


42-42: Gen 엔티티에 타입 정보 추가

Gen 생성자에 typeCode 속성이 추가되어 컨텐츠 타입 식별이 가능해졌습니다. 이는 컨텐츠 ID 기반 조회 API 구현에 필요한 변경사항으로 보입니다.

domain/generator/src/main/kotlin/com/few/generator/service/strategy/BasicGenGenerationStrategy.kt (3)

7-7: 새로운 임포트 추가에 대한 긍정적인 변경

GEN_TYPE 및 Constant 클래스를 임포트하여 코드의 일관성과 중앙화된 상수 관리를 개선했습니다.

Also applies to: 9-9


12-12: Component 어노테이션 리팩토링

하드코딩된 문자열 대신 Constant.GEN 클래스의 상수를 사용하도록 변경하여 코드 유지보수성이 향상되었습니다.


29-29: Gen 엔티티에 타입 정보 추가

Gen 생성자에 typeCode 속성이 추가되어 컨텐츠 타입 식별이 가능해졌습니다. 이는 컨텐츠 ID 기반 조회 API 구현에 필요한 변경사항입니다.

domain/generator/src/main/kotlin/com/few/generator/service/strategy/KoreanQuestionGenGenerationStrategy.kt (3)

9-9: 새로운 임포트 추가에 대한 긍정적인 변경

GEN_TYPE 및 Constant 클래스를 임포트하여 코드의 일관성과 중앙화된 상수 관리를 개선했습니다.

Also applies to: 11-11


16-16: Component 어노테이션 리팩토링

하드코딩된 문자열 대신 Constant.GEN 클래스의 상수를 사용하도록 변경하여 코드 유지보수성이 향상되었습니다.


51-51: Gen 엔티티에 타입 정보 추가

Gen 생성자에 typeCode 속성이 추가되어 컨텐츠 타입 식별이 가능해졌습니다. 이는 컨텐츠 ID 기반 조회 API 구현에 필요한 변경사항으로, 모든 전략에 일관되게 적용되었습니다.

domain/generator/src/main/kotlin/com/few/generator/domain/Gen.kt (3)

7-10: 인덱스 추가로 성능 개선이 기대됩니다.

provisioning_contents_id 컬럼에 인덱스를 추가하는 것은 이 컬럼을 기반으로 한 쿼리 성능을 크게 향상시킬 것입니다. 특히 컨텐츠 조회 API가 이 필드를 자주 사용한다면 적절한 최적화입니다.


26-27: typeCode 필드 추가는 적절합니다.

타입 코드를 통해 다양한 생성 전략을 구분할 수 있어 확장성이 향상됩니다. 이는 PR 목표와 일치하는 변경사항입니다.


11-11: 기존 TODO 코멘트에 대한 계획이 있나요?

"DB컬럼 타입 변경 필요"라는 TODO 코멘트가 있습니다. 이 PR의 일부로 이 이슈도 해결할 계획이 있으신지요? 아니라면 별도의 이슈로 트래킹하는 것이 좋겠습니다.

domain/generator/src/main/kotlin/com/few/generator/service/strategy/KoreanLongQuestionGenGenerationStrategy.kt (3)

16-16: 컴포넌트 이름 상수화는 좋은 변경입니다.

전략 이름을 하드코딩하는 대신 Constant.GEN.STRATEGY_NAME_KOREAN_LONG_QUESTION와 같은 상수를 사용하는 것은 유지보수성과 일관성을 향상시킵니다. 이는 좋은 프랙티스입니다.


9-9: typeCode 사용은 적절하나 검증이 필요할 수 있습니다.

GEN_TYPE enum을 사용하여 typeCode를 설정하는 것은 타입 안전성을 보장하는 좋은 방법입니다. 그러나 이 값이 적절한지 검증하는 메커니즘이 시스템 어딘가에 있는지 확인하세요.

또한 기존 데이터나 마이그레이션 계획에 대한 고려가 필요합니다. 기존 데이터에 대해 이 typeCode 필드를 어떻게 처리할 계획인지요?

Also applies to: 52-52


24-54: 전반적인 생성 로직은 잘 구현되어 있습니다.

generate 메소드의 전체 로직은 단계별로 잘 구성되어 있습니다. 헤드라인, 요약, 하이라이트 텍스트를 순차적으로 생성하고 최종 Gen 객체를 반환하는 흐름이 명확합니다. typeCode 추가는 기존 로직을 방해하지 않으면서 필요한 정보를 추가하고 있습니다.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (4)
domain/generator/src/main/kotlin/com/few/generator/domain/GenType.kt (4)

16-20: from 메서드 이름을 더 명확하게 변경하는 것을 고려해보세요.

from 메서드는 일반적인 이름입니다. fromCode와 같이 더 구체적인 이름을 사용하면 메서드의 목적이 더 명확해질 것입니다.

- fun from(code: Int): GenType =
+ fun fromCode(code: Int): GenType =

21-24: from(title) 메서드 이름을 더 명확하게 변경하는 것을 고려해보세요.

마찬가지로 문자열 타이틀을 매개변수로 받는 from 메서드도 fromTitle과 같이 더 구체적인 이름을 사용하면 좋겠습니다.

- fun from(title: String): GenType =
+ fun fromTitle(title: String): GenType =

17-24: 예외 메시지 언어의 일관성을 확인하세요.

예외 메시지가 영어로 작성되어 있습니다. 애플리케이션의 다른 예외 메시지들이 한국어로 되어 있다면, 일관성을 위해 한국어로 메시지를 작성하는 것이 좋겠습니다.

- ?: throw IllegalArgumentException("Invalid GEN_TYPE code: $code")
+ ?: throw IllegalArgumentException("유효하지 않은 GEN_TYPE 코드: $code")

- ?: throw IllegalArgumentException("Invalid GEN_TYPE name: $title")
+ ?: throw IllegalArgumentException("유효하지 않은 GEN_TYPE 이름: $title")

5-25: 코드 값과 타이틀의 중복 검사가 필요할 수 있습니다.

현재 코드에서는 열거형 상수들 간에 코드 값이나 타이틀이 중복되지 않는지 검사하는 로직이 없습니다. 런타임에 중복된 값이 있을 경우 from 메서드가 첫 번째로 찾은 값을 반환하게 됩니다. 초기화 시 중복 검사를 수행하는 static 초기화 블록을 추가하는 것을 고려해보세요.

companion object {
    init {
        val codeSet = mutableSetOf<Int>()
        val titleSet = mutableSetOf<String>()
        
        for (type in values()) {
            if (!codeSet.add(type.code)) {
                throw IllegalStateException("중복된 GenType 코드 발견: ${type.code}")
            }
            if (!titleSet.add(type.title)) {
                throw IllegalStateException("중복된 GenType 타이틀 발견: ${type.title}")
            }
        }
    }
    
    // 기존 메서드들...
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9990c78 and 5092792.

📒 Files selected for processing (6)
  • domain/generator/src/main/kotlin/com/few/generator/domain/GenType.kt (1 hunks)
  • domain/generator/src/main/kotlin/com/few/generator/service/strategy/BasicGenGenerationStrategy.kt (2 hunks)
  • domain/generator/src/main/kotlin/com/few/generator/service/strategy/KoreanGenGenerationStrategy.kt (2 hunks)
  • domain/generator/src/main/kotlin/com/few/generator/service/strategy/KoreanLongQuestionGenGenerationStrategy.kt (2 hunks)
  • domain/generator/src/main/kotlin/com/few/generator/service/strategy/KoreanQuestionGenGenerationStrategy.kt (2 hunks)
  • domain/generator/src/main/kotlin/com/few/generator/usecase/RawContentsBrowseContentUseCase.kt (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • domain/generator/src/main/kotlin/com/few/generator/service/strategy/KoreanQuestionGenGenerationStrategy.kt
  • domain/generator/src/main/kotlin/com/few/generator/service/strategy/BasicGenGenerationStrategy.kt
  • domain/generator/src/main/kotlin/com/few/generator/service/strategy/KoreanGenGenerationStrategy.kt
  • domain/generator/src/main/kotlin/com/few/generator/service/strategy/KoreanLongQuestionGenGenerationStrategy.kt
  • domain/generator/src/main/kotlin/com/few/generator/usecase/RawContentsBrowseContentUseCase.kt
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: api-test
  • GitHub Check: docs
  • GitHub Check: lint
🔇 Additional comments (2)
domain/generator/src/main/kotlin/com/few/generator/domain/GenType.kt (2)

5-8: 열거형 클래스 설계가 잘 되었습니다.

GenType 열거형 클래스는 코드와 제목을 속성으로 가지는 좋은 설계입니다. 이를 통해 생성 전략들을 체계적으로 관리할 수 있습니다.


9-12:

❓ Verification inconclusive

코드 값이 2의 거듭제곱으로 설정된 이유가 있나요?

현재 코드 값이 2, 4, 8, 16으로 설정되어 있습니다. 이는 비트 연산을 위한 설계인지, 아니면 다른 이유가 있는지 명확하지 않습니다. 만약 비트 연산을 위한 것이라면 주석을 추가하는 것이 좋겠습니다.


🏁 Script executed:

#!/bin/bash
# 프로젝트에서 GenType의 코드 값을 비트 연산자로 사용하는 코드가 있는지 확인합니다
rg "GenType.*[&|]" --type kotlin

Length of output: 34


비트 연산 의도 명확화 필요 (파일: domain/generator/src/main/kotlin/com/few/generator/domain/GenType.kt, 9-12)

현재 STRATEGY_NAME_BASIC(2, …), STRATEGY_NAME_KOREAN(4, …), STRATEGY_NAME_KOREAN_QUESTION(8, …), STRATEGY_NAME_KOREAN_LONG_QUESTION(16, …)와 같이 2의 거듭제곱 값이 할당되어 있는데, 검색 결과 코드 내에서 이 값들이 비트 연산(예: & 또는 |)으로 활용되는 흔적은 확인되지 않았습니다.

  • 만약 향후 비트 연산 목적으로 사용될 의도가 있다면, 그 점을 명확히 드러내는 주석을 추가해주시기 바랍니다.
  • 그렇지 않고 단순히 일정 패턴(2의 거듭제곱)을 따르는 값으로 선택된 것이라면, 이러한 선택 이유를 코드에 명시함으로써 다른 개발자가 이해하기 쉽도록 해주시면 좋겠습니다.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
domain/generator/src/main/kotlin/com/few/generator/domain/ProvisioningContents.kt (1)

24-32: JPA 기본 생성자 추가에 대한 검토

TODO 주석에서 이 기본 생성자의 필요성에 의문을 제기하고 있습니다. JPA는 엔티티 클래스에 기본 생성자가 필요하지만, 이 코드가 임시 솔루션인지 확인이 필요합니다.

몇 가지 고려사항:

  1. rawContentsId의 기본값으로 0L을 사용하는 것이 semantically 올바른지 검토하세요.
  2. 프로덕션 코드에서는 TODO 주석을 남겨두지 않는 것이 좋습니다.

PR 목표에서 언급된 "JPA 엔티티를 위한 기본 생성자의 임시 추가"와 일치하는 변경입니다.

) : BaseEntity() {
-    protected constructor() : this( // TODO: 기본 생성자 필요?
+    protected constructor() : this(
        id = null,
        rawContentsId = 0L,
        bodyTextsJson = "[]",
        coreTextsJson = "[]",
        completionIds = mutableListOf(),
    )
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5092792 and 50f6e96.

📒 Files selected for processing (3)
  • domain/generator/src/main/kotlin/com/few/generator/domain/Gen.kt (2 hunks)
  • domain/generator/src/main/kotlin/com/few/generator/domain/ProvisioningContents.kt (2 hunks)
  • domain/generator/src/main/kotlin/com/few/generator/domain/RawContents.kt (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • domain/generator/src/main/kotlin/com/few/generator/domain/RawContents.kt
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: api-test
  • GitHub Check: docs
  • GitHub Check: lint
🔇 Additional comments (4)
domain/generator/src/main/kotlin/com/few/generator/domain/Gen.kt (3)

7-10: DB 최적화를 위한 인덱스 추가에 대해 긍정적으로 평가합니다.

provisioning_contents_id 컬럼에 대한 인덱스를 추가한 것은 조회 성능 향상에 도움이 될 것입니다. PR 목표에서 언급된 대로 컨텐츠 조회 API의 성능을 개선하기 위한 인덱스 추가가 적절하게 구현되었습니다.


26-27: typeCode 필드 추가가 적절하게 구현되었습니다.

typeCode 필드 추가는 GenType 열거형과 관련된 것으로 보이며, 다양한 생성 전략을 식별하기 위한 용도로 사용될 것으로 이해됩니다. 필수 필드로 설정되어 있어 데이터 무결성을 보장할 수 있습니다.


29-37: 기본 생성자 관련 TODO 주석을 검토해 주세요.

코드에 "TODO: 기본 생성자 필요?" 주석이 있습니다. JPA 엔티티에는 기본 생성자가 필요하지만, PR 설명에서 언급된 대로 이는 임시 추가로 보입니다. 프로젝트 완료 후 이 TODO를 처리할 계획이 있는지 확인하고, 필요하다면 주석을 제거하거나 영구적인 해결책으로 변경하는 것을 권장합니다.

또한, 모든 필드가 이미 기본값을 가지고 있다면 JPA가 일반적으로 기본 생성자 없이도 작동할 수 있습니다. 이 생성자가 정말 필요한지 검토해 보세요.

domain/generator/src/main/kotlin/com/few/generator/domain/ProvisioningContents.kt (1)

7-10: 데이터베이스 성능 향상을 위한 인덱스 추가

raw_contents_id 컬럼에 유니크 인덱스를 추가한 것은 데이터베이스 성능 향상에 기여할 것입니다. 이는 PR 목표에 명시된 "데이터베이스 성능 향상을 위한 인덱스 추가"와 일치합니다.

유니크 제약 조건은 동일한 raw_contents_id를 가진 중복 레코드가 생성되는 것을 방지하는데, 이는 데이터 무결성 측면에서도 좋은 변경사항입니다.

Copy link
Collaborator

@belljun3395 belljun3395 left a comment

Choose a reason for hiding this comment

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

저희 이야기하던 요청시 어떤 Id로 받을지는 PM과 이야기해보았나요???
궁금한 것은 코멘트 해두었고 어프루브 합니다!
수고하셨습니다~~!

Comment on lines +7 to +10
@Table(
name = "gen",
indexes = [Index(name = "idx_gen_1", columnList = "provisioning_contents_id", unique = false)],
)
Copy link
Collaborator

Choose a reason for hiding this comment

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

idx_gen_1 이라고 한 이유가 있나요?
idx_gen_1 만 보고는 어떤 인덱스인지 잘 모를 수도 있을 것 같아요

Copy link
Member Author

Choose a reason for hiding this comment

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

인덱스 네이밍 룰을 정해보면 좋을거 같네요. 인덱스 명은 변경 가능하니 나중에 정해보죠

Comment on lines +29 to +37
id = null,
provisioningContentsId = 0L,
completionIds = mutableListOf(),
headline = "",
summary = "",
highlightTexts = "[]",
typeCode = 0,
)
Copy link
Collaborator

Choose a reason for hiding this comment

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

보내 주신 링크의 것 적용이 안되는 것인가요?

Comment on lines +7 to +10
@Table(
name = "provisioning_contents",
indexes = [Index(name = "idx_provisioning_contents_1", columnList = "raw_contents_id", unique = true)],
)
Copy link
Collaborator

Choose a reason for hiding this comment

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

요 인덱스 네이밍도요!

Copy link
Collaborator

Choose a reason for hiding this comment

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

유니크로 한 이유는 따로 있나요?

Copy link
Member Author

Choose a reason for hiding this comment

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

raw content - prov content 는 1대1이니까 유니크 되어야하고

Comment on lines +26 to +27
@Qualifier(GSON_BEAN_NAME)
private val gson: Gson,
Copy link
Collaborator

Choose a reason for hiding this comment

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

@qualifier(GSON_BEAN_NAME)
gson 빈이 하나만 있을 것 같긴 한데 위에 처럼 지정해줘야하나요?

Copy link
Member Author

Choose a reason for hiding this comment

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

지정을 안하면 변수명인 gson 이라는 이름의 bean을 찾을텐데 빈명을 지금 GSON_BEAN_NAME로 정해둬서 저렇게 가져오고 있어요

@hun-ca
Copy link
Member Author

hun-ca commented Mar 18, 2025

저희 이야기하던 요청시 어떤 Id로 받을지는 PM과 이야기해보았나요??? 궁금한 것은 코멘트 해두었고 어프루브 합니다! 수고하셨습니다~~!

우선 raw content id 기반으로만 조회되도록 추가하는걸로 결정 됐습니다.
cc. @mooyoung2309

@hun-ca hun-ca merged commit 5b06681 into dev Mar 18, 2025
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

생성된 컨텐츠 조회 API 추가 JPA 에러 수정(엔티티 기본생성자)
2 participants