Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
16 changes: 8 additions & 8 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public class Challenger extends BaseEntity {
@NoArgsConstructor // access level 누락
public class Challenger {
@ManyToOne
private User user; // 다른 도메인 직접 참조 금지
private Member member; // 다른 도메인 직접 참조 금지

// 도메인 로직 없이 getter/setter만
}
Expand Down Expand Up @@ -230,10 +230,10 @@ public class ChallengerController {

@PostMapping
public ApiResponse<Long> register(
@AuthenticationPrincipal SecurityUser user,
@AuthenticationPrincipal SecurityUser member,
@Valid @RequestBody RegisterChallengerRequest request) {

Long id = registerUseCase.register(request.toCommand(user.getUserId()));
Long id = registerUseCase.register(request.toCommand(member.getUserId()));
return ApiResponse.success(id);
}
}
Expand Down Expand Up @@ -407,7 +407,7 @@ public class ChallengerCommandService {
private final UserRepository userRepository; // 다른 도메인

public void register(...) {
User user = userRepository.findById(userId); // 직접 접근
User member = userRepository.findById(userId); // 직접 접근
}
}
```
Expand All @@ -418,7 +418,7 @@ public class ChallengerCommandService {
private final GetUserInfoUseCase getUserInfoUseCase;

public void register(...) {
UserInfo user = getUserInfoUseCase.getById(userId);
UserInfo member = getUserInfoUseCase.getById(userId);
}
```

Expand Down Expand Up @@ -446,9 +446,9 @@ public class ChallengerCommandService {
// ✅ 인증된 사용자 정보는 @AuthenticationPrincipal로
@PostMapping
public ApiResponse<Long> register(
@AuthenticationPrincipal SecurityUser user,
@AuthenticationPrincipal SecurityUser member,
@RequestBody RegisterRequest request) {
// user.getUserId() 사용
// member.getUserId() 사용
}

// ❌ Request Body에서 userId 받지 않음
Expand Down Expand Up @@ -482,7 +482,7 @@ public void updateNotice(Long noticeId, UpdateCommand command, Long requesterId)
// ❌ N+1 발생 가능
List<Challenger> challengers = repository.findAll();
for (Challenger c : challengers) {
User user = userRepository.findById(c.getUserId()); // N번 쿼리
User member = userRepository.findById(c.getUserId()); // N번 쿼리
}

// ✅ Fetch Join 또는 별도 쿼리
Expand Down
30 changes: 15 additions & 15 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ Level 0 Level 1 Level 2 Level 3
────────────────────────────────────────────────────────────────────────
common ◄──────────── 모든 도메인이 의존

user ◄───────────── organization
member ◄───────────── organization
┌───────────┴───────────┐
Expand All @@ -110,22 +110,22 @@ user ◄───────────── organization
▼ ▼ ▼
curriculum schedule notice

community ◄────────── user, challenger
community ◄────────── member, challenger

form ◄─────────────── user (독립적)
form ◄─────────────── member (독립적)
```

| Domain | Description | Dependencies |
|--------------|---------------------------------|--------------------------|
| common | 공통 (BaseEntity, Exception, DTO) | 없음 |
| user | 사용자, OAuth, 약관 | common |
| organization | 기수, 지부, 학교, 스터디 | common, user |
| challenger | 챌린저, 역할, 상벌점 | user, organization |
| member | 사용자, OAuth, 약관 | common |
| organization | 기수, 지부, 학교, 스터디 | common, member |
| challenger | 챌린저, 역할, 상벌점 | member, organization |
| curriculum | 커리큘럼, 워크북, 미션 | challenger |
| schedule | 일정, 출석 | challenger, organization |
| notice | 공지사항, 읽음, 알림 | challenger, organization |
| community | 게시글, 댓글, 번개모임 | user, challenger |
| form | 지원서 폼, 질문, 응답 | user |
| community | 게시글, 댓글, 번개모임 | member, challenger |
| form | 지원서 폼, 질문, 응답 | member |

---

Expand Down Expand Up @@ -348,8 +348,8 @@ public class ChallengerQueryService implements GetChallengerUseCase {
Challenger challenger = loadChallengerPort.findById(challengerId)
.orElseThrow(() -> new BusinessException(ErrorCode.CHALLENGER_NOT_FOUND));

UserInfo user = getUserInfoUseCase.getById(challenger.getUserId());
return ChallengerInfo.of(challenger, user);
UserInfo member = getUserInfoUseCase.getById(challenger.getUserId());
return ChallengerInfo.of(challenger, member);
}
}
```
Expand Down Expand Up @@ -390,9 +390,9 @@ public class ChallengerController {
@PostMapping
@Operation(summary = "챌린저 등록")
public ApiResponse<Long> register(
@AuthenticationPrincipal SecurityUser user,
@AuthenticationPrincipal SecurityUser member,
@Valid @RequestBody RegisterChallengerRequest request) {
Long id = registerUseCase.register(request.toCommand(user.getUserId()));
Long id = registerUseCase.register(request.toCommand(member.getUserId()));
return ApiResponse.success(id);
}

Expand Down Expand Up @@ -454,14 +454,14 @@ public record ChallengerResponse(
```java
// ❌ Bad: 다른 도메인 Entity 직접 참조
@ManyToOne
private User user;
private User member;

// ✅ Good: ID만 저장
@Column(nullable = false)
private Long userId;

// ✅ Good: 필요시 UseCase로 조회
UserInfo userInfo = getUserInfoUseCase.getById(challenger.getUserId());
UserInfo memberInfo = getUserInfoUseCase.getById(challenger.getUserId());
```

### Event-Based Communication
Expand Down Expand Up @@ -720,7 +720,7 @@ fix: resolve null pointer in attendance check

- Entity에 `@Setter` 사용
- Controller에서 비즈니스 로직 처리
- 다른 도메인 Entity 직접 참조 (`@ManyToOne private User user`)
- 다른 도메인 Entity 직접 참조 (`@ManyToOne private User member`)
- 순환 의존성 (도메인 간 양방향 의존)
- Adapter에서 트랜잭션 관리

Expand Down
57 changes: 24 additions & 33 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ plugins {
java
id("org.springframework.boot") version "3.5.9"
id("io.spring.dependency-management") version "1.1.7"
id("org.asciidoctor.jvm.convert") version "4.0.5"
}

group = "com.umc"
Expand All @@ -20,7 +19,6 @@ configurations {
compileOnly {
extendsFrom(configurations.annotationProcessor.get())
}
create("asciidoctorExt")
}

repositories {
Expand All @@ -32,6 +30,27 @@ val queryDslVersion = "5.0.0"
val jwtVersion = "0.12.5"
val awsVersion = "2.40.12"

// QueryDSL Q클래스 생성 경로 설정
val querydslDir = layout.buildDirectory.dir("generated/querydsl").get().asFile

sourceSets {
main {
java {
srcDirs(querydslDir)
}
}
}

tasks.withType<JavaCompile>().configureEach {
options.generatedSourceOutputDirectory.set(querydslDir)
}

tasks.named("clean") {
doLast {
querydslDir.deleteRecursively()
}
}

dependencies {
// --- Spring Boot Starters (버전 생략: Boot가 관리) ---
implementation("org.springframework.boot:spring-boot-starter-web")
Expand All @@ -56,6 +75,9 @@ dependencies {
annotationProcessor("com.querydsl:querydsl-apt:${queryDslVersion}:jakarta")
annotationProcessor("jakarta.annotation:jakarta.annotation-api")

// APT가 jakarta 클래스를 로딩할 수 있게 명시
annotationProcessor("jakarta.persistence:jakarta.persistence-api")

// --- Database ---
implementation("org.flywaydb:flyway-core")
implementation("org.flywaydb:flyway-database-postgresql")
Expand Down Expand Up @@ -94,39 +116,8 @@ dependencies {
testImplementation("org.testcontainers:testcontainers")
testImplementation("org.testcontainers:junit-jupiter")
testImplementation("org.testcontainers:postgresql")

// --- Spring REST Docs ---
"asciidoctorExt"("org.springframework.restdocs:spring-restdocs-asciidoctor")
testImplementation("org.springframework.restdocs:spring-restdocs-mockmvc")
}

tasks.withType<Test> {
useJUnitPlatform()
}


val snippetsDir = file("build/generated-snippets")

tasks.test {
outputs.dir(snippetsDir)

}

tasks.asciidoctor {
inputs.dir(snippetsDir)
configurations("asciidoctorExt")

sources {
include("**/index.adoc")
}

baseDirFollowsSourceDir()
dependsOn(tasks.test)
}

tasks.bootJar {
dependsOn(tasks.asciidoctor)
from(tasks.asciidoctor.get().outputDir) {
into("static/docs")
}
}
2 changes: 1 addition & 1 deletion docs/패키지_구분_방식.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

## Domain 구분

- user
- member
- organization
- challenger
- activity
Expand Down