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
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package com.atmd.backend.domain.group.dto.request;

import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Getter;
import lombok.NoArgsConstructor;
Expand All @@ -18,8 +21,11 @@ public class GroupCreateRequestDTO {
private String penalty;

/**
* 첫 그룹이 아닌 경우(SUBSCRIBED)에만 사용. 2~5 사이 값.
* 첫 그룹은 서버에서 2로 고정하므로 null 허용.
* 그룹 가용 최대 인원 (방장 포함, 2~5).
* 2인은 무료(GENERAL), 3~5인은 유료(SUBSCRIBED, (maxMemberCount - 2) × 500원).
*/
@NotNull
@Min(2)
@Max(5)
private Integer maxMemberCount;
}
42 changes: 16 additions & 26 deletions src/main/java/com/atmd/backend/domain/group/entity/Group.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@
public class Group extends BaseEntity {

public static final int MAX_GROUPS_PER_USER = 5;
public static final int GENERAL_MAX_MEMBER_COUNT = 2;
public static final int SUBSCRIBED_MIN_MEMBER_COUNT = 2;
public static final int SUBSCRIBED_MAX_MEMBER_COUNT = 5;
public static final int MIN_MEMBER_COUNT = 2;
public static final int MAX_MEMBER_COUNT = 5;
public static final int FREE_MEMBER_THRESHOLD = 2;
public static final int PRICE_PER_MEMBER = 500;

@Id
Expand Down Expand Up @@ -75,44 +75,34 @@ private Group(
this.price = price;
}

public static Group createFirst(
User owner,
String name,
String inviteCode,
String penalty
) {
return Group.builder()
.owner(owner)
.name(name)
.membership(GroupMembership.GENERAL)
.inviteCode(inviteCode)
.penalty(penalty)
.maxMemberCount(GENERAL_MAX_MEMBER_COUNT)
.price(0)
.build();
}

public static Group createSubscribed(
public static Group create(
User owner,
String name,
String inviteCode,
String penalty,
int maxMemberCount
) {
GroupMembership membership = maxMemberCount <= FREE_MEMBER_THRESHOLD
? GroupMembership.GENERAL
: GroupMembership.SUBSCRIBED;
int price = calculatePrice(maxMemberCount);
return Group.builder()
.owner(owner)
.name(name)
.membership(GroupMembership.SUBSCRIBED)
.membership(membership)
.inviteCode(inviteCode)
.penalty(penalty)
.maxMemberCount(maxMemberCount)
.price(maxMemberCount * PRICE_PER_MEMBER)
.price(price)
.build();
}

public static boolean isValidSubscribedCapacity(int memberCount) {
return memberCount >= SUBSCRIBED_MIN_MEMBER_COUNT
&& memberCount <= SUBSCRIBED_MAX_MEMBER_COUNT;
public static int calculatePrice(int maxMemberCount) {
return Math.max(0, maxMemberCount - FREE_MEMBER_THRESHOLD) * PRICE_PER_MEMBER;
}

public static boolean isValidMemberCount(int memberCount) {
return memberCount >= MIN_MEMBER_COUNT && memberCount <= MAX_MEMBER_COUNT;
}

public boolean isOwner(Long userId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,20 +48,17 @@ public GroupResponseDTO create(Long userId, GroupCreateRequestDTO request) {
throw new GeneralException(GroupErrorCode.MAX_GROUPS_EXCEEDED);
}

boolean isFirstGroup = !owner.isFirstGroupCreated();
String inviteCode = generateUniqueInviteCode();
Integer maxMemberCount = request.getMaxMemberCount();
if (maxMemberCount == null || !Group.isValidMemberCount(maxMemberCount)) {
throw new GeneralException(GroupErrorCode.INVALID_MEMBER_COUNT);
}

Group group = isFirstGroup
? Group.createFirst(owner, request.getName(), inviteCode, request.getPenalty())
: createSubscribedGroup(owner, request, inviteCode);
String inviteCode = generateUniqueInviteCode();
Group group = Group.create(owner, request.getName(), inviteCode, request.getPenalty(), maxMemberCount);

groupRepository.save(group);
groupUserRepository.save(GroupUser.of(group, owner));

if (isFirstGroup) {
owner.markFirstGroupCreated();
}

return GroupResponseDTO.of(group, 1L, userId);
}

Expand Down Expand Up @@ -166,14 +163,6 @@ private GroupJoinResponseDTO joinInternal(String inviteCode, User user) {
return GroupJoinResponseDTO.of(group.getId(), group.getName(), currentCount + 1);
}

private Group createSubscribedGroup(User owner, GroupCreateRequestDTO request, String inviteCode) {
Integer requested = request.getMaxMemberCount();
if (requested == null || !Group.isValidSubscribedCapacity(requested)) {
throw new GeneralException(GroupErrorCode.INVALID_MEMBER_COUNT);
}
return Group.createSubscribed(owner, request.getName(), inviteCode, request.getPenalty(), requested);
}

private String generateUniqueInviteCode() {
for (int i = 0; i < MAX_GENERATION_ATTEMPTS; i++) {
String code = randomCode();
Expand Down
7 changes: 0 additions & 7 deletions src/main/java/com/atmd/backend/domain/user/entity/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,6 @@ public class User extends BaseEntity {
@JoinColumn(name = "address_id")
private Address address;

@Column(name = "first_group_created", nullable = false)
private boolean firstGroupCreated = false;

@Builder
private User(String email, String nickname, Provider provider, String providerId, Role role,
Integer age, Gender gender, Double height, Double weight, Address address) {
Expand Down Expand Up @@ -113,8 +110,4 @@ private Double calculateBmi(Double height, Double weight) {
public void updateAddress(Address address) {
this.address = address;
}

public void markFirstGroupCreated() {
this.firstGroupCreated = true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
-- users 테이블에 그룹 도메인용 first_group_created 컬럼 추가
-- 프로덕션 DB에는 이미 수동으로 추가되어 있을 수 있으므로 IF NOT EXISTS 사용 (idempotent)
-- 새 환경 배포 및 DR 상황에서도 안전하게 실행됨

ALTER TABLE users
ADD COLUMN IF NOT EXISTS first_group_created BOOLEAN NOT NULL DEFAULT FALSE;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-- 그룹 생성 정책 변경(2인 무료/3~5인 유료)으로 first_group_created 플래그 미사용 처리
-- 프로덕션 DB에 컬럼이 없는 환경에서도 안전하게 실행되도록 IF EXISTS 사용 (idempotent)

ALTER TABLE users
DROP COLUMN IF EXISTS first_group_created;
Loading