Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
1ac59f5
fix: 어드민 채팅방 메시지 전송 403 에러 재수정
JanooGwan Feb 13, 2026
00f30dc
refactor: 동아리 상세 정보 Response 수정
JanooGwan Feb 14, 2026
fa7567b
refactor: ClubDetailResponse 필드 추가
JanooGwan Feb 14, 2026
753d245
refactor: 동아리 상세 정보 Response 수정
JanooGwan Feb 14, 2026
4c5d03d
Merge pull request #217 from BCSDLab/develop
Soundbar91 Feb 14, 2026
c2d133d
Merge pull request #219 from BCSDLab/develop
Soundbar91 Feb 14, 2026
12881a9
Merge pull request #220 from BCSDLab/develop
Soundbar91 Feb 14, 2026
0c3083f
fix: 어드민 권한 체크 로직 수정
Soundbar91 Feb 14, 2026
897dbfc
feat: 준동아리 카테고리 추가 (#226)
dh2906 Feb 15, 2026
fe27645
refactor: 모든 사용자가 동아리 회비 정보에 접근할 수 있도록 변경
JanooGwan Feb 14, 2026
f0b5a75
feat: 애플 토큰 revoke 로직 추가 (#235)
Soundbar91 Feb 16, 2026
ff1a18e
fix: 환경변수 수정
Soundbar91 Feb 16, 2026
0489332
Merge pull request #238 from BCSDLab/develop
Soundbar91 Feb 16, 2026
dff119b
fix: 어드민 채팅방 리스트 조회 시 상대방 이름이 출력되지 않는 오류 해결
JanooGwan Feb 16, 2026
0b65217
hotfix: pre-member 조회, 삭제 API 추가
dh2906 Feb 17, 2026
c22f1ee
docs: 명세 수정
dh2906 Feb 17, 2026
6a1c004
Merge pull request #246 from BCSDLab/hotfix/pre-member-manage
dh2906 Feb 17, 2026
b5d09dc
fix: 채팅방 관련 버그 수정
JanooGwan Feb 18, 2026
16f34f5
Revert "refactor: 회비 납부 여부 관련 수정, 납부 기한 삭제"
JanooGwan Feb 18, 2026
28b83f2
Revert "docs: Swagger 수정"
JanooGwan Feb 18, 2026
82dbe19
Revert "refactor: 회비 납부 여부 관련 수정, 납부 기한 삭제"
JanooGwan Feb 18, 2026
e427668
hotfix: 회비 기능 관련 커밋 3개 Revert 및 DB 롤백(V27)
JanooGwan Feb 18, 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
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ public interface ClubRecruitmentApi {

@Operation(summary = "동아리 모집 정보를 조회한다.", description = """
동아리의 모집 공고 상세 정보를 조회합니다.

- status는 모집 기간에 따라 BEFORE(모집 전), ONGOING(모집 중), CLOSED(모집 마감)으로 반환됩니다.
- 동아리 멤버이거나 지원 이력이 존재할 경우 isApplied는 true로 반환됩니다.

## 에러
- NOT_FOUND_CLUB (404): 동아리를 찾을 수 없습니다.
- NOT_FOUND_USER (404): 유저를 찾을 수 없습니다.
Expand All @@ -39,7 +39,6 @@ ResponseEntity<ClubRecruitmentResponse> getRecruitments(
요청 값을 기준으로 동아리 모집 공고를 저장합니다.
- 모집 공고가 없으면 생성
- 모집 공고가 있으면 수정

## 에러
- INVALID_RECRUITMENT_DATE_NOT_ALLOWED (400): 상시 모집인 경우 모집 시작일과 마감일을 지정할 수 없습니다.
- INVALID_RECRUITMENT_DATE_REQUIRED (400): 상시 모집이 아닐 경우 모집 시작일과 마감일이 필수입니다.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package gg.agit.konect.domain.club.dto;

import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.NOT_REQUIRED;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import java.time.LocalDate;

import com.fasterxml.jackson.annotation.JsonFormat;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
Expand All @@ -25,8 +27,8 @@ public record ClubFeeInfoReplaceRequest(
@Schema(description = "예금주", example = "BCSD", requiredMode = NOT_REQUIRED)
String accountHolder,

@NotNull(message = "회비 납부 필요 여부는 필수로 입력해야 합니다.")
@Schema(description = "회비 납부 필요 여부", example = "true", requiredMode = REQUIRED)
Boolean isFeeRequired
@Schema(description = "납부 기한", example = "2025.12.31", requiredMode = NOT_REQUIRED)
@JsonFormat(pattern = "yyyy.MM.dd")
LocalDate deadLine
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;

import java.time.LocalDate;

import com.fasterxml.jackson.annotation.JsonFormat;

import gg.agit.konect.domain.club.model.Club;
import io.swagger.v3.oas.annotations.media.Schema;

Expand All @@ -18,16 +22,17 @@ public record ClubFeeInfoResponse(
@Schema(description = "예금주", example = "BCSD", requiredMode = REQUIRED)
String accountHolder,

@Schema(description = "회비 납부 필요 여부", example = "true", requiredMode = REQUIRED)
Boolean isFeeRequired
@Schema(description = "납부 기한", example = "2025.12.31", requiredMode = REQUIRED)
@JsonFormat(pattern = "yyyy.MM.dd")
LocalDate deadLine
) {
public static ClubFeeInfoResponse from(Club club) {
return new ClubFeeInfoResponse(
club.getFeeAmount(),
club.getFeeBank(),
club.getFeeAccountNumber(),
club.getFeeAccountHolder(),
club.getIsFeeRequired()
club.getFeeDeadline()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ public record ClubRecruitmentResponse(
@Schema(description = "모집 공고 이미지 리스트", requiredMode = REQUIRED)
List<InnerRecruitmentImage> images,

@Schema(description = "회비 납부 필요 여부", example = "true", requiredMode = REQUIRED)
Boolean isFeeRequired,

@Schema(description = "지원 여부", example = "false", requiredMode = REQUIRED)
Boolean isApplied
) {
Expand All @@ -60,6 +63,7 @@ public static ClubRecruitmentResponse of(ClubRecruitment recruitment, Boolean is
recruitment.getImages().stream()
.map(InnerRecruitmentImage::from)
.toList(),
recruitment.getIsFeeRequired(),
isApplied
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ public record ClubRecruitmentUpsertRequest(
@Schema(description = "상시 모집 여부", example = "false", requiredMode = REQUIRED)
Boolean isAlwaysRecruiting,

@NotNull(message = "회비 납부 필요 여부는 필수 입력입니다.")
@Schema(description = "회비 납부 필요 여부", example = "true", requiredMode = REQUIRED)
Boolean isFeeRequired,

@NotEmpty(message = "모집 공고 내용은 필수 입력입니다.")
@Schema(description = "모집 공고 내용", example = "BCSD 2025학년도 2학기 신입 부원 모집...", requiredMode = REQUIRED)
String content,
Expand Down
36 changes: 21 additions & 15 deletions src/main/java/gg/agit/konect/domain/club/model/Club.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import static jakarta.persistence.GenerationType.IDENTITY;
import static lombok.AccessLevel.PROTECTED;

import java.time.LocalDate;

import org.springframework.util.StringUtils;

import gg.agit.konect.domain.club.dto.ClubCreateRequest;
Expand Down Expand Up @@ -75,8 +77,8 @@ public class Club extends BaseEntity {
@Column(name = "fee_account_holder", length = 100)
private String feeAccountHolder;

@Column(name = "is_fee_required", columnDefinition = "TINYINT(1)")
private Boolean isFeeRequired;
@Column(name = "fee_deadline")
private LocalDate feeDeadline;

@OneToOne(mappedBy = "club", fetch = LAZY, cascade = ALL, orphanRemoval = true)
private ClubRecruitment clubRecruitment;
Expand All @@ -95,7 +97,7 @@ private Club(
String feeBank,
String feeAccountNumber,
String feeAccountHolder,
Boolean isFeeRequired,
LocalDate feeDeadline,
ClubRecruitment clubRecruitment
) {
this.id = id;
Expand All @@ -110,7 +112,7 @@ private Club(
this.feeBank = feeBank;
this.feeAccountNumber = feeAccountNumber;
this.feeAccountHolder = feeAccountHolder;
this.isFeeRequired = isFeeRequired;
this.feeDeadline = feeDeadline;
this.clubRecruitment = clubRecruitment;
}

Expand All @@ -131,18 +133,18 @@ public void replaceFeeInfo(
String feeBank,
String feeAccountNumber,
String feeAccountHolder,
Boolean isFeeRequired
LocalDate feeDeadline
) {
if (isFeeInfoEmpty(feeAmount, feeBank, feeAccountNumber, feeAccountHolder)) {
if (isFeeInfoEmpty(feeAmount, feeBank, feeAccountNumber, feeAccountHolder, feeDeadline)) {
clearFeeInfo();
return;
}

if (!isFeeInfoComplete(feeAmount, feeBank, feeAccountNumber, feeAccountHolder)) {
if (!isFeeInfoComplete(feeAmount, feeBank, feeAccountNumber, feeAccountHolder, feeDeadline)) {
throw CustomException.of(INVALID_REQUEST_BODY);
}

updateFeeInfo(feeAmount, feeBank, feeAccountNumber, feeAccountHolder, isFeeRequired);
updateFeeInfo(feeAmount, feeBank, feeAccountNumber, feeAccountHolder, feeDeadline);
}

public void updateInfo(String description, String imageUrl, String location, String introduce) {
Expand All @@ -161,45 +163,49 @@ private boolean isFeeInfoEmpty(
Integer feeAmount,
String feeBank,
String feeAccountNumber,
String feeAccountHolder
String feeAccountHolder,
LocalDate feeDeadline
) {
return feeAmount == null
&& feeBank == null
&& feeAccountNumber == null
&& feeAccountHolder == null;
&& feeAccountHolder == null
&& feeDeadline == null;
}

private boolean isFeeInfoComplete(
Integer feeAmount,
String feeBank,
String feeAccountNumber,
String feeAccountHolder
String feeAccountHolder,
LocalDate feeDeadline
) {
return feeAmount != null
&& StringUtils.hasText(feeBank)
&& StringUtils.hasText(feeAccountNumber)
&& StringUtils.hasText(feeAccountHolder);
&& StringUtils.hasText(feeAccountHolder)
&& feeDeadline != null;
}

private void updateFeeInfo(
Integer feeAmount,
String feeBank,
String feeAccountNumber,
String feeAccountHolder,
Boolean isFeeRequired
LocalDate feeDeadline
) {
this.feeAmount = feeAmount;
this.feeBank = feeBank;
this.feeAccountNumber = feeAccountNumber;
this.feeAccountHolder = feeAccountHolder;
this.isFeeRequired = isFeeRequired;
this.feeDeadline = feeDeadline;
}

private void clearFeeInfo() {
this.feeAmount = null;
this.feeBank = null;
this.feeAccountNumber = null;
this.feeAccountHolder = null;
this.isFeeRequired = null;
this.feeDeadline = null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ public class ClubRecruitment extends BaseEntity {
@Column(name = "is_always_recruiting", columnDefinition = "TINYINT(1)")
private Boolean isAlwaysRecruiting;

@Column(name = "is_fee_required", nullable = false, columnDefinition = "TINYINT(1)")
private Boolean isFeeRequired;

@OneToOne(fetch = LAZY)
@JoinColumn(name = "club_id", nullable = false, updatable = false)
private Club club;
Expand All @@ -70,20 +73,23 @@ private ClubRecruitment(
LocalDate endDate,
String content,
Boolean isAlwaysRecruiting,
Boolean isFeeRequired,
Club club
) {
this.id = id;
this.startDate = startDate;
this.endDate = endDate;
this.content = content;
this.isAlwaysRecruiting = isAlwaysRecruiting;
this.isFeeRequired = isFeeRequired;
this.club = club;
}

public static ClubRecruitment of(
LocalDate startDate,
LocalDate endDate,
Boolean isAlwaysRecruiting,
Boolean isFeeRequired,
String content,
Club club
) {
Expand All @@ -100,6 +106,7 @@ public static ClubRecruitment of(
.content(content)
.club(club)
.isAlwaysRecruiting(isAlwaysRecruiting)
.isFeeRequired(isFeeRequired)
.build();
}

Expand Down Expand Up @@ -129,6 +136,7 @@ public void update(
LocalDate startDate,
LocalDate endDate,
Boolean isAlwaysRecruiting,
Boolean isFeeRequired,
String content
) {
if (isAlwaysRecruiting) {
Expand All @@ -141,6 +149,7 @@ public void update(
this.startDate = startDate;
this.endDate = endDate;
this.isAlwaysRecruiting = isAlwaysRecruiting;
this.isFeeRequired = isFeeRequired;
this.content = content;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,11 @@ public ClubFeeInfoResponse applyClub(Integer clubId, Integer userId, ClubApplyRe
}

private void validateFeePaymentImage(Club club, String feePaymentImageUrl) {
if (Boolean.TRUE.equals(club.getIsFeeRequired())
ClubRecruitment recruitment = clubRecruitmentRepository.findByClubId(club.getId())
.orElse(null);

if (recruitment != null
&& Boolean.TRUE.equals(recruitment.getIsFeeRequired())
&& !StringUtils.hasText(feePaymentImageUrl)) {
throw CustomException.of(FEE_PAYMENT_IMAGE_REQUIRED);
}
Expand Down Expand Up @@ -337,7 +341,7 @@ public ClubFeeInfoResponse replaceFeeInfo(Integer clubId, Integer userId, ClubFe
bankName,
request.accountNumber(),
request.accountHolder(),
request.isFeeRequired()
request.deadLine()
);

return ClubFeeInfoResponse.from(club);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public void upsertRecruitment(Integer clubId, Integer userId, ClubRecruitmentUps
request.startDate(),
request.endDate(),
request.isAlwaysRecruiting(),
request.isFeeRequired(),
request.content(),
club
));
Expand All @@ -61,20 +62,14 @@ public void upsertRecruitment(Integer clubId, Integer userId, ClubRecruitmentUps
request.startDate(),
request.endDate(),
request.isAlwaysRecruiting(),
request.isFeeRequired(),
request.content()
);

clubRecruitment.getImages().clear();
}

addImages(clubRecruitment, request.getImageUrls());

if (clubRecruitment.getId() == null) {
clubRecruitmentRepository.save(clubRecruitment);
}
}

private void addImages(ClubRecruitment clubRecruitment, List<String> imageUrls) {
List<String> imageUrls = request.getImageUrls();
for (int index = 0; index < imageUrls.size(); index++) {
ClubRecruitmentImage image = ClubRecruitmentImage.of(
imageUrls.get(index),
Expand All @@ -83,5 +78,9 @@ private void addImages(ClubRecruitment clubRecruitment, List<String> imageUrls)
);
clubRecruitment.addImage(image);
}

if (clubRecruitment.getId() == null) {
clubRecruitmentRepository.save(clubRecruitment);
}
}
}

This file was deleted.

9 changes: 9 additions & 0 deletions src/main/resources/db/migration/V27__add_fee_deadline
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
ALTER TABLE club_recruitment ADD COLUMN is_fee_required TINYINT(1) NULL;

UPDATE club_recruitment cr
INNER JOIN club c ON cr.club_id = c.id
SET cr.is_fee_required = c.is_fee_required;

ALTER TABLE club DROP COLUMN is_fee_required;

ALTER TABLE club ADD COLUMN fee_deadline DATE NULL;
Loading