Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
104 changes: 68 additions & 36 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,15 @@ adapter/in → adapter/out (수평 의존)
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Challenger extends BaseEntity {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private Long userId; // ID 참조만

@Builder
private Challenger(...) { }
private Challenger(...) {
}

// 도메인 로직
public void graduate() {
Expand Down Expand Up @@ -102,9 +104,9 @@ public interface RegisterChallengerUseCase {
}

public record RegisterChallengerCommand(
Long userId,
Long gisuId,
ChallengerPart part
Long userId,
Long gisuId,
ChallengerPart part
) {
// Validation in constructor if needed
public RegisterChallengerCommand {
Expand All @@ -115,6 +117,7 @@ public record RegisterChallengerCommand(
// ❌ BAD
public interface ChallengerUseCase { // 너무 포괄적인 이름
void register(Long userId, Long gisuId, String part); // primitive 타입 나열

Challenger getById(Long id); // Entity 직접 반환
}
```
Expand All @@ -133,6 +136,7 @@ public interface ChallengerUseCase { // 너무 포괄적인 이름
// ✅ GOOD
public interface LoadChallengerPort {
Optional<Challenger> findById(Long id);

boolean existsByUserIdAndGisuId(Long userId, Long gisuId);
}

Expand All @@ -143,7 +147,9 @@ public interface SaveChallengerPort {
// ❌ BAD
public interface ChallengerPort { // Load/Save 분리 안됨
Challenger findById(Long id); // Optional 미사용

void save(Challenger challenger); // 반환값 없음

List<ChallengerResponse> findAllWithUserInfo(); // Response DTO 반환
}
```
Expand All @@ -169,7 +175,7 @@ public class ChallengerQueryService implements GetChallengerUseCase {
@Override
public ChallengerInfo getById(Long challengerId) {
Challenger challenger = loadChallengerPort.findById(challengerId)
.orElseThrow(() -> new BusinessException(ErrorCode.CHALLENGER_NOT_FOUND));
.orElseThrow(() -> new BusinessException(ErrorCode.CHALLENGER_NOT_FOUND));
return ChallengerInfo.from(challenger);
}
}
Expand Down Expand Up @@ -267,27 +273,27 @@ public class ChallengerController {
```java
// ✅ GOOD - Request
public record RegisterChallengerRequest(
@NotNull Long gisuId,
@NotNull ChallengerPart part
) {
@NotNull Long gisuId,
@NotNull ChallengerPart part
) {
public RegisterChallengerCommand toCommand(Long userId) {
return new RegisterChallengerCommand(userId, gisuId, part);
}
}

// ✅ GOOD - Response
public record ChallengerResponse(
Long id,
String userName,
String part,
String status
Long id,
String userName,
String part,
String status
) {
public static ChallengerResponse from(ChallengerInfo info) {
return new ChallengerResponse(
info.id(),
info.userName(),
info.part().name(),
info.status().name()
info.id(),
info.userName(),
info.part().name(),
info.status().name()
);
}
}
Expand Down Expand Up @@ -330,12 +336,18 @@ public class ChallengerRequest {

```java
// UseCase methods
register(), create(), update(), delete() // Command
getById(), getAll(), search(), find() // Query
register(),create(),

update(),delete() // Command

getById(),getAll(),

search(),find() // Query

// Port methods
save(), delete() // Save Port
findById(), findAll(), existsBy...() // Load Port
save(),delete() // Save Port

findById(),findAll(),existsBy...() // Load Port

// Controller endpoints
POST /api/v1/{domains} // 생성
Expand All @@ -355,12 +367,23 @@ DELETE /api/v1/{domains}/{id} // 삭제
// ❌ 하나의 서비스가 너무 많은 책임
@Service
public class ChallengerService {
public void register() { }
public void assignRole() { }
public void addRewardPenalty() { }
public void graduate() { }
public List<ChallengerResponse> search() { }
public void sendNotification() { } // 다른 도메인 책임
public void register() {
}

public void assignRole() {
}

public void addRewardPenalty() {
}

public void graduate() {
}

public List<ChallengerResponse> search() {
}

public void sendNotification() {
} // 다른 도메인 책임
}
```

Expand All @@ -377,7 +400,9 @@ public class Challenger {
}

// Service에서 직접 상태 변경
challenger.setStatus(ChallengerStatus.GRADUATED);
challenger.

setStatus(ChallengerStatus.GRADUATED);
```

**권장:** Entity에 도메인 로직 포함
Expand Down Expand Up @@ -453,7 +478,7 @@ public ApiResponse<Long> register(

// ❌ Request Body에서 userId 받지 않음
public record RegisterRequest(
Long userId, // 보안 취약점
Long userId, // 보안 취약점
...
)
```
Expand Down Expand Up @@ -481,8 +506,9 @@ public void updateNotice(Long noticeId, UpdateCommand command, Long requesterId)
```java
// ❌ N+1 발생 가능
List<Challenger> challengers = repository.findAll();
for (Challenger c : challengers) {
User member = userRepository.findById(c.getUserId()); // N번 쿼리
for(
Challenger c :challengers){
User member = userRepository.findById(c.getUserId()); // N번 쿼리
}

// ✅ Fetch Join 또는 별도 쿼리
Expand Down Expand Up @@ -513,25 +539,31 @@ List<Challenger> findByGisuId(Long gisuId);
```java
// ✅ 한글 메서드명으로 명확하게
@Test
void 챌린저_등록_성공() { }
void 챌린저_등록_성공() {
}

@Test
void 존재하지_않는_사용자면_USER_NOT_FOUND_예외() { }
void 존재하지_않는_사용자면_USER_NOT_FOUND_예외() {
}

@Test
void 이미_등록된_챌린저면_중복_예외() { }
void 이미_등록된_챌린저면_중복_예외() {
}

// ❌ 불명확한 테스트명
@Test
void test1() { }
void test1() {
}

@Test
void registerTest() { }
void registerTest() {
}
```

### Test Structure

```java

@Test
void 챌린저_등록_성공() {
// given - 테스트 데이터 준비
Expand Down
55 changes: 32 additions & 23 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,15 @@ form ◄─────────────── member (독립적)
| `Get` | 조회 | `GetChallengerUseCase` |
| `Search` | 검색 | `SearchPostUseCase` |

### Manage 통합 옵션

CUD(Create, Update, Delete)를 하나의 인터페이스로 통합하고 싶다면 `Manage` 접두사를 사용할 수 있습니다.

| 대상 | 개별형 | 통합형 |
|-------------|---------------------------------------------------------------------|-----------------------|
| **UseCase** | `CreateSchoolUseCase`, `UpdateSchoolUseCase`, `DeleteSchoolUseCase` | `ManageSchoolUseCase` |
| **Port** | `SaveSchoolPort` | `ManageSchoolPort` |

---

## Code Examples
Expand Down Expand Up @@ -511,43 +520,43 @@ public class AttendanceEventListener {

```json
{
"success": true,
"data": {
...
},
"error": null
"success": true,
"data": {
...
},
"error": null
}
```

### Error

```json
{
"success": false,
"data": null,
"error": {
"code": "CHALLENGER_NOT_FOUND",
"message": "챌린저를 찾을 수 없습니다."
}
"success": false,
"data": null,
"error": {
"code": "CHALLENGER_NOT_FOUND",
"message": "챌린저를 찾을 수 없습니다."
}
}
```

### Pagination

```json
{
"success": true,
"data": {
"content": [
...
],
"page": 0,
"size": 20,
"totalElements": 100,
"totalPages": 5,
"hasNext": true
},
"error": null
"success": true,
"data": {
"content": [
...
],
"page": 0,
"size": 20,
"totalElements": 100,
"totalPages": 5,
"hasNext": true
},
"error": null
}
```

Expand Down
10 changes: 10 additions & 0 deletions src/docs/asciidoc/api/chapter/chapter.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[[chapter-get-list]]
=== 지부 목록 조회

operation::chapter-query-controller-test/지부_목록을_조회합니다[snippets='http-request,http-response']

[[chapter-create]]
=== 신규 지부 생성

operation::chapter-controller-test/신규_지부를_생성한다[snippets='http-request,request-fields,http-response']

25 changes: 25 additions & 0 deletions src/docs/asciidoc/api/gisu/gisu.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[[gisu-list]]
=== 기수 목록 조회

operation::gisu-query-controller-test/기수_목록을_조회한다[snippets='http-request,http-response,response-fields']

[[gisu-create]]
=== 신규 기수 추가

operation::gisu-controller-test/신규_기수를_추가한다[snippets='http-request,request-fields,http-response']

[[gisu-update]]
=== 기수 정보 수정

operation::gisu-controller-test/기수_정보를_수정한다[snippets='http-request,path-parameters,request-fields,http-response']

[[gisu-delete]]
=== 기수 삭제

operation::gisu-controller-test/기수를_삭제한다[snippets='http-request,path-parameters,http-response']

[[gisu-set-current]]
=== 현재 기수 설정

operation::gisu-controller-test/현재_기수를_설정한다[snippets='http-request,path-parameters,http-response']

30 changes: 30 additions & 0 deletions src/docs/asciidoc/api/school/school.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[[school-list]]
=== 총괄 학교 목록 조회

operation::school-query-controller-test/학교_목록을_조회합니다[snippets='http-request,query-parameters,http-response']

[[school-detail]]
=== 총괄 학교 상세 조회

operation::school-query-controller-test/학교_상세정보를_조회합니다[snippets='http-request,path-parameters,http-response']

[[school-create]]
=== 총괄 학교 등록

operation::school-controller-test/총괄_신규학교를_추가한다[snippets='http-request,request-fields,http-response']

[[school-delete]]
=== 총괄 학교 삭제

operation::school-controller-test/총괄_학교를_제거한다[snippets='http-request,path-parameters,http-response']

[[school-delete-bulk]]
=== 총괄 학교 일괄 삭제

operation::school-controller-test/총괄_학교를_일괄_삭제한다[snippets='http-request,request-fields,http-response']

[[school-update]]
=== 총괄 학교정보 수정

operation::school-controller-test/총괄_학교정보를_수정한다[snippets='http-request,path-parameters,request-fields,http-response']

14 changes: 14 additions & 0 deletions src/docs/asciidoc/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,17 @@ endif::[]
:toclevels: 2
:sectlinks:

[[School-API]]
== 학교 API

include::api/school/school.adoc[]

[[Gisu-API]]
== 기수 API

include::api/gisu/gisu.adoc[]

[[Chapter-API]]
== 지부 API

include::api/chapter/chapter.adoc[]
Loading
Loading