Skip to content

[FEAT] 사장님 - 자주 쓰는 채팅 CRUD 기능 구현#10

Merged
ksg1227 merged 11 commits into
developfrom
feat/#7-chat-template-crud
Sep 15, 2025
Merged

[FEAT] 사장님 - 자주 쓰는 채팅 CRUD 기능 구현#10
ksg1227 merged 11 commits into
developfrom
feat/#7-chat-template-crud

Conversation

@ksg1227

@ksg1227 ksg1227 commented Sep 15, 2025

Copy link
Copy Markdown
Contributor

#️⃣연관된 이슈

closes #7

📝작업 내용

자주 쓰는 채팅 관련 CRUD 기능을 구현하였습니다.

이 자주 쓰는 채팅의 경우 사실상 비즈니스 로직도 존재하지 않는 CRUD 였습니다.
채팅 내역이 중복되는지를 검증할 필요도 없고, 그 외의 복잡한 검증이 필요하지 않았기에, 오직 API 접근자가 사장님인지만 검증해줄 수 있도록 하였고, 그 외의 케이스는 -> 수정 / 삭제 를 시도할 시 해당 자주 쓰는 채팅 내역이 존재하는지 여부만 검증해주었습니다.

스크린샷 (선택)

스크린샷 2025-09-15 오후 3 55 57

💬리뷰 요구사항(선택)

개발동안은 매번 토큰을 발급받아서 사용하기 번거로울 것 같아 SecurityConfig 에서 임시로 토큰 검증 로직을 모든 API 에 대해 해제해준 상태입니다.
따라서 UserId 도 일단은 개발이 어느정도 진행된 이후에 적용하는 것이 좋을 것 같습니다!

Summary by CodeRabbit

  • New Features
    • 소유자가 “자주 쓰는 채팅” 템플릿을 등록/조회/수정/삭제할 수 있는 기능 추가
  • Documentation
    • 템플릿/계좌 응답 및 요청에 예시·설명 추가로 API 문서 강화
    • 관련 오류 코드와 응답 스펙 보강(CHAT_TEMPLATE_NOT_FOUND 등)
  • Chores
    • 개발 편의를 위해 인증을 임시 완화(모든 경로 접근 허용)

@ksg1227 ksg1227 requested a review from buzz0331 September 15, 2025 07:00
@ksg1227 ksg1227 self-assigned this Sep 15, 2025
@ksg1227 ksg1227 linked an issue Sep 15, 2025 that may be closed by this pull request
4 tasks
@coderabbitai

coderabbitai Bot commented Sep 15, 2025

Copy link
Copy Markdown

Walkthrough

오너 도메인에 “자주 쓰는 채팅” CRUD 기능을 추가했다. 컨트롤러·서비스·리포지토리·DTO·도메인 모델을 신설/확장하고, 에러코드와 스웨거 응답 설명을 보완했다. 개발 편의를 위해 SecurityConfig를 전체 허용으로, UserIdArgumentResolver는 사용자 ID 미존재 시 1L 반환으로 임시 조정했다.

Changes

Cohort / File(s) Change Summary
Controller - ChatTemplate 엔드포인트 추가
src/main/java/konkuk/chacall/domain/owner/presentation/OwnerController.java
오너 자주 쓰는 채팅 CRUD 엔드포인트 4종 추가(POST/GET/PATCH/DELETE). @UserId로 동적 ownerId 사용.
Service - Owner/ChatTemplate 연동
src/main/java/konkuk/chacall/domain/owner/application/OwnerService.java
ChatTemplateService 의존성 주입 및 등록/조회/수정/삭제 메서드 추가. 요청 전 OwnerValidator로 오너 검증.
Service - ChatTemplate 도메인 서비스 신설
.../owner/application/chatTemplate/ChatTemplateService.java
등록/조회/수정/삭제 트랜잭션 로직 구현. 미존재 시 EntityNotFoundException(CHAT_TEMPLATE_NOT_FOUND) 처리.
Repository - ChatTemplate JPA
.../owner/domain/repository/ChatTemplateRepository.java
JpaRepository 추가, findAllByOwnerId(Long ownerId) JPQL 제공.
Domain Model - ChatTemplate 확장
.../owner/domain/model/ChatTemplate.java
Lombok @Getter @AllArgsConstructor @Builder 추가. 정적 팩토리 of, 변경 메서드 update 도입.
DTO - Request/Response 추가
.../presentation/dto/request/RegisterChatTemplateRequest.java, .../presentation/dto/request/UpdateChatTemplateRequest.java, .../presentation/dto/response/ChatTemplateResponse.java
등록/수정 요청 레코드 및 응답 레코드 추가. 유효성 검사(최대 500자, NotBlank)와 Swagger 스키마 메타데이터 포함.
Error/Swagger - 코드 및 응답 설명 업데이트
.../global/common/exception/code/ErrorCode.java, .../global/common/swagger/SwaggerResponseDescription.java
CHAT_TEMPLATE_NOT_FOUND 추가. Swagger 응답 설명에 오너-채팅 템플릿 CRUD 항목 및 에러코드 세트 반영.
Security - 개발용 완화
.../global/config/SecurityConfig.java, .../global/common/security/resolver/UserIdArgumentResolver.java
모든 경로 permitAll, 토큰 미존재 시 1L 반환(기존 예외처리 주석화). 주석으로 임시 설정 명시.
Swagger 주석 보강(기존 DTO)
.../owner/presentation/dto/response/BankAccountResponse.java
필드별 Swagger @Schema 추가(설명/예시). 기능 로직 변경 없음.

Sequence Diagram(s)

sequenceDiagram
  actor Owner as Owner(사용자)
  participant API as OwnerController
  participant SVC as OwnerService
  participant CTS as ChatTemplateService
  participant REP as ChatTemplateRepository

  rect rgba(230,245,255,0.5)
    note over Owner,API: 등록 (POST /owners/me/chat-templates)
    Owner->>API: RegisterChatTemplateRequest
    API->>SVC: registerChatTemplate(request, ownerId)
    SVC->>CTS: registerChatTemplate(request, owner)
    CTS->>REP: save(ChatTemplate.of(...))
    REP-->>CTS: saved
    CTS-->>SVC: void
    SVC-->>API: BaseResponse<Void>
    API-->>Owner: 200 OK
  end

  rect rgba(240,255,240,0.5)
    note over Owner,API: 조회 (GET /owners/me/chat-templates)
    Owner->>API: 요청
    API->>SVC: getChatTemplates(ownerId)
    SVC->>CTS: getChatTemplates(ownerId)
    CTS->>REP: findAllByOwnerId(ownerId)
    REP-->>CTS: List<ChatTemplate>
    CTS-->>SVC: List<ChatTemplateResponse>
    SVC-->>API: BaseResponse<List<...>>
    API-->>Owner: 200 OK
  end

  rect rgba(255,250,230,0.6)
    note over Owner,API: 수정 (PATCH /owners/me/chat-templates/{id})
    Owner->>API: UpdateChatTemplateRequest
    API->>SVC: updateChatTemplate(request, ownerId, id)
    SVC->>CTS: updateChatTemplate(request, id)
    CTS->>REP: findById(id)
    alt 존재하지 않음
      CTS-->>SVC: throw EntityNotFound(CHAT_TEMPLATE_NOT_FOUND)
      SVC-->>API: 에러 응답
      API-->>Owner: 404
    else 존재함
      REP-->>CTS: ChatTemplate
      CTS->>CTS: entity.update(content)
      CTS-->>SVC: void
      SVC-->>API: BaseResponse<Void>
      API-->>Owner: 200 OK
    end
  end

  rect rgba(255,235,238,0.6)
    note over Owner,API: 삭제 (DELETE /owners/me/chat-templates/{id})
    Owner->>API: 요청
    API->>SVC: deleteChatTemplate(ownerId, id)
    SVC->>CTS: deleteChatTemplate(id)
    CTS->>REP: exists/findById or deleteById
    alt 미존재
      CTS-->>SVC: throw EntityNotFound(CHAT_TEMPLATE_NOT_FOUND)
      SVC-->>API: 에러 응답
      API-->>Owner: 404
    else 삭제
      REP-->>CTS: ok
      CTS-->>SVC: void
      SVC-->>API: BaseResponse<Void>
      API-->>Owner: 200 OK
    end
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • buzz0331

Poem

새 템플릿 콩콩, 토끼 발자국 두드려요 🐇
등록·조회·수정·삭제, 네 박자 딱딱 맞춰요.
깡충 뛰어 레포로, 살짝 돌아 서비스로—
없으면 404, 있으면 200 OK!
오늘도 채팅 한 줄, 부드럽게 완성해요.

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Out of Scope Changes Check ⚠️ Warning PR에 포함된 SecurityConfig의 전체 경로 permit-all 변경과 UserIdArgumentResolver의 예외 대신 1L 반환은 CRUD 기능 구현 목적과 무관하고 운영상 위험을 초래할 수 있는 범위를 벗어난 변경입니다. 또한 BankAccountResponse의 Swagger 주석 추가 및 SwaggerResponseDescription의 항목 변경 등 일부 문서화 관련 변경은 본 이슈의 최소 요구사항과 직접 관련이 적어 별도 PR로 분리하는 것이 바람직합니다. 이러한 비관련 변경들은 머지 전 분리 또는 되돌림이 필요합니다. 해결 방안: SecurityConfig의 인증 완화(permit-all) 변경을 원래 인증 흐름으로 복원하고 UserIdArgumentResolver는 토큰 누락 시 예외를 던지도록 되돌리세요. Swagger/BankAccount 관련 문서 주석 변경은 별도 PR로 이동하거나 변경 사유를 PR 설명에 명확히 적어 주세요. 또한 update/delete에 대한 소유자 검증을 추가하거나 해당 설계를 문서화한 후 머지하세요.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed 제목은 PR의 핵심 변경인 "사장님 자주 쓰는 채팅(채팅 템플릿) CRUD 기능 구현"을 명확히 요약하고 있으며 간결하고 팀 히스토리에서 빠르게 파악하기 좋습니다. '[FEAT]' 접두사는 일반적인 컨벤션으로 허용될 수 있고 불필요한 파일 목록이나 이모지가 포함되어 있지 않습니다.
Linked Issues Check ✅ Passed PR은 ChatTemplate 도메인(엔티티·리포지토리), 서비스, 컨트롤러, DTO 및 관련 에러코드·Swagger 정의를 추가하여 조회·추가·수정·삭제 기능을 구현했고 이는 링크된 이슈 [#7]의 CRUD 요구사항을 충족합니다. 다만 수정·삭제 동작은 템플릿의 소유자 검증을 수행하지 않고 존재 여부만 확인하며 개발 편의를 위해 SecurityConfig의 인증 완화와 UserIdArgumentResolver의 1L 반환 변경이 포함되어 실제 접근 제어가 약화되어 있습니다. 기능적 요구사항 측면에서는 충족하지만 접근 제어 관련 변경은 별도 검토가 필요합니다.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/#7-chat-template-crud

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (8)
src/main/java/konkuk/chacall/global/common/exception/code/ErrorCode.java (1)

43-49: ChatTemplate 권한 오류 코드 보강 및 상태 코드 정합성

  • CHAT_TEMPLATE_NOT_FOUND 추가는 적절합니다. 다만 권한 미스매치 상황을 구분할 전용 FORBIDDEN 코드(CHAT_TEMPLATE_FORBIDDEN)를 함께 두는 것을 권장합니다(업데이트/삭제 시 소유자 검증 실패용).
  • 참고로 BANK_ACCOUNT_FORBIDDEN이 CONFLICT(409)인데, 의미상 FORBIDDEN(403)이 더 적합합니다. 범위가 넓어 영향이 크니 별 PR에서 검토 권장.

권장 추가(diff):

     /**
      * ChatTemplate
      */
-    CHAT_TEMPLATE_NOT_FOUND(HttpStatus.NOT_FOUND, 80001, "자주 쓰는 채팅을 찾을 수 없습니다.");
+    CHAT_TEMPLATE_NOT_FOUND(HttpStatus.NOT_FOUND, 80001, "자주 쓰는 채팅을 찾을 수 없습니다."),
+    CHAT_TEMPLATE_FORBIDDEN(HttpStatus.FORBIDDEN, 80002, "자주 쓰는 채팅에 대한 권한이 없습니다.");
src/main/java/konkuk/chacall/global/common/security/resolver/UserIdArgumentResolver.java (1)

22-26: 원시 long 지원 및 타입 안전 캐스팅

  • supportsParameter가 Long만 허용합니다. 원시 long도 허용하세요.
  • Request attribute 타입이 Number/String일 수 있어 안전 캐스팅이 필요합니다.
     public boolean supportsParameter(MethodParameter parameter) {
-        return parameter.hasParameterAnnotation(UserId.class)
-                && parameter.getParameterType().equals(Long.class);
+        return parameter.hasParameterAnnotation(UserId.class)
+                && (parameter.getParameterType().equals(Long.class)
+                    || parameter.getParameterType().equals(long.class));
     }
@@
-        return (Long) userId;
+        if (userId instanceof Number n) {
+            return n.longValue();
+        }
+        if (userId instanceof String s) {
+            try {
+                return Long.parseLong(s);
+            } catch (NumberFormatException e) {
+                throw new AuthException(AUTH_TOKEN_NOT_FOUND);
+            }
+        }
+        throw new AuthException(AUTH_TOKEN_NOT_FOUND);

Also applies to: 34-39

src/main/java/konkuk/chacall/global/common/annotation/UserId.java (1)

1-11: 애너테이션 메타정보 보강(@documented)

API 문서/IDE 힌트를 위해 @documented 추가를 권장합니다.

 package konkuk.chacall.global.common.annotation;
 
+import java.lang.annotation.Documented;
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
 @Target(ElementType.PARAMETER)
 @Retention(RetentionPolicy.RUNTIME)
+@Documented
 public @interface UserId {
 }
src/main/java/konkuk/chacall/domain/owner/presentation/dto/request/RegisterChatTemplateRequest.java (1)

5-9: 검증 메시지 일관화 및 길이 상한 검토

Update DTO와 동일한 문구로 통일 권장. 또한 엔티티 칼럼 길이에 맞춘 @SiZe 상한을 고려하세요.

예시(diff – 메시지 통일만 반영):

 public record RegisterChatTemplateRequest(
-        @NotBlank(message = "자주 쓰는 채팅을 입력해야합니다.")
+        @NotBlank(message = "자주 쓰는 채팅은 비어 있을 수 없습니다.")
         String content
 ) {
 }
src/main/java/konkuk/chacall/domain/owner/domain/repository/ChatTemplateRepository.java (1)

12-13: 파생 쿼리 사용 및 레포지토리 레벨 소유자 검증 메서드 추가 권장

  • 목록 조회: 현재 @query를 사용 중이므로 파생 메서드로 교체해 유지보수 비용을 줄이세요 (예: findAllByOwnerUserId).
  • 업데이트/삭제 검증: ChatTemplateService가 chatTemplateRepository.findById(chatTemplateId) (src/main/java/konkuk/chacall/domain/owner/application/chatTemplate/ChatTemplateService.java:42) 및 deleteById(chatTemplateId) (same file: ~56) 를 직접 호출합니다. OwnerService가 호출 전에 ownerValidator.validateAndGetOwner(ownerId)로 검증하긴 하나 (src/main/java/konkuk/chacall/domain/owner/application/OwnerService.java:77-90), 레포지토리 레벨에서 소유자 조건을 강제하는 파생 메서드(예: Optional findByIdAndOwnerUserId(Long id, Long ownerId); long deleteByIdAndOwnerUserId(Long id, Long ownerId))를 추가하면 서비스 호출 실수(소유자 미검증)를 예방할 수 있습니다.
  • 운영 권장: owner_user_id 컬럼에 인덱스 추가하여 목록 조회 성능 확보.
src/main/java/konkuk/chacall/domain/owner/application/chatTemplate/ChatTemplateService.java (1)

25-30: 등록 시 생성된 ID 반환하면 클라이언트 UX가 좋아집니다

생성 후 식별자를 응답에 바로 실어 줄 수 있게 서비스에서 반환하도록 제안합니다. (컨트롤러/파사드 변경은 별도 코멘트 참조)

-    @Transactional
-    public void registerChatTemplate(RegisterChatTemplateRequest request, User owner) {
-        ChatTemplate chatTemplate = ChatTemplate.of(request.content(), owner);
-
-        chatTemplateRepository.save(chatTemplate);
-    }
+    @Transactional
+    public Long registerChatTemplate(RegisterChatTemplateRequest request, User owner) {
+        ChatTemplate chatTemplate = ChatTemplate.of(request.content(), owner);
+        ChatTemplate saved = chatTemplateRepository.save(chatTemplate);
+        return saved.getChatTemplateId();
+    }
src/main/java/konkuk/chacall/domain/owner/application/OwnerService.java (1)

61-67: 선택: 등록 결과로 생성 ID를 돌려주기

컨트롤러가 바로 ID를 응답하도록 파사드도 Long을 반환하게 바꿀 수 있습니다. 비즈니스 연쇄 호출에 유용합니다.

-    public void registerChatTemplate(RegisterChatTemplateRequest request, Long ownerId) {
+    public Long registerChatTemplate(RegisterChatTemplateRequest request, Long ownerId) {
         // 사장님인지 먼저 검증
         User owner = ownerValidator.validateAndGetOwner(ownerId);
 
         // 자주 쓰는 채팅 등록 로직 호출
-        chatTemplateService.registerChatTemplate(request, owner);
+        return chatTemplateService.registerChatTemplate(request, owner);
     }
src/main/java/konkuk/chacall/domain/owner/presentation/OwnerController.java (1)

61-69: 선택: 등록 API에서 생성된 템플릿 ID를 반환

클라이언트가 즉시 식별자를 사용할 수 있도록 응답을 ID로 변경하는 것을 제안합니다. (Service/Facade 변경안과 연동)

-    @PostMapping("/me/chat-templates")
-    public BaseResponse<Void> registerChatTemplate(
+    @PostMapping("/me/chat-templates")
+    public BaseResponse<Long> registerChatTemplate(
             @RequestBody @Valid RegisterChatTemplateRequest request
     ) {
         // todo 추후에 토큰 추가될 시 id 값은 토큰에서 추출하여 전달
-        ownerService.registerChatTemplate(request, 1L);
-
-        return BaseResponse.ok(null);
+        Long id = ownerService.registerChatTemplate(request, 1L);
+        return BaseResponse.ok(id);
     }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bce2c98 and e9f28ed.

📒 Files selected for processing (12)
  • src/main/java/konkuk/chacall/domain/owner/application/OwnerService.java (2 hunks)
  • src/main/java/konkuk/chacall/domain/owner/application/chatTemplate/ChatTemplateService.java (1 hunks)
  • src/main/java/konkuk/chacall/domain/owner/domain/model/ChatTemplate.java (2 hunks)
  • src/main/java/konkuk/chacall/domain/owner/domain/repository/ChatTemplateRepository.java (1 hunks)
  • src/main/java/konkuk/chacall/domain/owner/presentation/OwnerController.java (3 hunks)
  • src/main/java/konkuk/chacall/domain/owner/presentation/dto/request/RegisterChatTemplateRequest.java (1 hunks)
  • src/main/java/konkuk/chacall/domain/owner/presentation/dto/request/UpdateChatTemplateRequest.java (1 hunks)
  • src/main/java/konkuk/chacall/domain/owner/presentation/dto/response/ChatTemplateResponse.java (1 hunks)
  • src/main/java/konkuk/chacall/global/common/annotation/UserId.java (1 hunks)
  • src/main/java/konkuk/chacall/global/common/exception/code/ErrorCode.java (1 hunks)
  • src/main/java/konkuk/chacall/global/common/security/resolver/UserIdArgumentResolver.java (1 hunks)
  • src/main/java/konkuk/chacall/global/config/SecurityConfig.java (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
src/main/java/konkuk/chacall/domain/owner/application/chatTemplate/ChatTemplateService.java (1)
src/main/java/konkuk/chacall/global/common/exception/EntityNotFoundException.java (1)
  • EntityNotFoundException (6-11)
src/main/java/konkuk/chacall/domain/owner/presentation/OwnerController.java (1)
src/main/java/konkuk/chacall/domain/owner/application/chatTemplate/ChatTemplateService.java (1)
  • RequiredArgsConstructor (18-59)
src/main/java/konkuk/chacall/domain/owner/domain/model/ChatTemplate.java (2)
src/main/java/konkuk/chacall/domain/user/domain/model/User.java (1)
  • Getter (7-49)
src/main/java/konkuk/chacall/domain/owner/domain/model/BankAccount.java (1)
  • Entity (10-56)
🔇 Additional comments (6)
src/main/java/konkuk/chacall/global/common/security/resolver/UserIdArgumentResolver.java (1)

5-5: 패키지 이동 반영 OK

UserId 애너테이션 경로 변경이 정상 반영되었습니다.

src/main/java/konkuk/chacall/domain/owner/presentation/dto/response/ChatTemplateResponse.java (1)

5-15: DTO 매핑 단순·명확, LGTM

레코드 + 정적 팩토리 from 구성 적절합니다.

src/main/java/konkuk/chacall/domain/owner/domain/model/ChatTemplate.java (3)

27-36: content 정규화(트림)로 불필요한 공백 저장 방지

DTO에서 @notblank는 통과하더라도 앞뒤 공백이 그대로 저장됩니다. 일관성 유지를 위해 도메인에서 trim을 적용해 주세요. DB 컬럼 길이(500)와도 맞추면 좋습니다.

[ suggest_optional_refactor ]

-    public static ChatTemplate of(String content, User owner) {
+    public static ChatTemplate of(String content, User owner) {
         return ChatTemplate.builder()
-                .content(content)
+                .content(content == null ? null : content.trim())
                 .owner(owner)
                 .build();
     }
@@
-    public void update(String content) {
-        this.content = content;
+    public void update(String content) {
+        this.content = content == null ? null : content.trim();
     }

요청 DTO(Register/UpdateChatTemplateRequest)에도 @Size(max = 500) 추가를 권장합니다.


10-11: 조회 성능을 위한 인덱스 추가 제안

오너별 목록 조회가 빈번하므로 user_id 인덱스를 부여해 주세요.

[ suggest_optional_refactor ]

-@Table(name = "chat_templates")
+@Table(
+    name = "chat_templates",
+    indexes = {
+        @Index(name = "idx_chat_templates_user_id", columnList = "user_id")
+    }
+)

6-6: lombok. 와일드카드 import 지양*

팀 컨벤션에 맞춰 필요한 애너테이션만 명시적으로 import하면 가독성이 좋습니다.

[ suggest_nitpick_refactor ]

src/main/java/konkuk/chacall/domain/owner/presentation/OwnerController.java (1)

31-31: 임시 하드코딩된 ownerId(1L) 제거 및 SecurityConfig의 permitAll 제한 필요

  • 문제: ownerId가 1L로 하드코딩되어 있음 (src/main/java/konkuk/chacall/domain/owner/presentation/OwnerController.java — lines 31,39,47,56,66,74,82,90). SecurityConfig가 permitAll로 열려 있으면 전체 공개 및 타 계정 리소스 접근 위험 발생.
  • 조치: develop 병합 전 토큰 기반 인증(JWT 등)으로 owner 식별하도록 변경하거나 해당 엔드포인트를 오직 dev 프로파일에서만 노출; SecurityConfig의 permitAll 제거/제한.
  • 검증: 샌드박스에서 리포지토리 검색이 실패해 파일·Security 설정을 직접 확인하지 못함 — 로컬/CI에서 위 위치와 SecurityConfig를 확인해 변경 적용 여부를 검증할 것.

Comment thread src/main/java/konkuk/chacall/global/config/SecurityConfig.java
buzz0331
buzz0331 previously approved these changes Sep 15, 2025

@buzz0331 buzz0331 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

굿굿 흠 잡을데 없는 완벽한 코드 같습니다~

@ksg1227 ksg1227 merged commit 028e6b5 into develop Sep 15, 2025
1 of 2 checks passed
@ksg1227 ksg1227 deleted the feat/#7-chat-template-crud branch September 15, 2025 07:38

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (4)
src/main/java/konkuk/chacall/domain/owner/presentation/OwnerController.java (2)

116-129: 업데이트 엔드포인트는 호출 체인에서 소유자 검증이 실제 반영되는지 확인 필요

Controller→OwnerService 단계까지는 ownerId를 전달하지만, 현재 OwnerService가 chatTemplateService.updateChatTemplate(request, chatTemplateId)로 위임하고 있어 서비스 레이어에서 소유자 검증이 누락됩니다.

OwnerService 수정 예시(파일 외 참고):

-    chatTemplateService.updateChatTemplate(request, chatTemplateId);
+    chatTemplateService.updateChatTemplate(request, ownerId, chatTemplateId);

131-142: 삭제도 동일한 이슈

OwnerService가 deleteChatTemplate(chatTemplateId)로 위임하면 소유자 검증이 빠집니다. ownerId를 전달하도록 교정해 주세요.

-    chatTemplateService.deleteChatTemplate(chatTemplateId);
+    chatTemplateService.deleteChatTemplate(ownerId, chatTemplateId);

운영 메모: 현재 PR 설명상 SecurityConfig 토큰 검증이 임시 비활성화되어 있습니다. 병합 전 재활성/권한 테스트를 잊지 마세요.

src/main/java/konkuk/chacall/domain/owner/application/chatTemplate/ChatTemplateService.java (2)

40-48: 업데이트에 소유자 검증이 없습니다 → 임의 수정 가능(보안/권한 이슈)

ownerId를 받아 엔티티 로드 후 verifyOwner(ownerId) 또는 findByIdAndOwnerId로 검증해야 합니다. 현재는 다른 사용자의 템플릿을 수정할 수 있습니다.

-    @Transactional
-    public void updateChatTemplate(UpdateChatTemplateRequest request, Long chatTemplateId) {
-        ChatTemplate chatTemplate = chatTemplateRepository.findById(chatTemplateId)
-                .orElseThrow(() -> new EntityNotFoundException(ErrorCode.CHAT_TEMPLATE_NOT_FOUND));
-
-        chatTemplate.update(
-                request.content()
-        );
-    }
+    @Transactional
+    public void updateChatTemplate(UpdateChatTemplateRequest request, Long ownerId, Long chatTemplateId) {
+        ChatTemplate chatTemplate = chatTemplateRepository.findById(chatTemplateId)
+                .orElseThrow(() -> new EntityNotFoundException(ErrorCode.CHAT_TEMPLATE_NOT_FOUND));
+        chatTemplate.verifyOwner(ownerId);
+        chatTemplate.update(request.content());
+    }
  • 호춤부(OwnerService)도 chatTemplateService.updateChatTemplate(request, ownerId, chatTemplateId)로 변경 필요.

다음 스크립트로 호출부 체인을 확인해 주세요:

#!/bin/bash
rg -nP -C3 '\bupdateChatTemplate\s*\('

50-57: 삭제 로직에 TOCTOU 및 소유자 검증 누락

existsByIddeleteById는 사이에 상태가 바뀔 수 있고, 소유자 검증도 없습니다. 엔티티를 로드해 소유자 확인 후 삭제하세요.

-    @Transactional
-    public void deleteChatTemplate(Long chatTemplateId) {
-        if(!chatTemplateRepository.existsById(chatTemplateId)) {
-            throw new EntityNotFoundException(ErrorCode.CHAT_TEMPLATE_NOT_FOUND);
-        }
-
-        chatTemplateRepository.deleteById(chatTemplateId);
-    }
+    @Transactional
+    public void deleteChatTemplate(Long ownerId, Long chatTemplateId) {
+        ChatTemplate chatTemplate = chatTemplateRepository.findById(chatTemplateId)
+                .orElseThrow(() -> new EntityNotFoundException(ErrorCode.CHAT_TEMPLATE_NOT_FOUND));
+        chatTemplate.verifyOwner(ownerId);
+        chatTemplateRepository.delete(chatTemplate);
+    }

옵션: DB 단에서 findByIdAndOwnerId를 사용하면 한 번의 질의로 검증+조회가 가능해집니다.

🧹 Nitpick comments (3)
src/main/java/konkuk/chacall/domain/owner/presentation/dto/response/BankAccountResponse.java (1)

3-14: Swagger 스키마 주석 추가 좋습니다 — 예시/패턴만 살짝 다듬으면 더 명확해요

  • 계좌번호는 민감도가 있으니 예시값을 마스킹(예: 110-****-*****)하거나 pattern을 지정하면 API 문서 신뢰도가 올라갑니다.
  • record 자체에도 @Schema(name="BankAccountResponse")를 부여하면 스키마 식별이 쉬워집니다.

가능한 수정 예시:

-        @Schema(description = "계좌번호", example = "110-1123-123124")
+        @Schema(description = "계좌번호", example = "110-****-*****", pattern = "^[0-9\\-]{10,20}$")
         String accountNumber
src/main/java/konkuk/chacall/global/common/swagger/SwaggerResponseDescription.java (1)

61-76: 가변 Set이 그대로 외부로 노출됩니다 → 불변화로 방어하세요

getErrorCodeList()가 내부 LinkedHashSet을 그대로 반환해 외부에서 수정 가능합니다. 문서 스펙이 런타임에 변조될 수 있으니 불변 래핑이 필요합니다.

@@
-    private final Set<ErrorCode> errorCodeList;
+    private final Set<ErrorCode> errorCodeList;
@@
-    SwaggerResponseDescription(Set<ErrorCode> errorCodeList) {
-        // 공통 에러
-        errorCodeList.addAll(new LinkedHashSet<>(Set.of(
+    SwaggerResponseDescription(Set<ErrorCode> errorCodes) {
+        // 공통 에러 병합
+        Set<ErrorCode> merged = new LinkedHashSet<>(errorCodes);
+        merged.addAll(new LinkedHashSet<>(Set.of(
                 API_NOT_FOUND,
                 API_METHOD_NOT_ALLOWED,
                 API_SERVER_ERROR,
 
                 API_MISSING_PARAM,
                 API_INVALID_PARAM,
                 API_INVALID_TYPE
         )));
-
-        this.errorCodeList = errorCodeList;
+        this.errorCodeList = java.util.Collections.unmodifiableSet(merged);
     }
src/main/java/konkuk/chacall/domain/owner/presentation/OwnerController.java (1)

89-102: 등록 엔드포인트 구성 좋습니다

검증(@Valid), @userid 주입, 스웨거 설명 모두 적절합니다.

POST는 201 Created + Location 또는 생성 ID 반환을 고려해도 좋습니다.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e9f28ed and c213ef1.

📒 Files selected for processing (13)
  • src/main/java/konkuk/chacall/domain/owner/application/OwnerService.java (2 hunks)
  • src/main/java/konkuk/chacall/domain/owner/application/chatTemplate/ChatTemplateService.java (1 hunks)
  • src/main/java/konkuk/chacall/domain/owner/domain/model/ChatTemplate.java (2 hunks)
  • src/main/java/konkuk/chacall/domain/owner/domain/repository/ChatTemplateRepository.java (1 hunks)
  • src/main/java/konkuk/chacall/domain/owner/presentation/OwnerController.java (2 hunks)
  • src/main/java/konkuk/chacall/domain/owner/presentation/dto/request/RegisterChatTemplateRequest.java (1 hunks)
  • src/main/java/konkuk/chacall/domain/owner/presentation/dto/request/UpdateChatTemplateRequest.java (1 hunks)
  • src/main/java/konkuk/chacall/domain/owner/presentation/dto/response/BankAccountResponse.java (1 hunks)
  • src/main/java/konkuk/chacall/domain/owner/presentation/dto/response/ChatTemplateResponse.java (1 hunks)
  • src/main/java/konkuk/chacall/global/common/exception/code/ErrorCode.java (1 hunks)
  • src/main/java/konkuk/chacall/global/common/security/resolver/UserIdArgumentResolver.java (1 hunks)
  • src/main/java/konkuk/chacall/global/common/swagger/SwaggerResponseDescription.java (2 hunks)
  • src/main/java/konkuk/chacall/global/config/SecurityConfig.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (9)
  • src/main/java/konkuk/chacall/domain/owner/presentation/dto/request/UpdateChatTemplateRequest.java
  • src/main/java/konkuk/chacall/domain/owner/domain/repository/ChatTemplateRepository.java
  • src/main/java/konkuk/chacall/domain/owner/application/OwnerService.java
  • src/main/java/konkuk/chacall/domain/owner/presentation/dto/response/ChatTemplateResponse.java
  • src/main/java/konkuk/chacall/domain/owner/presentation/dto/request/RegisterChatTemplateRequest.java
  • src/main/java/konkuk/chacall/global/config/SecurityConfig.java
  • src/main/java/konkuk/chacall/global/common/security/resolver/UserIdArgumentResolver.java
  • src/main/java/konkuk/chacall/domain/owner/domain/model/ChatTemplate.java
  • src/main/java/konkuk/chacall/global/common/exception/code/ErrorCode.java
🧰 Additional context used
🧬 Code graph analysis (1)
src/main/java/konkuk/chacall/domain/owner/presentation/OwnerController.java (1)
src/main/java/konkuk/chacall/domain/owner/application/OwnerService.java (1)
  • RequiredArgsConstructor (18-92)
🔇 Additional comments (5)
src/main/java/konkuk/chacall/global/common/swagger/SwaggerResponseDescription.java (2)

32-35: OWNER_GET_BANK_ACCOUNT에 USER_NOT_FOUND 추가 적절합니다

은행 계좌 조회 시 사용자 미존재 케이스가 문서에 반영되었습니다. 👍


46-59: 채팅 템플릿 응답 스펙 추가 LGTM — 소유자 불일치(403) 코드 포함 여부 확인 부탁

현재 서비스 레이어에서 소유자 검증이 빠져 있어(아래 서비스 파일 코멘트 참조) 실제로 403 시나리오가 생길 예정입니다. 문서에도 추후 403(예: CHAT_TEMPLATE_FORBIDDEN 등)을 포함할지 검토해 주세요.

src/main/java/konkuk/chacall/domain/owner/application/chatTemplate/ChatTemplateService.java (2)

25-30: 등록 로직 깔끔합니다

도메인 팩토리 ChatTemplate.of(...) 사용과 영속화 흐름이 명확합니다.


32-38: 목록 조회 적절합니다

오너 기준 조회 후 DTO 매핑 스트림 처리도 간결합니다.

src/main/java/konkuk/chacall/domain/owner/presentation/OwnerController.java (1)

104-114: 조회 엔드포인트 OK

응답 랩핑과 DTO 사용 일관성 좋습니다.

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.

[FEAT] 사장님 - 자주 쓰는 채팅 CRUD 기능 구현

2 participants