From b848a8ae0e006d6fc335b7aa15b588f873abfd0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=95=88=ED=9B=88=EA=B8=B0?= Date: Mon, 2 Mar 2026 14:13:07 +0900 Subject: [PATCH 1/2] =?UTF-8?q?=20=E2=9C=A8=20Feat:=20MatchStatus=20?= =?UTF-8?q?=ED=99=95=EC=9E=A5=20=EB=B0=8F=20Admin=20=EB=A7=A4=EC=B9=AD=20?= =?UTF-8?q?=EC=B7=A8=EC=86=8C=20API=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/admin/controller/AdminController.java | 9 +++++++++ .../domain/admin/service/AdminService.java | 2 ++ .../domain/admin/service/AdminServiceImpl.java | 6 ++++++ .../sportizebe/domain/match/entity/MatchRoom.java | 4 ++++ .../domain/match/entity/MatchStatus.java | 8 +++++--- .../domain/match/exception/MatchErrorCode.java | 6 ++++++ .../domain/match/service/MatchService.java | 2 ++ .../domain/match/service/MatchServiceImpl.java | 15 +++++++++++++++ 8 files changed, 49 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/be/sportizebe/domain/admin/controller/AdminController.java b/src/main/java/com/be/sportizebe/domain/admin/controller/AdminController.java index 8f34b0f..2b56553 100644 --- a/src/main/java/com/be/sportizebe/domain/admin/controller/AdminController.java +++ b/src/main/java/com/be/sportizebe/domain/admin/controller/AdminController.java @@ -66,6 +66,15 @@ public ResponseEntity> createMatch( .body(BaseResponse.success("매칭 생성 성공", response)); } + @Operation(summary = "매칭 취소 (관리자 전용)", description = "매칭을 취소 상태로 변경합니다. 이미 시작/종료된 매칭은 취소할 수 없습니다.") + @PatchMapping("/matches/{matchId}/cancel") + public ResponseEntity> cancelMatch( + @PathVariable Long matchId + ) { + adminService.cancelMatch(matchId); + return ResponseEntity.ok(BaseResponse.success("매칭 취소 성공", null)); + } + @Operation(summary = "매칭 삭제 (관리자 전용)", description = "매칭을 강제 삭제합니다.") @DeleteMapping("/matches/{matchId}") public ResponseEntity> deleteMatch( diff --git a/src/main/java/com/be/sportizebe/domain/admin/service/AdminService.java b/src/main/java/com/be/sportizebe/domain/admin/service/AdminService.java index 39d048c..482284c 100644 --- a/src/main/java/com/be/sportizebe/domain/admin/service/AdminService.java +++ b/src/main/java/com/be/sportizebe/domain/admin/service/AdminService.java @@ -16,5 +16,7 @@ public interface AdminService { MatchResponse createMatch(Long adminId, MatchCreateRequest request); // 매칭 생성 + void cancelMatch(Long matchId); // 매칭 취소 + void deleteMatch(Long matchId); // 매칭 삭제 } diff --git a/src/main/java/com/be/sportizebe/domain/admin/service/AdminServiceImpl.java b/src/main/java/com/be/sportizebe/domain/admin/service/AdminServiceImpl.java index 3b5eaaf..280ec51 100644 --- a/src/main/java/com/be/sportizebe/domain/admin/service/AdminServiceImpl.java +++ b/src/main/java/com/be/sportizebe/domain/admin/service/AdminServiceImpl.java @@ -43,6 +43,12 @@ public MatchResponse createMatch(Long adminId, MatchCreateRequest request) { return matchService.createMatch(adminId, request); } + @Override + @Transactional + public void cancelMatch(Long matchId) { + matchService.cancelMatch(matchId); + } + @Override @Transactional public void deleteMatch(Long matchId) { diff --git a/src/main/java/com/be/sportizebe/domain/match/entity/MatchRoom.java b/src/main/java/com/be/sportizebe/domain/match/entity/MatchRoom.java index 142afd4..987017a 100644 --- a/src/main/java/com/be/sportizebe/domain/match/entity/MatchRoom.java +++ b/src/main/java/com/be/sportizebe/domain/match/entity/MatchRoom.java @@ -79,5 +79,9 @@ public void leave() { if (this.status == MatchStatus.FULL) this.status = MatchStatus.OPEN; } + public void cancel() { + this.status = MatchStatus.CANCELLED; + } + } \ No newline at end of file diff --git a/src/main/java/com/be/sportizebe/domain/match/entity/MatchStatus.java b/src/main/java/com/be/sportizebe/domain/match/entity/MatchStatus.java index 794cace..2a50bdf 100644 --- a/src/main/java/com/be/sportizebe/domain/match/entity/MatchStatus.java +++ b/src/main/java/com/be/sportizebe/domain/match/entity/MatchStatus.java @@ -1,7 +1,9 @@ package com.be.sportizebe.domain.match.entity; public enum MatchStatus { - OPEN, // 참여 가능 - FULL, // 정원 마감 - CLOSED // 운영상 종료(옵션) + OPEN, // 참여 가능 + FULL, // 정원 마감 + CLOSED, // 매칭 시작됨 (scheduledAt 이후, 참여 불가) -> "지금 진행중인 매칭" 탭 보여줄 때 + COMPLETED, // 매칭 종료 (scheduledAt + durationMinutes 이후) -> "매칭 완료 후 리뷰/평점. 포인트 지금 등 사이드 이펙트 필요 시COM + CANCELLED // Admin 취소 } diff --git a/src/main/java/com/be/sportizebe/domain/match/exception/MatchErrorCode.java b/src/main/java/com/be/sportizebe/domain/match/exception/MatchErrorCode.java index d02e750..74b13d1 100644 --- a/src/main/java/com/be/sportizebe/domain/match/exception/MatchErrorCode.java +++ b/src/main/java/com/be/sportizebe/domain/match/exception/MatchErrorCode.java @@ -29,6 +29,12 @@ public enum MatchErrorCode implements BaseErrorCode { HttpStatus.BAD_REQUEST, "MATCH_400_NOT_JOINED", "해당 매칭에 참가 중이지 않습니다." + ), + + MATCH_CANNOT_CANCEL( + HttpStatus.BAD_REQUEST, + "MATCH_400_CANNOT_CANCEL", + "이미 취소되었거나 시작/종료된 매칭은 취소할 수 없습니다." ); private final HttpStatus status; diff --git a/src/main/java/com/be/sportizebe/domain/match/service/MatchService.java b/src/main/java/com/be/sportizebe/domain/match/service/MatchService.java index c225293..388d3a0 100644 --- a/src/main/java/com/be/sportizebe/domain/match/service/MatchService.java +++ b/src/main/java/com/be/sportizebe/domain/match/service/MatchService.java @@ -21,6 +21,8 @@ public interface MatchService { List getNearMatches(MatchNearRequest request); // 내 주변 매칭 목록 조회 + void cancelMatch(Long matchId); // 매칭 취소 (관리자 전용) + void deleteMatch(Long matchId); // 매칭 삭제 (관리자 전용) } diff --git a/src/main/java/com/be/sportizebe/domain/match/service/MatchServiceImpl.java b/src/main/java/com/be/sportizebe/domain/match/service/MatchServiceImpl.java index 721c39e..81c13b3 100644 --- a/src/main/java/com/be/sportizebe/domain/match/service/MatchServiceImpl.java +++ b/src/main/java/com/be/sportizebe/domain/match/service/MatchServiceImpl.java @@ -7,6 +7,7 @@ import com.be.sportizebe.domain.match.entity.MatchParticipant; import com.be.sportizebe.domain.match.entity.MatchParticipantStatus; import com.be.sportizebe.domain.match.entity.MatchRoom; +import com.be.sportizebe.domain.match.entity.MatchStatus; import com.be.sportizebe.domain.match.exception.MatchErrorCode; import com.be.sportizebe.domain.match.repository.MatchParticipantRepository; import com.be.sportizebe.domain.match.repository.MatchRoomRepository; @@ -126,6 +127,20 @@ public MatchDetailResponse getMatchDetail(Long matchId, Long userId) { return MatchDetailResponse.of(matchRoom, user); } + @Override + public void cancelMatch(Long matchId) { + MatchRoom matchRoom = matchRoomRepository.findById(matchId) + .orElseThrow(() -> new CustomException(MatchErrorCode.MATCH_NOT_FOUND)); + + if (matchRoom.getStatus() == MatchStatus.CANCELLED + || matchRoom.getStatus() == MatchStatus.CLOSED + || matchRoom.getStatus() == MatchStatus.COMPLETED) { + throw new CustomException(MatchErrorCode.MATCH_CANNOT_CANCEL); + } + + matchRoom.cancel(); + } + @Override public void deleteMatch(Long matchId) { if (!matchRoomRepository.existsById(matchId)) { From 454fce5cc77b361b11f374c682386bf568d6bffb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=95=88=ED=9B=88=EA=B8=B0?= Date: Mon, 2 Mar 2026 17:25:21 +0900 Subject: [PATCH 2/2] =?UTF-8?q?=E2=9C=A8=20Feat:=20SportsFacility=20?= =?UTF-8?q?=EA=B5=AC=EC=9E=A5=EC=A0=95=EB=B3=B4=20=ED=95=84=EB=93=9C=20?= =?UTF-8?q?=EB=B0=8F=20MatchRoom=20=EB=A7=A4=EC=B9=AD=20=EC=A0=95=EB=B3=B4?= =?UTF-8?q?=20=ED=95=84=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/request/FacilityCreateRequest.java | 24 ++++++++++++- .../dto/request/FacilityUpdateRequest.java | 24 ++++++++++++- .../dto/response/FacilityResponse.java | 24 ++++++++++++- .../domain/facility/entity/ParkingType.java | 7 ++++ .../facility/entity/SportsFacility.java | 35 ++++++++++++++++++- .../facility/mapper/FacilityMapper.java | 9 ++++- .../service/SportsFacilityServiceImpl.java | 18 ++++++++++ .../match/dto/request/MatchCreateRequest.java | 13 ++++++- .../dto/response/MatchDetailResponse.java | 17 +++++++-- .../domain/match/entity/MatchRoom.java | 21 +++++++++-- .../domain/match/entity/UniformPolicy.java | 6 ++++ 11 files changed, 188 insertions(+), 10 deletions(-) create mode 100644 src/main/java/com/be/sportizebe/domain/facility/entity/ParkingType.java create mode 100644 src/main/java/com/be/sportizebe/domain/match/entity/UniformPolicy.java diff --git a/src/main/java/com/be/sportizebe/domain/facility/dto/request/FacilityCreateRequest.java b/src/main/java/com/be/sportizebe/domain/facility/dto/request/FacilityCreateRequest.java index b280f9c..97d12b4 100644 --- a/src/main/java/com/be/sportizebe/domain/facility/dto/request/FacilityCreateRequest.java +++ b/src/main/java/com/be/sportizebe/domain/facility/dto/request/FacilityCreateRequest.java @@ -1,6 +1,7 @@ package com.be.sportizebe.domain.facility.dto.request; import com.be.sportizebe.domain.facility.entity.FacilityType; +import com.be.sportizebe.domain.facility.entity.ParkingType; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; @@ -24,7 +25,28 @@ public record FacilityCreateRequest( @Schema(description = "시설 종목 타입", example = "SOCCER") @NotNull - FacilityType facilityType + FacilityType facilityType, + + @Schema(description = "화장실 유무", example = "true") + boolean hasToilet, + + @Schema(description = "자판기 유무", example = "false") + boolean hasVendingMachine, + + @Schema(description = "샤워실 유무", example = "true") + boolean hasShower, + + @Schema(description = "주차 유형 (NONE/FREE/PAID)", example = "FREE") + ParkingType parkingType, + + @Schema(description = "구장 가로 크기 (m)", example = "40") + Integer widthMeter, + + @Schema(description = "구장 세로 크기 (m)", example = "20") + Integer heightMeter, + + @Schema(description = "휠체어 접근 가능 여부", example = "true") + boolean wheelchairAccessible ) { } \ No newline at end of file diff --git a/src/main/java/com/be/sportizebe/domain/facility/dto/request/FacilityUpdateRequest.java b/src/main/java/com/be/sportizebe/domain/facility/dto/request/FacilityUpdateRequest.java index 56fd4ee..9970577 100644 --- a/src/main/java/com/be/sportizebe/domain/facility/dto/request/FacilityUpdateRequest.java +++ b/src/main/java/com/be/sportizebe/domain/facility/dto/request/FacilityUpdateRequest.java @@ -1,6 +1,7 @@ package com.be.sportizebe.domain.facility.dto.request; import com.be.sportizebe.domain.facility.entity.FacilityType; +import com.be.sportizebe.domain.facility.entity.ParkingType; import io.swagger.v3.oas.annotations.media.Schema; @Schema(description = "체육시설 수정 요청 (null 필드는 수정하지 않음)") @@ -19,6 +20,27 @@ public record FacilityUpdateRequest( String thumbnailUrl, @Schema(description = "시설 종목 타입", example = "SOCCER") - FacilityType facilityType + FacilityType facilityType, + + @Schema(description = "화장실 유무", example = "true") + Boolean hasToilet, + + @Schema(description = "자판기 유무", example = "false") + Boolean hasVendingMachine, + + @Schema(description = "샤워실 유무", example = "true") + Boolean hasShower, + + @Schema(description = "주차 유형 (NONE/FREE/PAID)", example = "FREE") + ParkingType parkingType, + + @Schema(description = "구장 가로 크기 (m)", example = "40") + Integer widthMeter, + + @Schema(description = "구장 세로 크기 (m)", example = "20") + Integer heightMeter, + + @Schema(description = "휠체어 접근 가능 여부", example = "true") + Boolean wheelchairAccessible ) {} diff --git a/src/main/java/com/be/sportizebe/domain/facility/dto/response/FacilityResponse.java b/src/main/java/com/be/sportizebe/domain/facility/dto/response/FacilityResponse.java index d3f538f..aa9750b 100644 --- a/src/main/java/com/be/sportizebe/domain/facility/dto/response/FacilityResponse.java +++ b/src/main/java/com/be/sportizebe/domain/facility/dto/response/FacilityResponse.java @@ -1,6 +1,7 @@ package com.be.sportizebe.domain.facility.dto.response; import com.be.sportizebe.domain.facility.entity.FacilityType; +import com.be.sportizebe.domain.facility.entity.ParkingType; import io.swagger.v3.oas.annotations.media.Schema; @Schema(description = "체육시설 단건 조회 응답") @@ -28,7 +29,28 @@ public record FacilityResponse( double lat, @Schema(description = "경도", example = "126.982") - double lng + double lng, + + @Schema(description = "화장실 유무", example = "true") + boolean hasToilet, + + @Schema(description = "자판기 유무", example = "false") + boolean hasVendingMachine, + + @Schema(description = "샤워실 유무", example = "true") + boolean hasShower, + + @Schema(description = "주차 유형 (NONE/FREE/PAID)", example = "FREE") + ParkingType parkingType, + + @Schema(description = "구장 가로 크기 (m)", example = "40") + Integer widthMeter, + + @Schema(description = "구장 세로 크기 (m)", example = "20") + Integer heightMeter, + + @Schema(description = "휠체어 접근 가능 여부", example = "true") + boolean wheelchairAccessible ) { } \ No newline at end of file diff --git a/src/main/java/com/be/sportizebe/domain/facility/entity/ParkingType.java b/src/main/java/com/be/sportizebe/domain/facility/entity/ParkingType.java new file mode 100644 index 0000000..c32329e --- /dev/null +++ b/src/main/java/com/be/sportizebe/domain/facility/entity/ParkingType.java @@ -0,0 +1,7 @@ +package com.be.sportizebe.domain.facility.entity; + +public enum ParkingType { + NONE, // 주차장 없음 + FREE, // 무료 주차 + PAID // 유료 주차 +} diff --git a/src/main/java/com/be/sportizebe/domain/facility/entity/SportsFacility.java b/src/main/java/com/be/sportizebe/domain/facility/entity/SportsFacility.java index 69e2d76..d3159f5 100644 --- a/src/main/java/com/be/sportizebe/domain/facility/entity/SportsFacility.java +++ b/src/main/java/com/be/sportizebe/domain/facility/entity/SportsFacility.java @@ -25,7 +25,7 @@ public class SportsFacility extends BaseTimeEntity { @Column(columnDefinition = "text") private String introduce; - // 리소스 부담 생각해서 일단 썸네일 이미지 1장으로만 구현하는 방식 + // 리소스 부담 생각해서 일단 썸네일 이미지 1/치장으로만 구현하는 방식 private String thumbnailUrl; @Enumerated(EnumType.STRING) @@ -35,6 +35,27 @@ public class SportsFacility extends BaseTimeEntity { @Column(columnDefinition = "geography(Point, 4326)", nullable = false) private Point location; + // 편의시설 + @Column(nullable = false) + private boolean hasToilet; + + @Column(nullable = false) + private boolean hasVendingMachine; + + @Column(nullable = false) + private boolean hasShower; + + @Enumerated(EnumType.STRING) + @Column(nullable = false, length = 10) + private ParkingType parkingType; + + // 구장 크기 (미터) + private Integer widthMeter; + private Integer heightMeter; + + @Column(nullable = false) + private boolean wheelchairAccessible; + // 변경 메서드(Dirty Checking용) public void changeInfo(String facilityName, String introduce, String thumbnailUrl, FacilityType facilityType) { if (facilityName != null) this.facilityName = facilityName; @@ -43,6 +64,18 @@ public void changeInfo(String facilityName, String introduce, String thumbnailUr if (facilityType != null) this.facilityType = facilityType; } + public void changeAmenity(Boolean hasToilet, Boolean hasVendingMachine, Boolean hasShower, + ParkingType parkingType, Integer widthMeter, Integer heightMeter, + Boolean wheelchairAccessible) { + if (hasToilet != null) this.hasToilet = hasToilet; + if (hasVendingMachine != null) this.hasVendingMachine = hasVendingMachine; + if (hasShower != null) this.hasShower = hasShower; + if (parkingType != null) this.parkingType = parkingType; + if (widthMeter != null) this.widthMeter = widthMeter; + if (heightMeter != null) this.heightMeter = heightMeter; + if (wheelchairAccessible != null) this.wheelchairAccessible = wheelchairAccessible; + } + public void changeAddress(String address) { this.address = address; } diff --git a/src/main/java/com/be/sportizebe/domain/facility/mapper/FacilityMapper.java b/src/main/java/com/be/sportizebe/domain/facility/mapper/FacilityMapper.java index f996a18..a46be39 100644 --- a/src/main/java/com/be/sportizebe/domain/facility/mapper/FacilityMapper.java +++ b/src/main/java/com/be/sportizebe/domain/facility/mapper/FacilityMapper.java @@ -42,7 +42,14 @@ static FacilityResponse toFacilityResponse(SportsFacility sf) { sf.getThumbnailUrl(), sf.getFacilityType(), lat, - lng + lng, + sf.isHasToilet(), + sf.isHasVendingMachine(), + sf.isHasShower(), + sf.getParkingType(), + sf.getWidthMeter(), + sf.getHeightMeter(), + sf.isWheelchairAccessible() ); } } diff --git a/src/main/java/com/be/sportizebe/domain/facility/service/SportsFacilityServiceImpl.java b/src/main/java/com/be/sportizebe/domain/facility/service/SportsFacilityServiceImpl.java index 046238e..5251737 100644 --- a/src/main/java/com/be/sportizebe/domain/facility/service/SportsFacilityServiceImpl.java +++ b/src/main/java/com/be/sportizebe/domain/facility/service/SportsFacilityServiceImpl.java @@ -7,6 +7,7 @@ import com.be.sportizebe.domain.facility.dto.response.FacilityMarkerResponse; import com.be.sportizebe.domain.facility.dto.response.FacilityNearResponse; import com.be.sportizebe.domain.facility.dto.response.FacilityResponse; +import com.be.sportizebe.domain.facility.entity.ParkingType; import com.be.sportizebe.domain.facility.entity.SportsFacility; import com.be.sportizebe.domain.facility.mapper.FacilityMapper; import com.be.sportizebe.domain.facility.repository.SportsFacilityRepository; @@ -81,6 +82,13 @@ public FacilityResponse create(FacilityCreateRequest request) { .thumbnailUrl(request.thumbnailUrl()) .facilityType(request.facilityType()) .location(point) + .hasToilet(request.hasToilet()) + .hasVendingMachine(request.hasVendingMachine()) + .hasShower(request.hasShower()) + .parkingType(request.parkingType() != null ? request.parkingType() : ParkingType.NONE) + .widthMeter(request.widthMeter()) + .heightMeter(request.heightMeter()) + .wheelchairAccessible(request.wheelchairAccessible()) .build(); SportsFacility saved = sportsFacilityRepository.save(facility); @@ -106,6 +114,16 @@ public FacilityResponse update(Long facilityId, FacilityUpdateRequest request) { request.facilityType() ); + facility.changeAmenity( + request.hasToilet(), + request.hasVendingMachine(), + request.hasShower(), + request.parkingType(), + request.widthMeter(), + request.heightMeter(), + request.wheelchairAccessible() + ); + return FacilityMapper.toFacilityResponse(facility); } diff --git a/src/main/java/com/be/sportizebe/domain/match/dto/request/MatchCreateRequest.java b/src/main/java/com/be/sportizebe/domain/match/dto/request/MatchCreateRequest.java index 69a720b..d653003 100644 --- a/src/main/java/com/be/sportizebe/domain/match/dto/request/MatchCreateRequest.java +++ b/src/main/java/com/be/sportizebe/domain/match/dto/request/MatchCreateRequest.java @@ -1,6 +1,7 @@ package com.be.sportizebe.domain.match.dto.request; import com.be.sportizebe.common.enums.SportType; +import com.be.sportizebe.domain.match.entity.UniformPolicy; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.Future; import jakarta.validation.constraints.Max; @@ -32,6 +33,16 @@ public record MatchCreateRequest( @Schema(description = "매칭 시작 일시", example = "2026-03-07T14:00:00") @NotNull(message = "매칭 시작 일시는 필수입니다.") @Future(message = "매칭 시작 일시는 현재 시간 이후여야 합니다.") - LocalDateTime scheduledAt + LocalDateTime scheduledAt, + + @Schema(description = "유니폼 정책 (BRING_OWN: 흰/검 지참, VEST_PROVIDED: 조끼 제공)", example = "BRING_OWN") + UniformPolicy uniformPolicy, + + @Schema(description = "몇 파전 (미입력 시 2파전)", example = "2") + @Min(value = 2, message = "파전 수는 2 이상이어야 합니다.") + Integer numberOfTeams, + + @Schema(description = "남/녀 혼성 허용 여부", example = "false") + boolean mixedGender ) {} \ No newline at end of file diff --git a/src/main/java/com/be/sportizebe/domain/match/dto/response/MatchDetailResponse.java b/src/main/java/com/be/sportizebe/domain/match/dto/response/MatchDetailResponse.java index cb50bf9..8f3969a 100644 --- a/src/main/java/com/be/sportizebe/domain/match/dto/response/MatchDetailResponse.java +++ b/src/main/java/com/be/sportizebe/domain/match/dto/response/MatchDetailResponse.java @@ -2,6 +2,7 @@ import com.be.sportizebe.domain.match.entity.MatchParticipantStatus; import com.be.sportizebe.domain.match.entity.MatchRoom; +import com.be.sportizebe.domain.match.entity.UniformPolicy; import com.be.sportizebe.common.enums.SportType; import com.be.sportizebe.domain.user.entity.User; import io.swagger.v3.oas.annotations.media.Schema; @@ -34,7 +35,16 @@ public record MatchDetailResponse( boolean joined, @Schema(description = "매칭 시작 일시", example = "2026-03-07T14:00:00") - LocalDateTime scheduledAt + LocalDateTime scheduledAt, + + @Schema(description = "유니폼 정책 (BRING_OWN: 흰/검 지참, VEST_PROVIDED: 조끼 제공)", example = "BRING_OWN") + UniformPolicy uniformPolicy, + + @Schema(description = "몇 파전", example = "2") + int numberOfTeams, + + @Schema(description = "남/녀 혼성 허용 여부", example = "false") + boolean mixedGender ) { public static MatchDetailResponse of( @@ -58,7 +68,10 @@ public static MatchDetailResponse of( participantIds.size(), participantIds, joined, - matchRoom.getScheduledAt() + matchRoom.getScheduledAt(), + matchRoom.getUniformPolicy(), + matchRoom.getNumberOfTeams(), + matchRoom.isMixedGender() ); } } \ No newline at end of file diff --git a/src/main/java/com/be/sportizebe/domain/match/entity/MatchRoom.java b/src/main/java/com/be/sportizebe/domain/match/entity/MatchRoom.java index 987017a..8b716a0 100644 --- a/src/main/java/com/be/sportizebe/domain/match/entity/MatchRoom.java +++ b/src/main/java/com/be/sportizebe/domain/match/entity/MatchRoom.java @@ -49,6 +49,16 @@ public class MatchRoom extends BaseTimeEntity { @Column(nullable = false) private LocalDateTime scheduledAt; // 매칭 시작 일시 + @Enumerated(EnumType.STRING) + @Column(length = 20) + private UniformPolicy uniformPolicy; // 흰/검 지참 or 조끼 제공 + + @Column(nullable = false) + @Builder.Default + private int numberOfTeams = 2; // 몇 파전 (default: 2파전) + + @Column(nullable = false) + private boolean mixedGender; // 남/녀 혼성 허용 여부 @OneToMany(mappedBy = "matchRoom", cascade = CascadeType.ALL, orphanRemoval = true) @Builder.Default @@ -59,7 +69,7 @@ public boolean isFull() { } public static MatchRoom create(MatchCreateRequest request) { - return MatchRoom.builder() + MatchRoom.MatchRoomBuilder builder = MatchRoom.builder() .sportsName(request.sportsName()) .facilityId(request.facilityId()) .curMembers(0) @@ -68,7 +78,14 @@ public static MatchRoom create(MatchCreateRequest request) { .durationMinutes(request.durationMinutes()) .entryFee(request.entryFee()) .scheduledAt(request.scheduledAt()) - .build(); + .uniformPolicy(request.uniformPolicy()) + .mixedGender(request.mixedGender()); + + if (request.numberOfTeams() != null) { + builder.numberOfTeams(request.numberOfTeams()); + } + + return builder.build(); } public void join() { this.curMembers++; diff --git a/src/main/java/com/be/sportizebe/domain/match/entity/UniformPolicy.java b/src/main/java/com/be/sportizebe/domain/match/entity/UniformPolicy.java new file mode 100644 index 0000000..abf8c3a --- /dev/null +++ b/src/main/java/com/be/sportizebe/domain/match/entity/UniformPolicy.java @@ -0,0 +1,6 @@ +package com.be.sportizebe.domain.match.entity; + +public enum UniformPolicy { + BRING_OWN, // 흰/검은 옷 지참 필요 + VEST_PROVIDED // 구장 내 조끼 제공 +}