Skip to content

Conversation

@stoneTiger0912
Copy link
Member

@stoneTiger0912 stoneTiger0912 commented Feb 9, 2026

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능

    • 그룹 생성 API 추가: 카테고리, 공개 범위, 가입 정책, 최대 인원, 이미지 참조 등을 지정해 새 그룹 생성 가능.
    • 그룹 소유자 자동 지정: 그룹 생성자는 자동으로 소유자 권한이 부여됩니다.
  • 인프라 개선

    • gRPC 및 Protocol Buffers 빌드/생성 지원 추가.
    • Java 17 도구체인 활성화 및 Redis/H2 테스트 지원 강화.

@stoneTiger0912 stoneTiger0912 self-assigned this Feb 9, 2026
@coderabbitai
Copy link

coderabbitai bot commented Feb 9, 2026

Walkthrough

그룹 생성 기능을 추가했습니다. 도메인 모델, 포트·어댑터, JPA 엔티티·리포지토리, 애플리케이션 서비스, 웹 컨트롤러와 JPA 감사 설정 및 빌드(프로토콜 버퍼·gRPC·QueryDSL) 구성이 포함됩니다.

Changes

Cohort / File(s) Summary
빌드 설정
build.gradle
Protobuf 플러그인 및 설정 추가, Spring gRPC BOM 및 의존성 추가, QueryDSL 설정 및 Java 17 툴체인 활성화, 테스트/런타임 관련 의존성 조정
웹 어댑터
src/main/java/flipnote/group/adapter/in/web/GroupController.java
POST /v1/groups 엔드포인트 추가; 요청 DTO 검증, X-USER-ID 헤더 사용, CreateGroupUseCase 호출
영속성 엔티티
src/main/java/flipnote/group/adapter/out/entity/GroupEntity.java, .../GroupMemberEntity.java
app_groups와 group_members 매핑 JPA 엔티티 추가(열거형 매핑, 제약, 빌더 패턴, BaseEntity 상속 등)
영속성 어댑터
src/main/java/flipnote/group/adapter/out/persistence/GroupRepositoryAdapter.java, .../GroupMemberRepositoryAdapter.java
포트 구현체 추가: 그룹 저장과 소유자 멤버 저장을 JPA 리포지토리로 위임
영속성 매퍼
src/main/java/flipnote/group/adapter/out/persistence/mapper/GroupMapper.java, .../GroupMemberMapper.java
도메인 → JPA 엔티티 변환을 위한 정적 매핑 메서드 추가
DTO 계층
src/main/java/flipnote/group/api/dto/request/CreateGroupRequestDto.java, .../response/CreateGroupResponseDto.java
그룹 생성 요청/응답 레코드 추가, Jakarta Bean Validation 적용, 응답 팩토리 메서드 추가
애플리케이션 포트/명령/결과
src/main/java/flipnote/group/application/port/in/CreateGroupUseCase.java, .../command/CreateGroupCommand.java, .../result/CreateGroupResult.java
CreateGroup 유스케이스 인터페이스 및 명령/결과 레코드 추가
애플리케이션 포트(출력)
src/main/java/flipnote/group/application/port/out/GroupRepositoryPort.java, .../GroupMemberRepositoryPort.java
영속성 추상화 포트 인터페이스 추가(그룹 저장, 소유자 저장)
애플리케이션 서비스
src/main/java/flipnote/group/application/service/CreateGroupService.java
CreateGroupUseCase 구현: 트랜잭션 내 도메인 생성, 그룹 저장 후 소유자 멤버 저장 및 결과 반환
도메인 모델 - 그룹
src/main/java/flipnote/group/domain/model/group/Group.java, Category.java, JoinPolicy.java, Visibility.java, GroupId.java
Group 도메인 클래스(유효성 검사 포함) 및 카테고리/가입정책/노출 enum, GroupId 값 객체 추가
도메인 모델 - 구성원
src/main/java/flipnote/group/domain/model/member/GroupMember.java, GroupMemberRole.java
GroupMember 도메인 및 역할 enum 추가(OWNER 등), 팩토리 메서드 제공
도메인 모델 - 사용자
src/main/java/flipnote/group/domain/model/user/UserId.java
UserId 값 객체(record) 추가
도메인 기반 클래스
src/main/java/flipnote/group/domain/model/BaseEntity.java
JPA 감사(createdAt, modifiedAt) 및 soft-delete(deletedAt) 구현, markDeleted/restore/isDeleted 메서드 추가
인프라 설정
src/main/java/flipnote/group/infrastructure/config/AuditingConfig.java
@EnableJpaAuditing 설정 추가
JPA 리포지토리
src/main/java/flipnote/group/infrastructure/persistence/jpa/GroupRepository.java, .../GroupMemberRepository.java
GroupEntity 및 GroupMemberEntity용 Spring Data JPA 리포지토리 추가

Sequence Diagram(s)

sequenceDiagram
    actor User as User
    participant Controller as GroupController
    participant Service as CreateGroupService
    participant GroupPort as GroupRepositoryPort
    participant MemberPort as GroupMemberRepositoryPort
    participant DB as Database

    rect rgba(200,200,255,0.5)
    User->>Controller: POST /v1/groups (body + X-USER-ID)
    Controller->>Service: create(CreateGroupCommand, userId)
    end

    rect rgba(200,255,200,0.5)
    Service->>Service: Group.create(cmd) (유효성 검사)
    Service->>GroupPort: saveNewGroup(domainGroup)
    GroupPort->>DB: INSERT app_groups
    DB-->>GroupPort: generated groupId
    GroupPort-->>Service: groupId
    Service->>MemberPort: saveOwner(groupId, userId)
    MemberPort->>DB: INSERT group_members (role=OWNER)
    DB-->>MemberPort: 저장 완료
    MemberPort-->>Service: void
    end

    rect rgba(255,200,200,0.5)
    Service-->>Controller: CreateGroupResult(groupId)
    Controller-->>User: 200 OK (CreateGroupResponseDto)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • Chore: 패키지 구조 설정 #1 — 동일한 BaseEntity 관련 변경 기록; 이전 PR이 빈 BaseEntity를 추가했고 이번 PR에서 감사·soft-delete를 확장함.

Poem

🐰 새싹 그룹이 피어났어요,
도메인 뿌리 내리고 리포지토리 댄스,
컨트롤러가 주문하고 서비스가 다리를 놓아,
엔티티와 매퍼가 손을 잡고 빛나네,
토끼가 깡충, 축하의 당근 하나! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.87% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목은 그룹 생성 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/refactor-create-group

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.

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: 11

🤖 Fix all issues with AI agents
In `@build.gradle`:
- Line 15: build.gradle의 설정에서 description = 'Image'로 잘못 설정되어 있습니다; 이 프로젝트는 그룹
서비스이므로 description 값을 'Group' 또는 PR/README에 맞는 적절한 설명으로 변경하세요 (찾을 식별자:
description = 'Image'를 찾아 description 값을 업데이트). 변경 후 커밋 메시지에 "fix: correct
project description" 등으로 기록하세요.
- Around line 67-71: The current configuration sets
options.generatedSourceOutputDirectory for all JavaCompile tasks (via
tasks.withType(JavaCompile).configureEach), which affects test compilation;
restrict this to the main compile task by setting
options.generatedSourceOutputDirectory only for the compileJava task (use the
compileJava task's options and querydslDir) so that querydslDir is applied to
compileJava only and not to testCompile or other JavaCompile tasks.
- Around line 39-65: The dependencies block in build.gradle is missing the
standard Spring Boot test starter; add testImplementation
'org.springframework.boot:spring-boot-starter-test' inside the dependencies { }
section (alongside existing testImplementation/testRuntimeOnly entries) so JUnit
5, Mockito and Spring Test utilities are available for unit/integration tests;
ensure it is added as testImplementation (not testRuntimeOnly) to work with the
current test dependencies like
'org.springframework.boot:spring-boot-starter-data-redis-test'.
- Line 50: Remove the obsolete javax.annotation dependency declaration
implementation 'javax.annotation:javax.annotation-api:1.3.2' from build.gradle
because Spring Boot 4 uses Jakarta EE; instead rely on the existing
jakarta.annotation:jakarta.annotation-api already configured for annotation
processing (referenced elsewhere in this file). Delete the implementation line
for javax.annotation, run a quick build to verify no compile errors, and ensure
all annotation-processing and imports resolve to jakarta.annotation types.
- Around line 78-94: The protobuf configuration currently hardcodes protoc and
grpc plugin artifacts in the protobuf block (artifact =
"com.google.protobuf:protoc:3.25.3" and "io.grpc:protoc-gen-grpc-java:1.64.0"),
causing a mismatch with the Spring gRPC BOM-managed versions (protoc 4.33.2 and
protoc-gen-grpc-java 1.77.1); fix by either removing the explicit version
pinning so the BOM controls versions or update those artifact strings to the BOM
versions (protoc -> com.google.protobuf:protoc:4.33.2 and protoc-gen-grpc-java
-> io.grpc:protoc-gen-grpc-java:1.77.1) in the protobuf { protoc { artifact } }
and plugins { grpc { artifact } } entries to ensure generated code and runtime
libs (grpc-stub, protobuf-java) remain consistent.

In `@src/main/java/flipnote/group/adapter/out/entity/GroupEntity.java`:
- Line 3: GroupEntity currently imports CreateGroupCommand which is unused and
violates dependency direction; remove the unused import statement for
CreateGroupCommand from GroupEntity and ensure the persistence entity does not
reference any application port types (replace any usage with entity/DTO classes
or mapping logic inside application/service layers if present); verify there are
no remaining references to CreateGroupCommand inside the GroupEntity class or
its methods and move any transformation logic that depends on application-layer
types into the appropriate application/service mapper.

In `@src/main/java/flipnote/group/adapter/out/entity/GroupMemberEntity.java`:
- Around line 21-31: GroupMemberEntity's DB-level unique constraint
(uk_group_members_group_user on group_members for (group_id,user_id)) conflicts
with BaseEntity soft-delete semantics and will cause unique violations on
rejoin; fix by either: 1) remove the JPA UniqueConstraint and add a PostgreSQL
partial unique index via migration (name it uk_group_members_group_user) on
(group_id, user_id) WHERE deleted_at IS NULL; or 2) implement a restore flow in
the repository/service that finds a soft-deleted GroupMemberEntity and calls its
restore() on rejoin instead of inserting a new row (adjust createMember logic to
check BaseEntity.deleted_at); or 3) change GroupMemberEntity's deletion behavior
to hard-delete by overriding BaseEntity soft-delete behavior for this entity —
choose one approach and apply the corresponding schema migration or
repository/service change.

In `@src/main/java/flipnote/group/api/dto/request/CreateGroupRequestDto.java`:
- Line 12: The CreateGroupRequestDto's name field lacks a max-length constraint
and can exceed GroupEntity.name (length = 50); add a DTO-level validation by
annotating the name field in CreateGroupRequestDto with `@Size`(max = 50) and
import jakarta.validation.constraints.Size so validation fails with a clear
error before hitting the DB.

In `@src/main/java/flipnote/group/application/port/out/GroupRepositoryPort.java`:
- Around line 1-8: The port interface GroupRepositoryPort currently depends on
the adapter entity GroupEntity and imports an unused CreateGroupCommand; change
the port to accept/use the domain Group model (e.g., replace GroupEntity
parameter with your domain model type, e.g., Group) so application.port.out
depends only on domain types, remove the unused CreateGroupCommand import, and
perform the entity↔domain mapping inside the adapter implementation (e.g.,
GroupRepositoryAdapter) when implementing saveNewGroup.

In `@src/main/java/flipnote/group/application/service/CreateGroupService.java`:
- Line 6: Change the port to accept the domain object instead of a persistence
entity: update GroupRepositoryPort.saveNewGroup to take a domain Group and
return Long, then move the mapping logic into the adapter by implementing
GroupRepositoryAdapter.saveNewGroup to call GroupMapper.createNewEntity(group)
and persist the resulting GroupEntity; finally remove the adapter import from
CreateGroupService (stop using GroupMapper there) and call the updated
GroupRepositoryPort.saveNewGroup(domainGroup) instead. Ensure method signatures
for GroupRepositoryPort.saveNewGroup, GroupRepositoryAdapter.saveNewGroup,
GroupMapper.createNewEntity, and usages in CreateGroupService are updated
consistently.

In `@src/main/java/flipnote/group/domain/model/group/Group.java`:
- Around line 90-109: The validate(CreateGroupCommand cmd) method is missing a
length check for cmd.name(), which can exceed the GroupEntity name column max
length (50) and cause DB exceptions; add a check in validate to ensure
cmd.name().length() <= 50 (or use a constant) and throw an
IllegalArgumentException (e.g., "name too long") when it exceeds that limit so
invalid input is rejected at the domain layer before persistence.
🧹 Nitpick comments (13)
src/main/java/flipnote/group/domain/model/group/Category.java (1)

6-15: 유효하지 않은 카테고리 값에 대해 null 반환 대신 예외를 던지는 것을 고려해 주세요.

null/빈 문자열이 아닌데 매칭되는 enum 상수가 없는 경우는 클라이언트의 잘못된 입력일 가능성이 높습니다. null을 반환하면 호출부에서 NPE가 발생할 수 있습니다. 카테고리가 선택(optional) 필드라면 null/빈 문자열에 대한 null 반환은 괜찮지만, 유효하지 않은 값에 대해서는 IllegalArgumentException을 던지는 것이 안전합니다.

♻️ 제안하는 수정안
 public static Category from(String category) {
   if (category == null || category.isEmpty()) {
     return null;
   }
   try {
     return Category.valueOf(category);
   } catch (IllegalArgumentException e) {
-    return null;
+    throw new IllegalArgumentException("Invalid category: " + category);
   }
 }
src/main/java/flipnote/group/infrastructure/config/AuditingConfig.java (1)

6-13: 빈 Javadoc 블록 제거 권장

Lines 6-8의 빈 Javadoc 주석(/** */)은 의미 없는 코드 노이즈입니다. 제거하거나 클래스 목적을 설명하는 내용을 추가해 주세요.

♻️ 제안
-/**
- *
- */
 `@EnableJpaAuditing`
 `@Configuration`
 public class AuditingConfig {
src/main/java/flipnote/group/domain/model/BaseEntity.java (1)

14-49: Soft-delete 필터링 전략 확인 필요

BaseEntity에 soft-delete 메커니즘이 잘 구현되어 있습니다. 다만, 이를 상속하는 엔티티(GroupEntity, GroupMemberEntity)에 @Where(clause = "deleted_at IS NULL") 또는 Hibernate 6의 @SQLRestriction 같은 자동 필터링이 적용되어 있지 않습니다. 별도의 쿼리 조건 없이 조회하면 삭제된 레코드도 함께 반환될 수 있으므로, 향후 조회 로직에서 이를 고려해 주세요.

src/main/java/flipnote/group/application/port/out/GroupMemberRepositoryPort.java (1)

1-7: 사용되지 않는 import 제거

Line 3의 GroupMemberRole import가 인터페이스 내에서 사용되지 않습니다. 제거해 주세요.

♻️ 제안
 package flipnote.group.application.port.out;
 
-import flipnote.group.domain.model.member.GroupMemberRole;
-
 public interface GroupMemberRepositoryPort {
     void saveOwner(Long groupId, Long userId);
 }
src/main/java/flipnote/group/adapter/out/persistence/mapper/GroupMemberMapper.java (1)

10-19: GroupMemberEntity.createOwner와 중복되는 로직입니다.

GroupMemberEntity(관련 스니펫 참조)에 이미 동일한 createOwner(Long groupId, Long userId) 정적 팩토리 메서드가 존재합니다. 이 매퍼는 해당 로직을 그대로 복제하고 있어 불필요합니다. GroupMemberRepositoryAdapter에서 GroupMemberEntity.createOwner(groupId, userId)를 직접 호출하면 이 클래스를 제거할 수 있습니다.

또한, 정적 메서드만 있는 유틸리티 클래스에 @Component를 붙이면 불필요한 Spring 빈이 등록됩니다. GroupMapper도 동일한 패턴을 사용하고 있으니 함께 정리하는 것을 권장합니다.

src/main/java/flipnote/group/domain/model/member/GroupMember.java (1)

10-11: 도메인 모델에 @Setter는 캡슐화를 약화시킵니다.

GroupMember는 도메인 모델로서 불변성을 보장해야 합니다. @Setter를 제거하고, 상태 변경이 필요하다면 의미 있는 도메인 메서드(예: changeRole(GroupMemberRole newRole))를 통해 제어하는 것이 좋습니다. 팩토리 메서드(createOwner, join)를 통한 생성 패턴은 적절하므로, setter 없이도 충분히 동작합니다.

♻️ `@Setter` 제거 제안
 `@Getter`
-@Setter
 `@NoArgsConstructor`(access = AccessLevel.PRIVATE)
 public class GroupMember {
src/main/java/flipnote/group/adapter/in/web/GroupController.java (1)

30-47: 리소스 생성 시 HTTP 201 (Created) 응답이 더 적절합니다.

POST로 그룹을 생성하는 엔드포인트이므로 ResponseEntity.ok()(200) 대신 ResponseEntity.status(HttpStatus.CREATED).body(res) 또는 ResponseEntity.created(uri).body(res)를 사용하는 것이 REST 규약에 부합합니다.

♻️ 수정 제안
-		return ResponseEntity.ok(res);
+		return ResponseEntity.status(HttpStatus.CREATED).body(res);
src/main/java/flipnote/group/adapter/out/persistence/mapper/GroupMapper.java (1)

10-12: @Component는 정적 메서드만 있는 유틸리티 클래스에 불필요합니다.

createNewEntitystatic 메서드이므로 Spring 빈으로 등록할 필요가 없습니다. GroupMemberMapper도 동일한 패턴을 따르고 있으니, 둘 다 @Component를 제거하고 순수 유틸리티 클래스로 사용하는 것을 권장합니다.

♻️ 제안
-@Component
 `@NoArgsConstructor`(access = AccessLevel.PRIVATE)
 public class GroupMapper {
src/main/java/flipnote/group/domain/model/group/Group.java (3)

3-3: 도메인 모델이 애플리케이션 포트에 의존하고 있습니다.

Group 도메인 모델이 CreateGroupCommand(application port)를 직접 임포트하면 헥사고날 아키텍처의 의존성 방향 원칙에 위배됩니다. 도메인 계층은 가장 안쪽 계층으로, 외부 계층(application)에 의존하면 안 됩니다. create() 메서드가 개별 파라미터를 받거나, 도메인 계층에 정의된 인터페이스/VO를 사용하도록 변경하는 것을 권장합니다.


10-12: 도메인 모델에 @Setter를 사용하면 불변성이 깨집니다.

@Setter가 클래스 전체에 적용되어 id, memberCount 등 모든 필드가 외부에서 자유롭게 변경 가능합니다. 도메인 모델의 상태 변경은 의미 있는 도메인 메서드를 통해서만 이루어지는 것이 바람직합니다. @Setter를 제거하고 필요한 상태 변경만 명시적 메서드로 노출하는 것을 권장합니다.


5-5: 사용되지 않는 import: lombok.Builder

Group 클래스에 @Builder 어노테이션이 사용되지 않으므로 이 import를 제거해 주세요.

♻️ 제안
-import lombok.Builder;
build.gradle (2)

61-64: QueryDSL 버전(5.0.0)이 하드코딩되어 있습니다. 버전 변수를 사용하거나 BOM 관리를 권장합니다.

여러 곳에서 동일 버전을 반복 기재하면 업그레이드 시 불일치가 발생할 수 있습니다.

♻️ 버전 변수 추출 제안
 ext {
 	springGrpcVersion = "1.0.1"
+	querydslVersion = "5.0.0"
 }
-	implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
-	annotationProcessor "com.querydsl:querydsl-apt:5.0.0:jakarta"
+	implementation "com.querydsl:querydsl-jpa:${querydslVersion}:jakarta"
+	annotationProcessor "com.querydsl:querydsl-apt:${querydslVersion}:jakarta"

96-105: $buildDir는 Gradle 8+에서 deprecated입니다. layout.buildDirectory를 사용하세요.

Line 67에서는 layout.buildDirectory를 올바르게 사용하고 있지만, 여기서는 deprecated된 $buildDir를 사용하고 있어 일관성이 없습니다. Gradle 9에서는 $buildDir가 제거될 예정입니다.

♻️ 수정 제안
 sourceSets {
 	main {
 		java {
 			srcDirs += [
-					"$buildDir/generated/sources/proto/main/java",
-					"$buildDir/generated/sources/proto/main/grpc"
+					layout.buildDirectory.dir("generated/sources/proto/main/java").get().asFile,
+					layout.buildDirectory.dir("generated/sources/proto/main/grpc").get().asFile
 			]
 		}
 	}
 }

Comment on lines +21 to +31
@Table(
name = "group_members",
uniqueConstraints = {
@UniqueConstraint(
name = "uk_group_members_group_user",
columnNames = {"group_id", "user_id"}
)
}
)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class GroupMemberEntity extends BaseEntity {
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

Soft-delete와 unique constraint 간 충돌 가능성

(group_id, user_id)에 대한 unique constraint가 설정되어 있으나, BaseEntity의 soft-delete 패턴을 사용하면 탈퇴(soft-deleted) 후 재가입 시 DB 레벨에서 unique constraint violation이 발생할 수 있습니다.

해결 방안으로는:

  1. Unique constraint에 deleted_at IS NULL partial index 적용 (PostgreSQL 지원)
  2. 재가입 시 soft-deleted 레코드를 restore()하여 재사용
  3. Hard delete로 전환

향후 멤버 탈퇴/재가입 플로우 구현 시 반드시 고려해 주세요.

🤖 Prompt for AI Agents
In `@src/main/java/flipnote/group/adapter/out/entity/GroupMemberEntity.java`
around lines 21 - 31, GroupMemberEntity's DB-level unique constraint
(uk_group_members_group_user on group_members for (group_id,user_id)) conflicts
with BaseEntity soft-delete semantics and will cause unique violations on
rejoin; fix by either: 1) remove the JPA UniqueConstraint and add a PostgreSQL
partial unique index via migration (name it uk_group_members_group_user) on
(group_id, user_id) WHERE deleted_at IS NULL; or 2) implement a restore flow in
the repository/service that finds a soft-deleted GroupMemberEntity and calls its
restore() on rejoin instead of inserting a new row (adjust createMember logic to
check BaseEntity.deleted_at); or 3) change GroupMemberEntity's deletion behavior
to hard-delete by overriding BaseEntity soft-delete behavior for this entity —
choose one approach and apply the corresponding schema migration or
repository/service change.

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: 1

🤖 Fix all issues with AI agents
In `@build.gradle`:
- Around line 61-64: Update the QueryDSL dependency declarations to let the BOM
manage the version or explicitly set it to 5.1.0+: remove the hardcoded
"5.0.0:jakarta" from implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
and annotationProcessor "com.querydsl:querydsl-apt:5.0.0:jakarta" (or change
both to 5.1.0 or later) so Spring Boot 4's BOM (which expects 5.1.0) is not
overridden; also replace any usage of the deprecated $buildDir (lines referenced
around $buildDir) with layout.buildDirectory to be compatible with Gradle 8+ and
future Gradle 10 removal.
🧹 Nitpick comments (1)
build.gradle (1)

96-105: $buildDir는 Gradle 8+에서 deprecated되었습니다. layout.buildDirectory를 사용하세요.

Line 67에서 이미 layout.buildDirectory를 사용하고 있으므로 일관성을 위해 여기서도 동일한 API를 사용하는 것이 좋습니다.

♻️ 수정 제안
 sourceSets {
 	main {
 		java {
 			srcDirs += [
-					"$buildDir/generated/sources/proto/main/java",
-					"$buildDir/generated/sources/proto/main/grpc"
+					layout.buildDirectory.dir("generated/sources/proto/main/java").get().asFile,
+					layout.buildDirectory.dir("generated/sources/proto/main/grpc").get().asFile
 			]
 		}
 	}
 }

Comment on lines +61 to +64
implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
annotationProcessor "com.querydsl:querydsl-apt:5.0.0:jakarta"
annotationProcessor "jakarta.annotation:jakarta.annotation-api"
annotationProcessor "jakarta.persistence:jakarta.persistence-api"
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
# Check if there's actual QueryDSL usage in the codebase
echo "=== QueryDSL usage in Java files ==="
rg -n 'querydsl|JPAQueryFactory|QClass|BooleanBuilder|@QueryEntity' --type java 2>/dev/null | head -30

echo ""
echo "=== Check full build.gradle to understand context ==="
wc -l build.gradle

echo ""
echo "=== Check Spring Boot version and toolchain ==="
rg -n 'spring-boot-gradle-plugin|SpringBootPlugin|sourceCompatibility|targetCompatibility|toolchain' build.gradle

Repository: FlipNoteTeam/FlipNote-Group

Length of output: 244


🌐 Web query:

QueryDSL 5.0.0 Spring Boot 4 compatibility Hibernate 7 Jakarta EE

💡 Result:

  • Spring Boot 4 baseline (JPA/Hibernate/Jakarta): Boot 4.0 upgrades to Jakarta Persistence 3.2 and Hibernate ORM 7.1 (Jakarta EE 11 level). [1] Spring Framework 7 (the foundation for Boot 4) also states a Jakarta EE 11 baseline (incl. Hibernate ORM 7). [2]
  • QueryDSL 5.0.0 + Jakarta EE: QueryDSL 5.x supports Jakarta namespaces via the jakarta classifier (e.g., querydsl-jpa:…:jakarta, querydsl-apt:…:jakarta). [3]
  • Hibernate 7 compatibility risk: QueryDSL’s Hibernate-specific integration (com.querydsl.jpa.hibernate.*) depends on Hibernate native APIs (e.g., ScrollableResults) and has known breakages already with Hibernate 6.x that were closed as “wontfix” for QueryDSL 5.0.0-era usage. [4] With Boot 4 moving to Hibernate 7.1 [1], you should assume Hibernate-specific QueryDSL features may break unless proven in your test suite.
  • Practical recommendation:
    1. Prefer pure JPA QueryDSL usage (EntityManager-based) and avoid Hibernate-only QueryDSL APIs if you want the best chance of working on Boot 4/Hibernate 7.1.
    2. Don’t stick to 5.0.0—QueryDSL 5.1.0 exists (latest tag) and is the safer starting point for any modern stack testing. [5]

Sources: Spring Boot 4.0 release notes [1], Spring Framework 7 baseline announcement [2], QueryDSL Jakarta classifier guidance [3], QueryDSL Hibernate 6.x incompatibility issue example [4], QueryDSL releases (5.1.0) [5].


🌐 Web query:

spring-boot-starter-data-redis-test Maven artifact

💡 Result:

Maven coordinates

  • GroupId: org.springframework.boot
  • ArtifactId: spring-boot-starter-data-redis-test
  • What it is: Starter for testing Redis with Spring Data Redis (Lettuce). [1]

Latest versions in Maven Central (as of Jan 22, 2026)

  • Latest stable: 4.0.2 [2]
  • Milestone: 4.1.0-M1 [2]

Maven dependency (typical: test scope)

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis-test</artifactId>
  <version>4.0.2</version>
  <scope>test</scope>
</dependency>

🌐 Web query:

QueryDSL version Spring Boot 4.0 recommended compatibility matrix

💡 Result:

Spring Boot 4.0.x → recommended QueryDSL version (compatibility)

Spring Boot Spring Data baseline Recommended QueryDSL (managed by Boot BOM)
4.0.x Spring Data 2025.1 QueryDSL 5.1.0 (via com.querydsl:querydsl-bom) (github.com)

Notes

  • Spring Data’s Querydsl integration is best-effort and mentions that the community has also forked Querydsl under OpenFeign (io.github.openfeign.querydsl). (docs.spring.io)
  • If you use Spring Boot’s dependency management (spring-boot-dependencies), you typically omit Querydsl versions and let Boot pin them (Boot 4.0.2 pins com.querydsl:querydsl-bom to 5.1.0). (mvnrepository.com)

Citations:


🏁 Script executed:

#!/bin/bash
echo "=== Lines 96-105 (sourceSets with $buildDir) ==="
sed -n '96,105p' build.gradle

echo ""
echo "=== Lines 57-58 (test starters) ==="
sed -n '55,65p' build.gradle

echo ""
echo "=== Check Gradle version ==="
if [ -f gradle/wrapper/gradle-wrapper.properties ]; then
  rg 'distributionUrl' gradle/wrapper/gradle-wrapper.properties
fi

echo ""
echo "=== Check for deprecated buildDir usage ==="
rg '\$buildDir' build.gradle

Repository: FlipNoteTeam/FlipNote-Group

Length of output: 1135


🌐 Web query:

Gradle $buildDir deprecated layout.buildDirectory when removed

💡 Result:

  • Project.buildDir (a File) was deprecated in Gradle 8.x in favor of the lazy DirectoryProperty project.layout.buildDirectory. [1]
  • It has not been removed in Gradle 9.0.0 (the Gradle 9.0 upgrade guide lists many removals, but does not list Project.buildDir as removed). [2]
  • The Gradle team is tracking its removal in gradle/gradle issue #25661: it was “tentatively scheduled for Gradle 9” in the issue text, but the issue is currently targeted at the 10.0.0 RC1 milestone—so removal is likely Gradle 10, not 9. [3]

Migration: use layout.buildDirectory (and .dir(...) / .file(...), or .fileValue(...) if you need to set it from a File). [1]


QueryDSL 5.0.0을 5.1.0으로 업그레이드하거나 버전을 명시하지 않아야 합니다.

Spring Boot 4.0의 BOM은 QueryDSL을 5.1.0으로 관리하지만, 빌드파일에서 명시적으로 5.0.0을 지정하면 이를 무시합니다. QueryDSL 5.0.0은 Hibernate 6.x 이상과의 호환성 문제가 있으며 "wontfix"로 표시되었고, Spring Boot 4가 사용하는 Hibernate 7.1과의 동작 보장이 불확실합니다.

두 가지 해결책:

  1. QueryDSL 의존성의 버전을 제거하여 BOM이 관리하도록 함 (권장)
  2. 명시적으로 5.1.0 이상으로 업그레이드

또한 lines 100-101의 $buildDir는 Gradle 8.x부터 deprecated되었습니다. Gradle 10에서 제거될 예정이므로 layout.buildDirectory로 변경하기를 권장합니다.

🤖 Prompt for AI Agents
In `@build.gradle` around lines 61 - 64, Update the QueryDSL dependency
declarations to let the BOM manage the version or explicitly set it to 5.1.0+:
remove the hardcoded "5.0.0:jakarta" from implementation
'com.querydsl:querydsl-jpa:5.0.0:jakarta' and annotationProcessor
"com.querydsl:querydsl-apt:5.0.0:jakarta" (or change both to 5.1.0 or later) so
Spring Boot 4's BOM (which expects 5.1.0) is not overridden; also replace any
usage of the deprecated $buildDir (lines referenced around $buildDir) with
layout.buildDirectory to be compatible with Gradle 8+ and future Gradle 10
removal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant