Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
005ca0a
feat: organization 관련 도메인 개발
kanghana1 Jan 2, 2026
11e5f7a
feat: entity pk전략 sequence에서 identity로 변경
kanghana1 Jan 2, 2026
80a5aa2
feat: studyGroup과 studyGroupMember 양방향 매핑 추가
kanghana1 Jan 3, 2026
f7ac3f9
feat: organization 도메인 및 outbound interface 개발
kanghana1 Jan 4, 2026
31ab234
feat: web api부분 interface 구현
kanghana1 Jan 5, 2026
d6e4a41
rename: dto 네이밍 수정
kanghana1 Jan 5, 2026
c48dd16
Merge branch 'develop' into feature/#5
kanghana1 Jan 5, 2026
831a1a7
style: WootecoStyle 적용
kyeoungwoon Jan 5, 2026
1696b31
feat: StudyGroup과 StudyGroupMember aggregate
kyeoungwoon Jan 5, 2026
60bf9f7
chore: OrganizationErrorCode 코드명 컨벤션에 맞게 수정
kyeoungwoon Jan 5, 2026
4e836f1
feat: 구조개선
wlgusqkr Jan 5, 2026
668b8ca
feat: 함수명개선
wlgusqkr Jan 5, 2026
aa6c4f8
feat: 최종 구조
wlgusqkr Jan 6, 2026
c90b00d
feat: Manage 컨벤션 개선
wlgusqkr Jan 6, 2026
65d6fc1
feat: LoadCentralOrganizationPort 추가
wlgusqkr Jan 6, 2026
b4117d5
feat: Response객체 Page 인터페이스 추가
wlgusqkr Jan 7, 2026
ff477e7
feat: ApplicationTest 제거, JpaAuditing 설정 분리, 필요한 DocumentationTest에서 …
wlgusqkr Jan 7, 2026
7fb7ec2
feat: 총괄 학교 관리 Post API 추가
wlgusqkr Jan 7, 2026
2eb2474
feat: @Valid 어노테이션 추가, 출력코드 없애기
wlgusqkr Jan 7, 2026
fc01317
feat: 학교 정보수정, 학교 제거 API, Docs 추가
wlgusqkr Jan 7, 2026
55c0d50
remove: CursorPageable.java, OffsetPageable.java
wlgusqkr Jan 8, 2026
34bf48b
feat: 학교상세조회 API 추가
wlgusqkr Jan 8, 2026
5e09723
feat: 지부 목록 조회 API
wlgusqkr Jan 8, 2026
cf065e6
feat: 학교 목록조회 API
wlgusqkr Jan 8, 2026
a7c5aaf
docs: 학교 목록 조회 docs에서 query parameter도 나오게 수정
wlgusqkr Jan 8, 2026
4101481
feat: 총괄 일괄 학교 삭제 API추가
wlgusqkr Jan 8, 2026
f36b248
docs: docs에 optional 속성추가
wlgusqkr Jan 8, 2026
544e2c0
feat: 기수 CRUD API
wlgusqkr Jan 8, 2026
e1d4bd1
feat: Chapter 등록 API
wlgusqkr Jan 8, 2026
5176735
merge: update with develop
kyeoungwoon Jan 9, 2026
018e6ff
style: format project code
kyeoungwoon Jan 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -236,4 +236,4 @@ $RECYCLE.BIN/
# Windows shortcuts
*.lnk

# End of https://www.toptal.com/developers/gitignore/api/java,intellij+all,macos,windows,linux
# End of https://www.toptal.com/developers/gitignore/api/java,intellij+all,macos,windows,linux
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.umc.product.organization.application.port.in;

import java.util.List;

public interface DeleteSchoolUseCase {
void deleteById(Long schoolId);
void deleteAll(List<Long> schoolIds);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.umc.product.organization.application.port.in;
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

패키지 구조가 헥사고날 아키텍처 규칙을 위반합니다.

학습된 가이드라인에 따르면, query 유형의 UseCase(Get으로 시작)는 application/port/in/query/ 패키지에 위치해야 합니다.

Based on learnings, UseCase interfaces must be defined in application/port/in/{command|query}/ packages; query usecases use Get{Domain}UseCase pattern.

🔎 제안된 수정사항
-package com.umc.product.organization.application.port.in;
+package com.umc.product.organization.application.port.in.query;
📝 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
package com.umc.product.organization.application.port.in;
package com.umc.product.organization.application.port.in.query;
🤖 Prompt for AI Agents
In
@src/main/java/com/umc/product/organization/application/port/in/GetDeletableSchoolListUseCase.java
around line 1, The GetDeletableSchoolListUseCase interface is placed in the
wrong package; move it from package
com.umc.product.organization.application.port.in to the query subpackage to
follow hexagonal conventions. Update the package declaration to
com.umc.product.organization.application.port.in.query and relocate the file
into the corresponding directory, ensuring the interface name
GetDeletableSchoolListUseCase remains unchanged and any imports/usages elsewhere
are updated to the new package.


import com.umc.product.organization.application.port.in.dto.DeletableSchoolSummary;
import com.umc.product.organization.application.port.in.dto.SchoolDeleteSearchCondition;
import com.umc.product.organization.application.port.in.dto.paging.PageRequest;
import com.umc.product.organization.application.port.in.dto.paging.PageResult;
import java.util.List;

public interface GetDeletableSchoolListUseCase {
PageResult<DeletableSchoolSummary> getList(SchoolDeleteSearchCondition condition, PageRequest pageRequest);

Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

JavaDoc 문서화와 예외 처리 명세가 누락되었습니다.

코딩 가이드라인에 따르면, 예외 처리가 적절히 정의되어야 합니다. 다음 항목들을 추가하여 인터페이스의 계약을 명확히 해주세요:

  1. JavaDoc 문서: 메서드의 동작, 파라미터, 반환값, 예외 상황 설명
  2. 예외 처리 명세:
    • condition이 null인 경우
    • pageRequest가 null인 경우
    • 잘못된 페이징 파라미터인 경우 (음수, 0 등)
    • chapterId가 존재하지 않는 경우

As per coding guidelines, 예외가 적절히 처리되었는지 확인하고 의미 있는 커스텀 예외를 사용해야 합니다.

🔎 제안된 수정사항
+/**
+ * 삭제 가능한 학교 목록 조회 UseCase
+ * <p>
+ * 검색 조건과 페이징 정보에 따라 삭제 가능한 학교 목록을 조회하는 인바운드 포트입니다.
+ */
 public interface GetDeletableSchoolListUseCase {
+    /**
+     * 삭제 가능한 학교 목록을 페이징 조회합니다.
+     *
+     * @param condition 학교 검색 조건 (키워드, 지부 ID 등)
+     * @param pageRequest 페이징 요청 정보 (페이지 번호, 페이지 크기)
+     * @return 삭제 가능한 학교 요약 정보 목록과 페이징 메타데이터
+     * @throws IllegalArgumentException condition 또는 pageRequest가 null인 경우, 또는 잘못된 페이징 파라미터인 경우
+     * @throws ChapterNotFoundException chapterId가 존재하지 않는 경우
+     */
     PageResult<DeletableSchoolSummary> getList(SchoolDeleteSearchCondition condition, PageRequest pageRequest);
 
 }
📝 Committable suggestion

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

Suggested change
public interface GetDeletableSchoolListUseCase {
PageResult<DeletableSchoolSummary> getList(SchoolDeleteSearchCondition condition, PageRequest pageRequest);
/**
* 삭제 가능한 학교 목록 조회 UseCase
* <p>
* 검색 조건과 페이징 정보에 따라 삭제 가능한 학교 목록을 조회하는 인바운드 포트입니다.
*/
public interface GetDeletableSchoolListUseCase {
/**
* 삭제 가능한 학교 목록을 페이징 조회합니다.
*
* @param condition 학교 검색 조건 (키워드, 지부 ID )
* @param pageRequest 페이징 요청 정보 (페이지 번호, 페이지 크기)
* @return 삭제 가능한 학교 요약 정보 목록과 페이징 메타데이터
* @throws IllegalArgumentException condition 또는 pageRequest가 null인 경우, 또는 잘못된 페이징 파라미터인 경우
* @throws ChapterNotFoundException chapterId가 존재하지 않는 경우
*/
PageResult<DeletableSchoolSummary> getList(SchoolDeleteSearchCondition condition, PageRequest pageRequest);
}
🤖 Prompt for AI Agents
In
@src/main/java/com/umc/product/organization/application/port/in/GetDeletableSchoolListUseCase.java
around lines 8-10, Add JavaDoc to the GetDeletableSchoolListUseCase interface
and its getList(SchoolDeleteSearchCondition condition, PageRequest pageRequest)
method that documents behavior, parameters, return value, and failure modes;
explicitly declare the checked/unchecked exceptions the contract can throw
(e.g., IllegalArgumentException or a project-specific InvalidParameterException
when condition or pageRequest is null or when paging params are invalid
(negative/zero), and a ResourceNotFoundException or ChapterNotFoundException
when a referenced chapterId does not exist) so callers know expected error cases
and handling; ensure the JavaDoc lists each exceptional case and reference the
parameter types SchoolDeleteSearchCondition, PageRequest and the return type
PageResult<DeletableSchoolSummary> so implementors and callers can follow the
contract.

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.umc.product.organization.application.port.in;


import com.umc.product.organization.application.port.in.dto.SchoolInfo;
import com.umc.product.organization.application.port.in.dto.SchoolSummary;
import java.util.List;

public interface GetSchoolUserCase {
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

인터페이스명 오타 수정 필요

GetSchoolUserCase가 아니라 GetSchoolUseCase로 수정해야 합니다. "UserCase"는 오타입니다.

파일명도 함께 GetSchoolUseCase.java로 변경해야 합니다.

🔎 수정 방안

파일명과 인터페이스명 변경:

  • GetSchoolUserCase.javaGetSchoolUseCase.java
  • public interface GetSchoolUserCasepublic interface GetSchoolUseCase
🤖 Prompt for AI Agents
In
src/main/java/com/umc/product/organization/application/port/in/GetSchoolUserCase.java
around line 8, the interface name has a typo: change the interface declaration
from GetSchoolUserCase to GetSchoolUseCase and also rename the file from
GetSchoolUserCase.java to GetSchoolUseCase.java; update any references/imports
across the codebase to the new file and interface name to ensure compilation.

List<SchoolSummary> getAll(Long gisuId);
SchoolInfo getById(Long schoolId);

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

UseCase 인터페이스의 단일 책임 원칙 위반

하나의 UseCase 인터페이스에 getAllgetById 두 개의 메서드가 정의되어 있습니다.

헥사고날 아키텍처의 UseCase 패턴에서는 하나의 인터페이스가 하나의 유스케이스만 담당해야 합니다. 다음과 같이 분리를 권장합니다:

  • GetSchoolListUseCase (getAll 담당)
  • GetSchoolDetailUseCase (getById 담당)

이렇게 분리하면 각 유스케이스별로 독립적인 구현과 테스트가 가능하며, 인터페이스 변경의 영향 범위를 최소화할 수 있습니다.

🔎 제안하는 분리 방안

GetSchoolListUseCase.java:

package com.umc.product.organization.application.port.in;

import com.umc.product.organization.application.port.in.dto.SchoolSummary;
import java.util.List;

public interface GetSchoolListUseCase {
    List<SchoolSummary> getList(Long gisuId);
}

GetSchoolDetailUseCase.java:

package com.umc.product.organization.application.port.in;

import com.umc.product.organization.application.port.in.dto.SchoolInfo;

public interface GetSchoolDetailUseCase {
    SchoolInfo getDetail(Long schoolId);
}

Based on learnings, UseCase 인터페이스는 단일 책임을 가져야 하며, 하나의 인터페이스당 하나의 유스케이스를 정의해야 합니다.

🤖 Prompt for AI Agents
In
src/main/java/com/umc/product/organization/application/port/in/GetSchoolUserCase.java
around lines 8-11, this interface violates single-responsibility by exposing
both getAll and getById; split it into two interfaces: GetSchoolListUseCase
(with getList/getAll for gisuId) and GetSchoolDetailUseCase (with
getDetail/getById for schoolId); then update all implementations, dependency
injections, and tests to implement/use the appropriate new interface names and
method names, and remove or deprecate the original GetSchoolUserCase.

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.umc.product.organization.application.port.in;

import com.umc.product.organization.application.port.in.dto.RegisterSchoolCommand;

public interface RegisterSchoolUseCase {
Long register(RegisterSchoolCommand command);
}
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

UseCase 인터페이스의 패키지 위치를 command 하위로 이동해주세요.

코딩 가이드라인과 retrieved learnings에 따르면, UseCase 인터페이스는 application/port/in/{command|query}/ 패키지에 정의되어야 합니다. 현재 RegisterSchoolUseCase는 등록(명령) 작업이므로 application/port/in/command/ 패키지로 이동해야 합니다.

🔎 권장 패키지 구조

파일 위치를 다음과 같이 변경하세요:

src/main/java/com/umc/product/organization/application/port/in/command/RegisterSchoolUseCase.java

패키지 선언도 함께 수정:

-package com.umc.product.organization.application.port.in;
+package com.umc.product.organization.application.port.in.command;

Based on learnings, UseCase 인터페이스는 command 또는 query 하위 패키지에 위치해야 합니다.

🤖 Prompt for AI Agents
In
src/main/java/com/umc/product/organization/application/port/in/RegisterSchoolUseCase.java
lines 1-7, the UseCase interface belongs in the command subpackage; move the
file to
src/main/java/com/umc/product/organization/application/port/in/command/RegisterSchoolUseCase.java
and update its package declaration to
com.umc.product.organization.application.port.in.command; after moving, update
all imports/usages across the codebase to reference the new package (IDE
refactor or search-and-replace) so compilation and references remain correct.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.umc.product.organization.application.port.in;
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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# UseCase 파일들의 현재 패키지 구조 확인
fd -type f -name '*UseCase.java' | head -20

Repository: UMC-PRODUCT/umc-product-server

Length of output: 244


🏁 Script executed:

#!/bin/bash
# UpdateSchoolUseCase의 실제 위치 확인
find . -name 'UpdateSchoolUseCase.java' -type f

Repository: UMC-PRODUCT/umc-product-server

Length of output: 163


🏁 Script executed:

#!/bin/bash
# application/port/in 하위의 UseCase 파일 구조 분석
find . -path '*/application/port/in/*UseCase.java' | sort

Repository: UMC-PRODUCT/umc-product-server

Length of output: 445


🏁 Script executed:

#!/bin/bash
# 전체 저장소에서 모든 UseCase 파일 위치 확인
find . -name '*UseCase.java' -type f | sort

Repository: UMC-PRODUCT/umc-product-server

Length of output: 445


🏁 Script executed:

#!/bin/bash
# command/ 또는 query/ 하위에 UseCase가 있는지 확인
find . -path '*/application/port/in/command/*UseCase.java' -o -path '*/application/port/in/query/*UseCase.java' 2>/dev/null

Repository: UMC-PRODUCT/umc-product-server

Length of output: 56


UseCase 패키지 구조 재정렬 필요

코딩 가이드라인에 따르면 UseCase 인터페이스는 application/port/in/{command|query}/ 패키지에 정의되어야 합니다. UpdateSchoolUseCaseapplication/port/in/command/ 디렉토리로 이동해야 합니다. (다른 command 패턴의 usecases들도 동일하게 재정렬 필요)

🤖 Prompt for AI Agents
In
src/main/java/com/umc/product/organization/application/port/in/UpdateSchoolUseCase.java
around lines 1-1, the UseCase interface is in the wrong package; move this file
into application/port/in/command/, update its package declaration to package
com.umc.product.organization.application.port.in.command;, and adjust any
imports and references (including build configs and tests) to the new package;
apply the same relocation and package-declaration changes for other
command-pattern usecases so all command interfaces live under
application.port.in.command.


import com.umc.product.organization.application.port.in.dto.UpdateSchoolCommand;
import com.umc.product.organization.application.port.in.dto.UpdateSchoolInfo;

public interface UpdateSchoolUseCase {
UpdateSchoolInfo update(UpdateSchoolCommand command);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.umc.product.organization.application.port.in.dto;

import java.time.LocalDate;

public record DeletableSchoolSummary(
Long schoolId,
String schoolName,
Long chapterId,
String chapterName,
LocalDate createdAt,
boolean isActive
) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.umc.product.organization.application.port.in.dto;

import com.umc.product.organization.domain.Chapter;
import jakarta.validation.constraints.NotBlank;

public record RegisterSchoolCommand(
@NotBlank
String schoolName,
Long chapterId,
String remark
) {
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

필수 필드에 대한 validation 어노테이션이 누락되었습니다.

Command 레코드의 필드에 적절한 검증이 필요합니다:

  • chapterId: Long 타입이지만 @NotNull이 누락되어 null 값이 허용됩니다. Chapter는 School의 필수 연관 관계로 보이므로 null 검증이 필요합니다.
  • remark: 선택 필드인 경우 명시적으로 @Nullable 또는 주석으로 표시하거나, 필수 필드라면 @NotBlank 추가가 필요합니다.
🔎 제안하는 수정 (remark가 선택 필드인 경우)
 public record RegisterSchoolCommand(
         @NotBlank
         String schoolName,
+        @NotNull
         Long chapterId,
         String remark  // 선택 필드
 ) {

As per coding guidelines, 입력 검증이 적절히 되어 있는지 확인이 필요합니다.

🤖 Prompt for AI Agents
In
src/main/java/com/umc/product/organization/application/port/in/dto/RegisterSchoolCommand.java
around lines 6 to 11, validation annotations are missing: add @NotNull to the
chapterId field to prevent null chapter IDs, and annotate remark either with
@Nullable (if optional) or with @NotBlank (if required); also add the
appropriate import for the chosen Nullable annotation (e.g.
javax.annotation.Nullable or org.springframework.lang.Nullable) and ensure any
validation framework annotations used are on the record components.

}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Command 레코드에 도메인 엔티티로의 변환 메서드가 누락되었습니다.

Retrieved learnings와 코딩 가이드라인에 따르면, Command 레코드는 도메인 엔티티나 다른 레이어로 변환하기 위한 메서드(예: toEntity(), toDomain())를 포함해야 합니다. 이를 통해 DTO와 엔티티 간의 변환 로직이 명확해지고 중복이 방지됩니다.

🔎 제안하는 변환 메서드 추가
 public record RegisterSchoolCommand(
         @NotBlank
         String schoolName,
+        @NotNull
         Long chapterId,
         String remark
 ) {
+    public School toEntity(Chapter chapter) {
+        return School.builder()
+                .schoolName(schoolName)
+                .chapter(chapter)
+                .remark(remark)
+                .build();
+    }
 }

또는 서비스 레이어에서 변환하는 것이 더 적절하다고 판단되면, 최소한 변환 책임의 위치를 명확히 해주세요.

Based on learnings, Command 레코드는 변환 메서드를 포함해야 합니다.

📝 Committable suggestion

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

Suggested change
public record RegisterSchoolCommand(
@NotBlank
String schoolName,
Long chapterId,
String remark
) {
}
public record RegisterSchoolCommand(
@NotBlank
String schoolName,
@NotNull
Long chapterId,
String remark
) {
public School toEntity(Chapter chapter) {
return School.builder()
.schoolName(schoolName)
.chapter(chapter)
.remark(remark)
.build();
}
}
🤖 Prompt for AI Agents
In
src/main/java/com/umc/product/organization/application/port/in/dto/RegisterSchoolCommand.java
around lines 6-12, the record lacks a conversion method to transform the DTO
into the domain entity; add a toEntity() (or toDomain()) method that returns a
School domain object constructed from this.schoolName, this.remark and maps
chapterId to the appropriate Chapter reference (e.g., Chapter.ofId(chapterId) or
null if absent) so that DTO-to-entity conversion logic lives in the command
record and downstream services can use the resulting School instance.

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.umc.product.organization.application.port.in.dto;

public record SchoolDeleteSearchCondition(
String keyword,
Long chapterId
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.umc.product.organization.application.port.in.dto;

import java.time.LocalDate;

public record SchoolInfo(
Long chapterId,
String chapterName,
String schoolName,
Long schoolId,
String remark,
LocalDate createdAt,
LocalDate updatedAt
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.umc.product.organization.application.port.in.dto;

public record SchoolSummary(
Long schoolId,
String schoolName
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.umc.product.organization.application.port.in.dto;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import java.time.LocalDate;

public record UpdateSchoolCommand(
@NotNull
Long schoolId,
@NotBlank
String schoolName,
@NotNull
String chapterId,
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

chapterId 타입 불일치 확인 필요

chapterIdString 타입으로 선언되어 있으나, UpdateSchoolInfo에서는 Long 타입으로 정의되어 있습니다. 이는 런타임 시 타입 변환 오류나 데이터 불일치를 유발할 수 있습니다.

🔎 제안된 수정
        @NotNull
-       String chapterId,
+       Long chapterId,
📝 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
@NotNull
String chapterId,
@NotNull
Long chapterId,
🤖 Prompt for AI Agents
In
src/main/java/com/umc/product/organization/application/port/in/dto/UpdateSchoolCommand.java
around lines 12-13, the field chapterId is declared as String but
UpdateSchoolInfo expects a Long; change chapterId's type from String to Long
(keeping the @NotNull annotation) so DTO types match across layers, and update
any constructors/getters/setters and usages to accept/return Long to avoid
runtime conversion issues.

String remark

) {
}
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

toEntity() 또는 변환 메소드 추가 권장

코딩 가이드라인에 따르면, Command record는 toCommand() 또는 toEntity() 변환 메소드를 포함해야 합니다. 이를 통해 도메인 엔티티로의 변환 로직을 명확하게 캡슐화할 수 있습니다.

Based on learnings, Command records should include conversion method.

🤖 Prompt for AI Agents
In
src/main/java/com/umc/product/organization/application/port/in/dto/UpdateSchoolCommand.java
around lines 7 to 17, the Command record lacks a conversion method; add a
toEntity() (or toCommand()) instance method that converts this DTO into the
domain School entity by creating and returning a School using the record fields
(schoolId, schoolName, chapterId, remark), mapping types appropriately (e.g.,
converting chapterId to the domain identifier type if needed) and using the
domain constructor or builder; ensure imports are added and keep the conversion
logic simple and null-safe.

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.umc.product.organization.application.port.in.dto;

import java.time.LocalDate;

public record UpdateSchoolInfo(
String newSchoolName,
Long chapterId,
String chapterName,
String remark,
LocalDate createdAt,
LocalDate updatedAt
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.umc.product.organization.application.port.in.dto.paging;

import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;

public record PageRequest(
// common으로 빼도 괜찮을 거 같습니다
@Min(1) int page,
@Min(1) @Max(100) int limit
) {
public long offset() {
return (long) (page - 1) * limit;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.umc.product.organization.application.port.in.dto.paging;

import java.util.List;

public record PageResult<T>(
List<T> items,
long totalCount,
int page,
int limit
) {
public long totalPages() {
return (totalCount + limit - 1) / limit;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.umc.product.organization.application.port.out;

import com.umc.product.organization.domain.CentralOrganization;
import java.util.Optional;

public interface LoadCentralOrganizationPort {

Optional<CentralOrganization> findById(Long id);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.umc.product.organization.application.port.out;

import com.umc.product.organization.domain.Chapter;
import com.umc.product.organization.domain.Gisu;
import java.util.List;
import java.util.Optional;

public interface LoadChapterPort {

Optional<Chapter> findById(Long id);
List<Chapter> findAll();
List<Chapter> findAllByGisu(Gisu gisu);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.umc.product.organization.application.port.out;

import com.umc.product.organization.domain.Chapter;
import com.umc.product.organization.domain.ChapterSchool;
import com.umc.product.organization.domain.School;
import java.util.List;
import java.util.Optional;

public interface LoadChapterSchoolPort {

Optional<ChapterSchool> findById(Long id);
Optional<ChapterSchool> findByChapterAndSchool(Chapter chapter, School school);
List<ChapterSchool> findAllByChapter(Chapter chapter);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.umc.product.organization.application.port.out;

import com.umc.product.organization.domain.Gisu;
import java.util.List;
import java.util.Optional;

public interface LoadGisuPort {

Optional<Gisu> findById(Long id);
List<Gisu> findAll();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.umc.product.organization.application.port.out;

import com.umc.product.organization.domain.Chapter;
import com.umc.product.organization.domain.School;
import java.util.List;
import java.util.Optional;

public interface LoadSchoolPort {

Optional<School> findById(Long id);
List<School> findAll();
List<School> findByChapter(Chapter chapter);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.umc.product.organization.application.port.out;

import com.umc.product.organization.domain.StudyGroup;
import com.umc.product.organization.domain.StudyGroupMember;
import java.util.List;
import java.util.Optional;

public interface LoadStudyGroupMemberPort {

Optional<StudyGroupMember> findById(Long id);
List<StudyGroupMember> findByStudyGroup(StudyGroup studyGroup);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.umc.product.organization.application.port.out;

import com.umc.product.organization.domain.StudyGroup;
import java.util.Optional;

public interface LoadStudyGroupPort {

Optional<StudyGroup> findById(Long id);
Optional<StudyGroup> findByName(String name);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.umc.product.organization.application.port.out;

import com.umc.product.organization.domain.CentralOrganization;

public interface SaveCentralOrganizationPort {

CentralOrganization save(CentralOrganization organization);
void delete(CentralOrganization organization);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.umc.product.organization.application.port.out;

import com.umc.product.organization.domain.Chapter;

public interface SaveChapterPort {


Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

불필요한 공백 라인을 제거하는 것을 권장합니다.

다른 Save 포트 인터페이스들(SaveGisuPort, SaveChapterSchoolPort)과의 일관성을 위해 불필요한 빈 줄을 제거하는 것이 좋습니다.

🔎 제안하는 수정
 public interface SaveChapterPort {
-

     Chapter save(Chapter chapter);
📝 Committable suggestion

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

Suggested change
public interface SaveChapterPort {
Chapter save(Chapter chapter);
void delete(Chapter chapter);
}
🤖 Prompt for AI Agents
In
src/main/java/com/umc/product/organization/application/port/out/SaveChapterPort.java
around line 7, remove the unnecessary blank line to match the
formatting/consistency of other Save* port interfaces (e.g., SaveGisuPort,
SaveChapterSchoolPort); simply delete the empty line so the file has no
extraneous blank lines and adheres to the project's interface formatting
conventions.

Chapter save(Chapter chapter);
void delete(Chapter chapter);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.umc.product.organization.application.port.out;

import com.umc.product.organization.domain.ChapterSchool;

public interface SaveChapterSchoolPort {

ChapterSchool save(ChapterSchool chapterSchool);
void delete(ChapterSchool chapterSchool);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.umc.product.organization.application.port.out;

import com.umc.product.organization.domain.Gisu;

public interface SaveGisuPort {

Gisu save(Gisu gisu);
void delete(Gisu gisu);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.umc.product.organization.application.port.out;

import com.umc.product.organization.domain.School;

public interface SaveSchoolPort {

School save(School school);
void delete(School school);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.umc.product.organization.application.port.out;

import com.umc.product.organization.domain.StudyGroupMember;

public interface SaveStudyGroupMemberPort {

StudyGroupMember save(StudyGroupMember studyGroupMember);
void delete(StudyGroupMember studyGroupMember);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.umc.product.organization.application.port.out;

import com.umc.product.organization.domain.StudyGroup;

public interface SaveStudyGroupPort {

StudyGroup save(StudyGroup studyGroup);
void delete(StudyGroup studyGroup);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.umc.product.organization.domain;

import com.umc.product.global.exception.BusinessException;
import com.umc.product.global.exception.constant.Domain;
import com.umc.product.organization.exception.OrganizationErrorCode;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class CentralOrganization {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "gisu_id")
private Gisu gisu;

private String name;

@Builder
private CentralOrganization(Gisu gisu, String name) {
validate(gisu, name);
this.gisu = gisu;
this.name = name;
}

private static void validate(Gisu gisu, String name) {
if (gisu == null) throw new BusinessException(Domain.COMMON, OrganizationErrorCode.GISU_REQUIRED);
if (name == null || name.isBlank()) throw new BusinessException(Domain.COMMON, OrganizationErrorCode.ORGAN_NAME_REQUIRED);
}

}
Loading