Skip to content

[FEAT] 모임과 태그 엔티티 구성#36

Merged
LimdaeIl merged 2 commits intomainfrom
feat/group-entity
Dec 8, 2025
Merged

[FEAT] 모임과 태그 엔티티 구성#36
LimdaeIl merged 2 commits intomainfrom
feat/group-entity

Conversation

@LimdaeIl
Copy link
Collaborator

@LimdaeIl LimdaeIl commented Dec 8, 2025

📝 Pull Request

📌 PR 종류

해당하는 항목에 체크해주세요.

  • 기능 추가 (Feature)
  • 버그 수정 (Fix)
  • 문서 수정 (Docs)
  • 코드 리팩터링 (Refactor)
  • 테스트 추가 (Test)
  • 기타 변경 (Chore)

✨ 변경 내용

  • Group 루트 애그리거트 기준으로, GroupImage, Group Tag, GroupUser 엔티티를 생성합니다.
  • GroupRole은 ENUM 타입으로 HOST, MEMBER를 구분할 수 있도록 합니다.
  • Tag 의 경우 Tag 엔티티와 함께 Controller, Service, Repository 클래스를 생성합니다.

🔍 관련 이슈

🧪 테스트

변경된 기능에 대한 테스트 범위 또는 테스트 결과를 작성해주세요.

  • 유닛 테스트 추가 / 수정
  • 통합 테스트 검증
  • 수동 테스트 완료

🚨 확인해야 할 사항 (Checklist)

PR을 제출하기 전에 아래 항목들을 확인해주세요.

  • 코드 포매팅 완료
  • 불필요한 파일/코드 제거
  • 로직 검증 완료
  • 프로젝트 빌드 성공
  • 린트/정적 분석 통과 (해당 시)

🙋 기타 참고 사항

리뷰어가 참고하면 좋을 만한 추가 설명이 있다면 적어주세요.

Summary by CodeRabbit

릴리스 노트

  • New Features
    • 그룹 관리 기능이 추가되었습니다. 제목, 위치, 시간, 이미지, 최대 참여자 수를 포함하여 그룹을 생성할 수 있습니다.
    • 태그 시스템이 도입되어 그룹을 분류하고 관리할 수 있습니다.
    • 그룹 멤버십 관리 및 호스트/멤버 역할 기능이 추가되었습니다.

✏️ Tip: You can customize this high-level summary in your review settings.

@LimdaeIl LimdaeIl self-assigned this Dec 8, 2025
Copilot AI review requested due to automatic review settings December 8, 2025 07:38
@LimdaeIl LimdaeIl added the ✨enhancement New feature or request label Dec 8, 2025
@LimdaeIl LimdaeIl moved this from Backlog to In progress in WeGo-Together Backend Dec 8, 2025
@coderabbitai
Copy link

coderabbitai bot commented Dec 8, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

이 변경사항은 모임(Group) 및 태그(Tag) 엔티티 구조를 도입합니다. Group 엔티티는 다중 이미지, 태그, 사용자 관계를 포함하고, GroupUser와 GroupTag를 통해 관계를 관리합니다. Tag 엔티티는 기본 도메인 모델로 제공되며, 관련 리포지토리, 서비스, 컨트롤러 스캐폴드가 추가됩니다.

Changes

집단 / 파일 변경 요약
모임 도메인 엔티티
src/main/java/team/wego/wegobackend/group/domain/Group.java, GroupImage.java, GroupRole.java, GroupTag.java, GroupUser.java
Group 루트 애그리거트와 관련 엔티티들을 도입. Group은 이미지, 사용자, 태그에 대한 일대다 관계를 포함 (cascade, orphanRemoval 설정). GroupUser 및 GroupTag는 관계 엔티티로 양방향 연관을 관리. GroupRole 열거형(HOST, MEMBER)으로 역할 구분. 각 엔티티는 정적 팩토리 메서드 제공.
태그 도메인 모델
src/main/java/team/wego/wegobackend/tag/domain/entity/Tag.java, tag/domain/repository/TagRepository.java
Tag 엔티티를 도입하며 고유 제약 조건(uk_tags_name)을 v1_tags 테이블에 적용. Tag.create(String name) 팩토리 메서드 제공. TagRepository는 JpaRepository를 확장하며 표준 CRUD 기능 제공.
태그 애플리케이션 및 프레젠테이션
src/main/java/team/wego/wegobackend/tag/application/service/TagService.java, tag/presentation/TagController.java
TagService 서비스 클래스(TagRepository 주입)와 TagController REST 컨트롤러 스캐폴드("/api/v1/tags" 경로) 도입. 현재 엔드포인트 메서드는 구현되지 않음.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • 주의 영역:
    • Group 엔티티의 cascade 및 orphanRemoval 설정이 의도한 대로 작동하는지 확인 필요
    • 양방향 관계(Group ↔ GroupImage/GroupTag/GroupUser)의 일관성 및 순환 참조 가능성 검토
    • GroupUser 및 GroupTag의 팩토리 메서드에서 group.addUser(), group.addTag() 호출 시 올바른 초기화 순서
    • 지연 로딩(LAZY) 설정으로 인한 잠재적 N+1 쿼리 문제

Poem

🐰 모임의 집을 지었네, 친구들과 태그로 꾸미고,
이미지 붙이고 역할 나누니 참 좋구나!
아그리거트 패턴으로 질서 있게,
데이터베이스에 새로운 정원이 피어난다! 🌱

✨ 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/group-entity

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 555652a and c7f8719.

📒 Files selected for processing (9)
  • src/main/java/team/wego/wegobackend/group/domain/Group.java (1 hunks)
  • src/main/java/team/wego/wegobackend/group/domain/GroupImage.java (1 hunks)
  • src/main/java/team/wego/wegobackend/group/domain/GroupRole.java (1 hunks)
  • src/main/java/team/wego/wegobackend/group/domain/GroupTag.java (1 hunks)
  • src/main/java/team/wego/wegobackend/group/domain/GroupUser.java (1 hunks)
  • src/main/java/team/wego/wegobackend/tag/application/service/TagService.java (1 hunks)
  • src/main/java/team/wego/wegobackend/tag/domain/entity/Tag.java (1 hunks)
  • src/main/java/team/wego/wegobackend/tag/domain/repository/TagRepository.java (1 hunks)
  • src/main/java/team/wego/wegobackend/tag/presentation/TagController.java (1 hunks)

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

@LimdaeIl LimdaeIl merged commit c3e113c into main Dec 8, 2025
4 of 5 checks passed
@LimdaeIl LimdaeIl deleted the feat/group-entity branch December 8, 2025 07:38
@github-project-automation github-project-automation bot moved this from In progress to Done in WeGo-Together Backend Dec 8, 2025
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR establishes the foundational entity structure for the Group domain, creating a root aggregate (Group) with its associated entities (GroupImage, GroupTag, GroupUser) and introducing a Tag management system with its controller, service, and repository layers.

Key changes:

  • Created Group aggregate root with bidirectional relationships to images, tags, and users
  • Introduced GroupRole enum to distinguish between HOST and MEMBER roles
  • Implemented Tag entity with supporting infrastructure (Controller, Service, Repository)

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 15 comments.

Show a summary per file
File Description
Group.java Root aggregate entity with relationships to images, tags, users, and host; includes factory method and relationship helper methods
GroupImage.java Entity for managing group images with sort order; maintains relationship to Group
GroupTag.java Junction entity linking Group and Tag in a many-to-many relationship
GroupUser.java Junction entity linking Group and User with role assignment and join/leave timestamps
GroupRole.java Enum defining HOST and MEMBER roles for group participation
Tag.java Tag entity with unique name constraint and factory method
TagRepository.java JPA repository interface for Tag entity
TagService.java Service layer for Tag operations (currently empty placeholder)
TagController.java REST controller for Tag endpoints (currently empty placeholder)

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +49 to +57
public static GroupUser create(Group group, User user, GroupRole role) {
GroupUser groupUser = new GroupUser();
groupUser.group = group;
groupUser.user = user;
groupUser.groupRole = role;
groupUser.joinedAt = LocalDateTime.now();
group.addUser(groupUser);
return groupUser;
}
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

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

The create method doesn't validate that the group, user, and role parameters are not null. Since these are all marked with nullable = false in the database, null values will cause constraint violations. Consider adding null checks:

public static GroupUser create(Group group, User user, GroupRole role) {
    if (group == null || user == null || role == null) {
        throw new IllegalArgumentException("Group, User, and Role cannot be null");
    }
    GroupUser groupUser = new GroupUser();
    // ... rest of the method
}

Copilot uses AI. Check for mistakes.

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "group_tag_id", nullable = false, updatable = false)
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

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

There's an extra space in the @Column annotation: "group_tag_id", nullable (double space before nullable). This should be a single space for consistency.

Suggested change
@Column(name = "group_tag_id", nullable = false, updatable = false)
@Column(name = "group_tag_id", nullable = false, updatable = false)

Copilot uses AI. Check for mistakes.
public class GroupUser extends BaseTimeEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

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

The id column is missing the @Column annotation with name, nullable, and updatable properties. For consistency with other entities in this codebase (like GroupImage, GroupTag, Tag), consider adding: @Column(name = "group_user_id", nullable = false, updatable = false)

Suggested change
@GeneratedValue(strategy = GenerationType.IDENTITY)
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "group_user_id", nullable = false, updatable = false)

Copilot uses AI. Check for mistakes.
Comment on lines +32 to +36
public static Tag create(String name) {
Tag tag = new Tag();
tag.name = name;
return tag;
}
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

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

The create method doesn't validate that the name parameter is not null or empty. Since the database column is marked as nullable = false, attempting to create a Tag with a null or empty name will cause a database constraint violation. Consider adding validation:

public static Tag create(String name) {
    if (name == null || name.trim().isEmpty()) {
        throw new IllegalArgumentException("Tag name cannot be null or empty");
    }
    Tag tag = new Tag();
    tag.name = name;
    return tag;
}

Copilot uses AI. Check for mistakes.
Comment on lines +37 to +43
public static GroupTag create(Group group, Tag tag) {
GroupTag groupTag = new GroupTag();
groupTag.group = group;
groupTag.tag = tag;
group.addTag(groupTag);
return groupTag;
}
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

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

The create method doesn't validate that the group and tag parameters are not null. Since these are marked with nullable = false in the database, null values will cause constraint violations. Consider adding null checks:

public static GroupTag create(Group group, Tag tag) {
    if (group == null || tag == null) {
        throw new IllegalArgumentException("Group and Tag cannot be null");
    }
    GroupTag groupTag = new GroupTag();
    // ... rest of the method
}

Copilot uses AI. Check for mistakes.
Comment on lines +15 to +20

@Getter(AccessLevel.PUBLIC)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(name = "v1_group_images")
@Entity
public class GroupImage {
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

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

The GroupImage entity doesn't extend BaseTimeEntity while other related entities (Group, GroupTag, GroupUser) do. This inconsistency means GroupImage won't have createdAt and updatedAt timestamps. Consider extending BaseTimeEntity for consistency and to track when images are added or modified.

Suggested change
@Getter(AccessLevel.PUBLIC)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(name = "v1_group_images")
@Entity
public class GroupImage {
import team.wego.wegobackend.common.domain.BaseTimeEntity;
@Getter(AccessLevel.PUBLIC)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(name = "v1_group_images")
@Entity
public class GroupImage extends BaseTimeEntity {

Copilot uses AI. Check for mistakes.
Comment on lines +11 to +16
public class TagController {

private final TagService tagService;


}
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

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

[nitpick] The TagController class is empty except for the injected service. While this may be intentional for initial entity setup, consider adding a TODO comment or basic endpoint (e.g., to list or create tags) to clarify the intended future functionality and prevent this class from being accidentally left unused.

Copilot uses AI. Check for mistakes.

@Getter(AccessLevel.PUBLIC)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(name = "v1_group_users")
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

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

Missing unique constraint on the group_id and user_id combination. Without this constraint, the same user can be added to the same group multiple times (e.g., as both HOST and MEMBER, or as MEMBER multiple times), which could lead to data inconsistencies. Consider adding a unique constraint:

@Table(name = "v1_group_users",
    uniqueConstraints = {
        @UniqueConstraint(name = "uk_group_user", columnNames = {"group_id", "user_id"})
    })
Suggested change
@Table(name = "v1_group_users")
@Table(
name = "v1_group_users",
uniqueConstraints = {
@jakarta.persistence.UniqueConstraint(
name = "uk_group_user",
columnNames = {"group_id", "user_id"}
)
}
)

Copilot uses AI. Check for mistakes.

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "group_id", nullable = false, unique = true)
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

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

The unique = true constraint on the group_id column is redundant. Primary key columns are already unique by definition. This constraint adds unnecessary metadata to the schema.

Suggested change
@Column(name = "group_id", nullable = false, unique = true)
@Column(name = "group_id", nullable = false)

Copilot uses AI. Check for mistakes.
import team.wego.wegobackend.common.entity.BaseTimeEntity;

@Getter(AccessLevel.PUBLIC)
@NoArgsConstructor
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

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

The @NoArgsConstructor annotation is missing the access parameter. For consistency with other entities in this codebase (Group, GroupTag, GroupUser, GroupImage), consider adding access = AccessLevel.PROTECTED to prevent uncontrolled instantiation: @NoArgsConstructor(access = AccessLevel.PROTECTED)

Suggested change
@NoArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨enhancement New feature or request

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[FEAT] 모임과 태그 엔티티 구성

1 participant