Skip to content

Feat/#26#28

Merged
ojy0903 merged 8 commits intodevelopfrom
feat/#26
Feb 5, 2026
Merged

Feat/#26#28
ojy0903 merged 8 commits intodevelopfrom
feat/#26

Conversation

@ojy0903
Copy link
Collaborator

@ojy0903 ojy0903 commented Feb 4, 2026

📌 관련 이슈

🚀 개요

이번 PR에서 변경된 핵심 내용을 요약해주세요.

조직 정보 수정 API 추가

📄 작업 내용

구체적인 작업 내용을 설명해주세요.

  • 조직 정보 수정 API 추가
  • 조직 정보 수정 관련 오류 코드 추가
  • 조직 정보 수정 관련 DTO 추가

📸 스크린샷 / 테스트 결과 (선택)

결과물 확인을 위한 사진이나 테스트 로그를 첨부해주세요.

===이름 test 인 유저(id = 1) 가 생성한 org1 조직의 이름, 설명, 로고 이미지 URL 변경하기===

  1. 변경 전 users 테이블 & organization 테이블
image image
  1. 조직 생성자만 정보 수정 가능하므로, id = 1 인 test 유저로 로그인 하여 토큰 획득
image
  1. 조직 정보 새롭게 변경
image

DB organization 테이블 변경 내역 확인 가능
image

===예외 처리===

  1. 조직 생성자(ADMIN) 가 아닌 회원으로 조직 정보 변경 요청 시

1-1. id = 2 인 test2 사용자로 로그인, 토큰 획득
image

1-2. test2 사용자의 AccessToken 으로 org1 조직 정보 변경 요청 시 예외처리 (403 Forbidden)
image

  1. 잘못된 조직 id 로 접근한 경우 -> DB 내 존재하지 않는 orgId = 6 에 대해 정보 수정 요청시 예외 (404 Not Found)
image
  1. 정보 수정 요청 시 필수 값인 조직 이름이 공백으로 넘어오는 경우 -> @Valid 검사 예외 처리 (400 Bad Request)
image

✅ 체크리스트

  • [✅] 브랜치 전략(GitHub Flow)을 준수했나요?
  • [✅] 메서드 단위로 코드가 잘 쪼개져 있나요?
  • [✅] 테스트 통과 확인
  • [✅] 서버 실행 확인
  • [✅] API 동작 확인

🔍 리뷰 포인트 (Review Points)

리뷰어가 중점적으로 확인했으면 하는 부분을 적어주세요. (P1~P4 적용 가이드)

  • 조직 조회 API 의 경우 한 회원의 모든 조직 리스트 / 각 조직의 세부 내용 조회 / 조직에 속한 회원들 조회 등 여러가지 관점이 있을 것 같아 비교적 작업이 빠르게 끝날 것 같은 수정, 삭제 API 부터 진행하려 합니다.
  • 제가 기존에 알기로는 CRUD 에서 Update 와 Delete 는 요청이 성공적으로 처리되었을 때 204 noContent() 로 응답값을 따로 반환하지 않는 걸로 알고 있었는데 조사를 해보니 최근에는 Update 의 경우 200 OK 로 처리해서 Body 에 변경된 내용과 해당 조직 id, updatedAt 를 함께 반환하는 것도 권장된다고 하더라구요. 어떤 방법이 나을까요?
  • 정보 수정 Request DTO 에서 조직 이름에만 @notblank 를 적용하고 나머지 필드에는 적용하지 않았는데, 나머지 필드에도 적용하는게 좋을까요?

💬 리뷰어 가이드 (P-Rules)
P1: 필수 반영 (Critical) - 버그 가능성, 컨벤션 위반. 해결 전 머지 불가.
P2: 적극 권장 (Recommended) - 더 나은 대안 제시. 가급적 반영 권장.
P3: 제안 (Suggestion) - 아이디어 공유. 반영 여부는 드라이버 자율.
P4: 단순 확인/칭찬 (Nit) - 사소한 오타, 칭찬 등 피드백.

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능

    • 조직 정보 수정 기능 추가 — 이름, 설명, 로고 URL을 업데이트할 수 있습니다.
    • 수정 결과를 반환하도록 변경되어 업데이트된 정보와 수정 시각을 확인할 수 있습니다.
    • 조직 소유자만 수정 가능하도록 권한 검증을 추가했습니다.
  • 문서

    • 조직 수정 API 문서화 및 요청 유효성 검사(이름 필수) 명세가 추가되었습니다.

@ojy0903 ojy0903 self-assigned this Feb 4, 2026
@ojy0903 ojy0903 added the ✨ Feature 새로운 기능 추가 label Feb 4, 2026
@coderabbitai
Copy link

coderabbitai bot commented Feb 4, 2026

Walkthrough

조직 수정(Update) 기능이 구현되었습니다. 요청 DTO에 필드와 검증을 추가하고, 서비스에서 존재 및 소유권을 확인한 뒤 엔티티의 modifyInfo를 호출해 변경사항을 저장하고 업데이트 응답을 반환합니다.

Changes

Cohort / File(s) Summary
DTOs
src/main/java/.../dto/request/OrgRequest.java
Update 레코드에 name, description, logoUrl 필드 추가; name@NotBlank 적용.
응답 DTO
src/main/java/.../application/dto/response/OrgResponse.java
새로운 nested record Update(Long orgId, String name, String description, String logoUrl, LocalDateTime updatedAt) 추가.
엔티티
src/main/java/.../persistence/entity/Organization.java
modifyInfo(OrgRequest.Update request) 메서드 추가: name, description, logoUrl 갱신 로직.
서비스 인터페이스 & 구현
src/main/java/.../domain/service/OrgService.java, src/main/java/.../domain/service/OrgServiceImpl.java
modifyOrganization 반환타입을 OrgResponse.Update로 변경하고, 조직 조회·존재 확인, 소유자 검증(권한), modifyInfo 호출 및 업데이트 응답 반환 로직 구현.
컨트롤러 & 문서
src/main/java/.../presentation/OrgController.java, src/main/java/.../presentation/docs/OrgControllerDocs.java
@Hidden 제거로 API 노출, @Valid 추가로 요청 검증 활성화, 반환형을 ResponseEntity<DataResponse<OrgResponse.Update>>로 변경 및 문서화 추가.
컨버터
src/main/java/.../application/mapper/OrgConverter.java
toUpdatedResponse(Organization) 추가: Organization → OrgResponse.Update 매핑.
에러 코드
src/main/java/.../exception/code/OrgErrorCode.java
ORG_NOT_FOUND(404) 및 ORG_UPDATE_FORBIDDEN(403) 에러 코드 추가.

Sequence Diagram

sequenceDiagram
    participant Client
    participant OrgController
    participant OrgServiceImpl
    participant OrgRepository
    participant Organization
    participant OrgErrorCode

    Client->>OrgController: PATCH /organizations/{orgId}\n(userId, OrgRequest.Update)
    OrgController->>OrgController: 요청 바인딩 및 `@Valid` 검증
    OrgController->>OrgServiceImpl: modifyOrganization(userId, orgId, request)
    OrgServiceImpl->>OrgRepository: findById(orgId)
    OrgRepository-->>OrgServiceImpl: Organization or empty
    alt 조직 없음
        OrgServiceImpl->>OrgErrorCode: ORG_NOT_FOUND
        OrgServiceImpl-->>Client: 404 응답
    else 조직 존재
        OrgServiceImpl->>OrgServiceImpl: ownerUserId == userId 검증
        alt 소유자 불일치
            OrgServiceImpl->>OrgErrorCode: ORG_UPDATE_FORBIDDEN
            OrgServiceImpl-->>Client: 403 응답
        else 소유자 일치
            OrgServiceImpl->>Organization: modifyInfo(request)
            Organization->>Organization: name, description, logoUrl 갱신
            OrgServiceImpl->>OrgRepository: save(organization)
            OrgRepository-->>OrgServiceImpl: 저장 완료
            OrgServiceImpl-->>OrgController: OrgResponse.Update
            OrgController-->>Client: 200 응답 (DataResponse<OrgResponse.Update>)
        end
    end
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly Related PRs

  • Feat/#19 #20 — Organization 엔티티 최초 도입 관련 PR; 동일 엔티티 변경점(메서드 추가)과 코드 레벨 연관성 있음.
  • Feat/#23 #24 — 조직 수정 흐름의 초기 스케치/부분 구현 PR; 이번 PR이 해당 기능을 완성함으로써 직접적인 연속성 있음.

Suggested Reviewers

  • kingmingyu
  • jinnieusLab

🚥 Pre-merge checks | ✅ 3 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 26.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive 제목이 너무 일반적이어서 변경 내용을 명확히 파악하기 어렵습니다. 예를 들어 'Feat: 조직 정보 수정 API 추가' 처럼 더 구체적인 제목을 사용해주세요.
✅ Passed checks (3 passed)
Check name Status Explanation
Description check ✅ Passed PR 설명이 템플릿을 잘 따르며 개요, 작업 내용, 테스트 결과, 체크리스트를 모두 포함하고 있습니다.
Linked Issues check ✅ Passed PR의 모든 코드 변경이 이슈 #26의 '조직 정보 수정 API 추가' 요구사항을 만족하고 있습니다.
Out of Scope Changes check ✅ Passed 모든 변경사항이 조직 수정 API 구현과 직접 관련되어 있으며 범위를 벗어난 변경이 없습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/#26

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

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

🤖 Fix all issues with AI agents
In
`@src/main/java/com/whereyouad/WhereYouAd/domains/organization/persistence/entity/Organization.java`:
- Around line 40-43: modifyInfo currently overwrites existing fields with null
when description or logoUrl are omitted; change
Organization.modifyInfo(OrgRequest.Update) to only assign
name/description/logoUrl if the incoming value is non-null (e.g., if
(request.description() != null) this.description = request.description(); and
similarly for logoUrl) or alternatively use a distinct partial-update DTO,
ensuring OrgRequest.Update is not blindly applied and existing values are
preserved when nulls are passed.

In
`@src/main/java/com/whereyouad/WhereYouAd/domains/organization/presentation/docs/OrgControllerDocs.java`:
- Around line 27-40: The API documentation in OrgControllerDocs.java for
modifyOrganization uses incorrect responseCode strings ("403_1", "404_1");
update the `@ApiResponse` entries to match the actual OrgErrorCode constants (use
"ORG_403_1" and "ORG_404_1") so the documented response codes align with
OrgErrorCode; search for and fix any other `@ApiResponse` entries in
OrgControllerDocs that reference the shorthand codes to use the full constant
names.
🧹 Nitpick comments (1)
src/main/java/com/whereyouad/WhereYouAd/domains/organization/persistence/entity/Organization.java (1)

3-41: 엔티티가 요청 DTO에 직접 의존

Organization이 OrgRequest.Update에 직접 의존하면 계층 방향이 뒤집혀 유지보수성이 떨어집니다. 도메인 메서드는 primitive 인자(또는 도메인 커맨드)로 받고, 매핑은 서비스/컨버터로 이동하는 편이 좋습니다.

♻️ 리팩터링 예시
- public void modifyInfo(OrgRequest.Update request) {
-     this.name = request.name();
-     this.description = request.description();
-     this.logoUrl = request.logoUrl();
- }
+ public void modifyInfo(String name, String description, String logoUrl) {
+     this.name = name;
+     this.description = description;
+     this.logoUrl = logoUrl;
+ }

Comment on lines +40 to +43
public void modifyInfo(OrgRequest.Update request) {
this.name = request.name();
this.description = request.description();
this.logoUrl = request.logoUrl();
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

PATCH에서 null 덮어쓰기로 데이터 유실 가능

description/logoUrl을 생략하면 null이 저장되어 기존 값이 사라질 수 있어요. 부분 업데이트 의도라면 null은 유지하도록 가드하거나 별도 DTO로 분리하는 게 안전합니다.

🛠️ 수정 예시 (null 유지)
 public void modifyInfo(OrgRequest.Update request) {
-    this.name = request.name();
-    this.description = request.description();
-    this.logoUrl = request.logoUrl();
+    if (request.name() != null) {
+        this.name = request.name();
+    }
+    if (request.description() != null) {
+        this.description = request.description();
+    }
+    if (request.logoUrl() != null) {
+        this.logoUrl = request.logoUrl();
+    }
 }
🤖 Prompt for AI Agents
In
`@src/main/java/com/whereyouad/WhereYouAd/domains/organization/persistence/entity/Organization.java`
around lines 40 - 43, modifyInfo currently overwrites existing fields with null
when description or logoUrl are omitted; change
Organization.modifyInfo(OrgRequest.Update) to only assign
name/description/logoUrl if the incoming value is non-null (e.g., if
(request.description() != null) this.description = request.description(); and
similarly for logoUrl) or alternatively use a distinct partial-update DTO,
ensuring OrgRequest.Update is not blindly applied and existing values are
preserved when nulls are passed.

Comment on lines 27 to 40
@Operation(
summary = "조직 정보 수정 API",
description = "새로운 조직 이름, 설명, 로고 이미지 URL 을 받아 저장(해당 조직을 생성한 회원만 정보 변경 가능)"
)
@ApiResponses({
@ApiResponse(responseCode = "204", description = "성공(응답X)"),
@ApiResponse(responseCode = "403_1", description = "허가되지 않은 회원의 요청(조직 생성 회원 X)"),
@ApiResponse(responseCode = "404_1", description = "해당 id 조직 존재 X")
})
public ResponseEntity<Void> modifyOrganization(
@AuthenticationPrincipal(expression = "userId") Long userId,
@PathVariable Long orgId,
@RequestBody @Valid OrgRequest.Update request
);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

문서의 에러 코드 값 일치 여부 확인

OrgErrorCode는 ORG_403_1, ORG_404_1인데 문서에는 403_1, 404_1로 표기되어 있습니다. 실제 응답 코드와 동일하게 맞추는 게 좋아요.

📝 문서 수정 예시
- `@ApiResponse`(responseCode = "403_1", description = "허가되지 않은 회원의 요청(조직 생성 회원 X)"),
- `@ApiResponse`(responseCode = "404_1", description = "해당 id 조직 존재 X")
+ `@ApiResponse`(responseCode = "ORG_403_1", description = "허가되지 않은 회원의 요청(조직 생성 회원 X)"),
+ `@ApiResponse`(responseCode = "ORG_404_1", description = "해당 id 조직 존재 X")
📝 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
@Operation(
summary = "조직 정보 수정 API",
description = "새로운 조직 이름, 설명, 로고 이미지 URL 을 받아 저장(해당 조직을 생성한 회원만 정보 변경 가능)"
)
@ApiResponses({
@ApiResponse(responseCode = "204", description = "성공(응답X)"),
@ApiResponse(responseCode = "403_1", description = "허가되지 않은 회원의 요청(조직 생성 회원 X)"),
@ApiResponse(responseCode = "404_1", description = "해당 id 조직 존재 X")
})
public ResponseEntity<Void> modifyOrganization(
@AuthenticationPrincipal(expression = "userId") Long userId,
@PathVariable Long orgId,
@RequestBody @Valid OrgRequest.Update request
);
`@Operation`(
summary = "조직 정보 수정 API",
description = "새로운 조직 이름, 설명, 로고 이미지 URL 을 받아 저장(해당 조직을 생성한 회원만 정보 변경 가능)"
)
`@ApiResponses`({
`@ApiResponse`(responseCode = "ORG_403_1", description = "허가되지 않은 회원의 요청(조직 생성 회원 X)"),
`@ApiResponse`(responseCode = "ORG_404_1", description = "해당 id 조직 존재 X")
})
public ResponseEntity<Void> modifyOrganization(
`@AuthenticationPrincipal`(expression = "userId") Long userId,
`@PathVariable` Long orgId,
`@RequestBody` `@Valid` OrgRequest.Update request
);
🤖 Prompt for AI Agents
In
`@src/main/java/com/whereyouad/WhereYouAd/domains/organization/presentation/docs/OrgControllerDocs.java`
around lines 27 - 40, The API documentation in OrgControllerDocs.java for
modifyOrganization uses incorrect responseCode strings ("403_1", "404_1");
update the `@ApiResponse` entries to match the actual OrgErrorCode constants (use
"ORG_403_1" and "ORG_404_1") so the documented response codes align with
OrgErrorCode; search for and fix any other `@ApiResponse` entries in
OrgControllerDocs that reference the shorthand codes to use the full constant
names.

Copy link
Collaborator

@jinnieusLab jinnieusLab left a comment

Choose a reason for hiding this comment

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

P4: 고생하셨습니다! 제 생각에는 수정 요청 이후 프론트가 별도 GET api 요청을 하는 불편함을 줄이기 위해서, 수정 응답을 그대로 쓸 수 있게 변경 내용을 함께 포함하는 것도 괜찮을 것 같습니다! 그리고 @notblank 제약도 지금처럼 두어도 될 듯 합니다!

@ojy0903
Copy link
Collaborator Author

ojy0903 commented Feb 5, 2026

P4: 고생하셨습니다! 제 생각에는 수정 요청 이후 프론트가 별도 GET api 요청을 하는 불편함을 줄이기 위해서, 수정 응답을 그대로 쓸 수 있게 변경 내용을 함께 포함하는 것도 괜찮을 것 같습니다! 그리고 @notblank 제약도 지금처럼 두어도 될 듯 합니다!

넵 그러면 응답값만 200 OK 로 해서 Body 에 DTO 반환하는 방식으로 해볼게요!

Copy link
Collaborator

@kingmingyu kingmingyu left a comment

Choose a reason for hiding this comment

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

고생하셨습니다! 수정할 때 변한 값도 응답하는 거 참고하겠습니다!

@ojy0903 ojy0903 merged commit 9550273 into develop Feb 5, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ Feature 새로운 기능 추가

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: 조직 수정 API - Organization CRUD 중 수정(Update API) 추가

3 participants