Skip to content

[Feat] Admin 매칭 취소 API 추가 및 구장·매칭 상세 정보 필드 확장#62

Merged
angoroa merged 2 commits intodevelopfrom
feat/facility-info
Mar 2, 2026
Merged

[Feat] Admin 매칭 취소 API 추가 및 구장·매칭 상세 정보 필드 확장#62
angoroa merged 2 commits intodevelopfrom
feat/facility-info

Conversation

@angoroa
Copy link
Copy Markdown
Member

@angoroa angoroa commented Mar 2, 2026

#️⃣ Issue Number

  • closed #

📝 요약(Summary)

  • Admin 매칭 취소 기능 추가
  • SportsFacility 엔티티에 편의시설 관련 필드 추가 (화장실/자판기/샤워실/주차/구장크기/휠체어)
  • MatchRoom 엔티티에 매칭 정보 필드 추가 (유니폼 정책/파전 수/혼성 여부)
  • 신규 enum ParkingType, UniformPolicy 생성
  • 관련 Request/Response DTO 및 Service 레이어 전체 반영

🛠️ PR 유형

어떤 변경 사항이 있나요?

  • 새로운 기능 추가
  • 버그 수정
  • CSS 등 사용자 UI 디자인 변경
  • 코드에 영향을 주지 않는 변경사항(오타 수정, 탭 사이즈 변경, 변수명 변경)
  • 코드 리팩토링
  • 주석 추가 및 수정
  • 문서 수정
  • 테스트 추가, 테스트 리팩토링
  • 빌드 부분 혹은 패키지 매니저 수정
  • 파일 혹은 폴더명 수정
  • 파일 혹은 폴더 삭제

📸스크린샷 (선택)

💬 공유사항 to 리뷰어

✅ PR Checklist

PR이 다음 요구 사항을 충족하는지 확인하세요.

  • 커밋 메시지 컨벤션에 맞게 작성했습니다.
  • 변경 사항에 대한 테스트를 했습니다.(버그 수정/기능에 대한 테스트).

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능
    • 매칭 취소 기능 추가: 관리자가 진행 중인 매칭을 취소할 수 있습니다.
    • 시설 정보 개선: 화장실, 자판기, 샤워실 등 편의시설과 주차 유형, 휠체어 접근성 정보가 추가됩니다.
    • 매칭 생성 옵션 확대: 유니폼 정책, 팀 수, 혼성 여부를 지정할 수 있습니다.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 2, 2026

Walkthrough

관리자의 경기 취소 기능과 함께 경기 도메인에 상태(CLOSED, COMPLETED, CANCELLED) 및 정책(UniformPolicy) 관련 필드를 추가하고, 시설 도메인에 편의시설 및 주차 정보 필드를 확장했습니다.

Changes

Cohort / File(s) Summary
Admin Domain - Match Cancellation
src/main/java/com/be/sportizebe/domain/admin/controller/AdminController.java, src/main/java/com/be/sportizebe/domain/admin/service/AdminService.java, src/main/java/com/be/sportizebe/domain/admin/service/AdminServiceImpl.java
관리자 전용 경기 취소 엔드포인트(PATCH /api/admin/matches/{matchId}/cancel) 추가 및 관련 서비스 메서드 구현
Match Domain - Status and Policy
src/main/java/com/be/sportizebe/domain/match/entity/MatchStatus.java, src/main/java/com/be/sportizebe/domain/match/entity/UniformPolicy.java, src/main/java/com/be/sportizebe/domain/match/entity/MatchRoom.java
경기 상태에 CLOSED, COMPLETED, CANCELLED 추가 및 UniformPolicy 열거형 도입, MatchRoom에 uniformPolicy, numberOfTeams, mixedGender 필드 및 cancel() 메서드 추가
Match Domain - DTOs and Requests
src/main/java/com/be/sportizebe/domain/match/dto/request/MatchCreateRequest.java, src/main/java/com/be/sportizebe/domain/match/dto/response/MatchDetailResponse.java
MatchCreateRequest와 MatchDetailResponse에 uniformPolicy, numberOfTeams, mixedGender 필드 추가
Match Domain - Service Layer
src/main/java/com/be/sportizebe/domain/match/service/MatchService.java, src/main/java/com/be/sportizebe/domain/match/service/MatchServiceImpl.java, src/main/java/com/be/sportizebe/domain/match/exception/MatchErrorCode.java
cancelMatch() 메서드 추가 및 MATCH_CANNOT_CANCEL 에러 코드 정의
Facility Domain - Parking Type
src/main/java/com/be/sportizebe/domain/facility/entity/ParkingType.java
주차 유형을 나타내는 ParkingType 열거형(NONE, FREE, PAID) 신규 추가
Facility Domain - Entity and Amenities
src/main/java/com/be/sportizebe/domain/facility/entity/SportsFacility.java
편의시설 필드(hasToilet, hasVendingMachine, hasShower, wheelchairAccessible) 및 주차/크기 정보(parkingType, widthMeter, heightMeter) 추가, changeAmenity() 메서드 구현
Facility Domain - DTOs and Mapping
src/main/java/com/be/sportizebe/domain/facility/dto/request/FacilityCreateRequest.java, src/main/java/com/be/sportizebe/domain/facility/dto/request/FacilityUpdateRequest.java, src/main/java/com/be/sportizebe/domain/facility/dto/response/FacilityResponse.java, src/main/java/com/be/sportizebe/domain/facility/mapper/FacilityMapper.java
FacilityCreateRequest, FacilityUpdateRequest, FacilityResponse에 편의시설 및 주차 관련 필드 추가, FacilityMapper 업데이트
Facility Domain - Service
src/main/java/com/be/sportizebe/domain/facility/service/SportsFacilityServiceImpl.java
시설 생성 및 업데이트 시 새로운 편의시설 필드 처리 로직 추가

Sequence Diagram

sequenceDiagram
    participant Client
    participant AdminController
    participant AdminService
    participant MatchService
    participant MatchRoom as MatchRoom<br/>(Entity)
    participant Database

    Client->>AdminController: PATCH /api/admin/matches/{matchId}/cancel
    AdminController->>AdminService: cancelMatch(matchId)
    AdminService->>MatchService: cancelMatch(matchId)
    MatchService->>Database: findById(matchId)
    Database-->>MatchService: MatchRoom
    MatchService->>MatchRoom: cancel()
    MatchRoom->>MatchRoom: status = CANCELLED
    MatchService->>Database: save(MatchRoom)
    Database-->>MatchService: success
    MatchService-->>AdminService: void
    AdminService-->>AdminController: void
    AdminController-->>Client: 200 OK (success response)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • imjuyongp

Poem

🐰 경기는 미루거나 취소하고,
시설에 편의를 더 채우며,
관리자의 손길이 닿으니
정책도 선택하고 상태도 밝혀,
스포츠의 길이 한층 넓어지네! ⚽✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.93% 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
Title check ✅ Passed PR 제목이 변경사항의 주요 내용을 명확하게 요약하고 있습니다. 관리자 매칭 취소 API 추가와 구장·매칭 상세 정보 필드 확장이라는 두 가지 핵심 변경사항을 정확히 반영하고 있습니다.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/facility-info

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
Copy Markdown

@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: 6

🧹 Nitpick comments (1)
src/main/java/com/be/sportizebe/domain/facility/entity/SportsFacility.java (1)

67-76: 구장 크기 필드에 도메인 유효성 검증을 넣는 것을 권장합니다.

Line 74~75는 음수/0 값도 그대로 반영됩니다. 잘못된 시설 데이터 저장을 막기 위해 최소값 검증을 추가하는 편이 안전합니다.

제안 diff
 public void changeAmenity(Boolean hasToilet, Boolean hasVendingMachine, Boolean hasShower,
                           ParkingType parkingType, Integer widthMeter, Integer heightMeter,
                           Boolean wheelchairAccessible) {
+    if (widthMeter != null && widthMeter <= 0) {
+        throw new IllegalArgumentException("widthMeter must be greater than 0");
+    }
+    if (heightMeter != null && heightMeter <= 0) {
+        throw new IllegalArgumentException("heightMeter must be greater than 0");
+    }
+
     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;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/be/sportizebe/domain/facility/entity/SportsFacility.java`
around lines 67 - 76, The changeAmenity method currently assigns widthMeter and
heightMeter even when zero or negative; update SportsFacility.changeAmenity to
validate these two parameters (widthMeter and heightMeter) when non-null and
require they are > 0 before assigning; if a provided value is <= 0, reject it by
throwing an IllegalArgumentException (with a clear message mentioning
widthMeter/heightMeter) or otherwise handle according to domain rules, and keep
existing null checks for other fields (hasToilet, hasVendingMachine, hasShower,
parkingType, wheelchairAccessible).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/main/java/com/be/sportizebe/domain/facility/dto/request/FacilityCreateRequest.java`:
- Around line 42-47: Add strict positive-range validation to the facility
dimension fields in FacilityCreateRequest so negative or zero sizes cannot be
submitted: annotate the Integer fields widthMeter and heightMeter with a
bean-validation constraint such as `@Min`(1) or `@Positive` and update imports
(javax/ jakarta.validation.constraints.*) accordingly, and ensure any existing
validation groups/DTO usage will trigger validation on create requests so
invalid payloads return 400.

In
`@src/main/java/com/be/sportizebe/domain/facility/dto/request/FacilityUpdateRequest.java`:
- Around line 37-41: The DTO FacilityUpdateRequest allows widthMeter and
heightMeter to be zero or negative; add bean validation to enforce positive
dimensions by annotating the Integer fields widthMeter and heightMeter with an
appropriate constraint such as `@Min`(1) or `@Positive` (and import
javax.validation.constraints.*), and ensure the controller uses `@Valid` on the
request parameter so invalid values are rejected before persistence.

In `@src/main/java/com/be/sportizebe/domain/facility/entity/SportsFacility.java`:
- Around line 39-57: The new NOT NULL fields in SportsFacility (hasToilet,
hasVendingMachine, hasShower, wheelchairAccessible, parkingType) need default
values or a backfill migration to avoid schema apply failures for existing rows;
either add explicit column defaults on the entity (e.g., `@Column`(nullable =
false, columnDefinition="boolean default false") or `@ColumnDefault`("false") for
the four booleans and a sensible default string for parkingType) and ensure the
Java fields have matching initial values, or create a proper migration
(Liquibase/Flyway) that adds the columns with DEFAULT clauses and performs an
UPDATE backfill before dropping defaults — update the SportsFacility class
fields and/or add the migration so schema changes are safe for preexisting data.

In
`@src/main/java/com/be/sportizebe/domain/match/dto/request/MatchCreateRequest.java`:
- Around line 45-46: The mixedGender field in MatchCreateRequest is a primitive
boolean so missing request values silently default to false; change its type
from primitive boolean to the wrapper Boolean (field name mixedGender in class
MatchCreateRequest) and, if the field is required, annotate it with `@NotNull`
(and update imports) so you can distinguish absent values from an explicit
false; also update any related `@Schema` or validation annotations/examples
accordingly.

In `@src/main/java/com/be/sportizebe/domain/match/entity/MatchStatus.java`:
- Around line 6-8: The enum states CLOSED and COMPLETED are never reached
because there is no write path to transition MatchRoom to those states; add a
scheduled transition mechanism that (1) after scheduledAt flips the MatchRoom
status to CLOSED and persists it (invoke a new method on MatchRoom like
markClosed() or setStatus(CLOSED) and save via MatchRepository), and (2) after
scheduledAt + durationMinutes flips to COMPLETED and persists it (invoke
markCompleted() and save), and ensure the scheduler/event listener also triggers
related side effects (trigger review/points/ratings workflows) that
MatchServiceImpl currently guards for; implement either a Spring `@Scheduled` task
or domain event listener that queries by scheduledAt/durationMinutes, updates
statuses, and saves so the existing guard checks in MatchServiceImpl become
reachable.

In `@src/main/java/com/be/sportizebe/domain/match/service/MatchServiceImpl.java`:
- Around line 130-142: The cancelMatch correctly sets MatchStatus.CANCELLED via
matchRoom.cancel(), but joinMatch currently lacks a guard so users can still
join cancelled matches; update the joinMatch method to check
matchRoom.getStatus() and disallow joining when status is CANCELLED, CLOSED, or
COMPLETED (mirror the checks used in cancelMatch), and throw the appropriate
CustomException (e.g., MatchErrorCode.MATCH_CANNOT_JOIN or add a new error code
if missing) before allowing participant addition.

---

Nitpick comments:
In `@src/main/java/com/be/sportizebe/domain/facility/entity/SportsFacility.java`:
- Around line 67-76: The changeAmenity method currently assigns widthMeter and
heightMeter even when zero or negative; update SportsFacility.changeAmenity to
validate these two parameters (widthMeter and heightMeter) when non-null and
require they are > 0 before assigning; if a provided value is <= 0, reject it by
throwing an IllegalArgumentException (with a clear message mentioning
widthMeter/heightMeter) or otherwise handle according to domain rules, and keep
existing null checks for other fields (hasToilet, hasVendingMachine, hasShower,
parkingType, wheelchairAccessible).

ℹ️ Review info

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 49c2144 and 454fce5.

📒 Files selected for processing (18)
  • src/main/java/com/be/sportizebe/domain/admin/controller/AdminController.java
  • src/main/java/com/be/sportizebe/domain/admin/service/AdminService.java
  • src/main/java/com/be/sportizebe/domain/admin/service/AdminServiceImpl.java
  • src/main/java/com/be/sportizebe/domain/facility/dto/request/FacilityCreateRequest.java
  • src/main/java/com/be/sportizebe/domain/facility/dto/request/FacilityUpdateRequest.java
  • src/main/java/com/be/sportizebe/domain/facility/dto/response/FacilityResponse.java
  • src/main/java/com/be/sportizebe/domain/facility/entity/ParkingType.java
  • src/main/java/com/be/sportizebe/domain/facility/entity/SportsFacility.java
  • src/main/java/com/be/sportizebe/domain/facility/mapper/FacilityMapper.java
  • src/main/java/com/be/sportizebe/domain/facility/service/SportsFacilityServiceImpl.java
  • src/main/java/com/be/sportizebe/domain/match/dto/request/MatchCreateRequest.java
  • src/main/java/com/be/sportizebe/domain/match/dto/response/MatchDetailResponse.java
  • src/main/java/com/be/sportizebe/domain/match/entity/MatchRoom.java
  • src/main/java/com/be/sportizebe/domain/match/entity/MatchStatus.java
  • src/main/java/com/be/sportizebe/domain/match/entity/UniformPolicy.java
  • src/main/java/com/be/sportizebe/domain/match/exception/MatchErrorCode.java
  • src/main/java/com/be/sportizebe/domain/match/service/MatchService.java
  • src/main/java/com/be/sportizebe/domain/match/service/MatchServiceImpl.java

Comment on lines +42 to +47
@Schema(description = "구장 가로 크기 (m)", example = "40")
Integer widthMeter,

@Schema(description = "구장 세로 크기 (m)", example = "20")
Integer heightMeter,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

구장 크기 필드에 값 범위 검증이 필요합니다.

현재는 음수/0 크기도 통과할 수 있어 잘못된 시설 데이터가 저장될 수 있습니다. 생성 요청에서는 최소 양수 제약을 거는 편이 안전합니다.

제안 수정안
 import io.swagger.v3.oas.annotations.media.Schema;
 import jakarta.validation.constraints.NotBlank;
 import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Positive;
@@
         `@Schema`(description = "구장 가로 크기 (m)", example = "40")
+        `@Positive`
         Integer widthMeter,
@@
         `@Schema`(description = "구장 세로 크기 (m)", example = "20")
+        `@Positive`
         Integer heightMeter,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Schema(description = "구장 가로 크기 (m)", example = "40")
Integer widthMeter,
@Schema(description = "구장 세로 크기 (m)", example = "20")
Integer heightMeter,
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;
`@Schema`(description = "구장 가로 크기 (m)", example = "40")
`@Positive`
Integer widthMeter,
`@Schema`(description = "구장 세로 크기 (m)", example = "20")
`@Positive`
Integer heightMeter,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/be/sportizebe/domain/facility/dto/request/FacilityCreateRequest.java`
around lines 42 - 47, Add strict positive-range validation to the facility
dimension fields in FacilityCreateRequest so negative or zero sizes cannot be
submitted: annotate the Integer fields widthMeter and heightMeter with a
bean-validation constraint such as `@Min`(1) or `@Positive` and update imports
(javax/ jakarta.validation.constraints.*) accordingly, and ensure any existing
validation groups/DTO usage will trigger validation on create requests so
invalid payloads return 400.

Comment on lines +37 to +41
@Schema(description = "구장 가로 크기 (m)", example = "40")
Integer widthMeter,

@Schema(description = "구장 세로 크기 (m)", example = "20")
Integer heightMeter,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

구장 크기에 음수/0 값이 들어갈 수 있습니다.

Line 37-41은 값 경계 검증이 없어 비정상 규격 데이터가 저장될 수 있습니다.

🧩 제안 수정안
+import jakarta.validation.constraints.Min;
@@
         `@Schema`(description = "구장 가로 크기 (m)", example = "40")
+        `@Min`(value = 1, message = "구장 가로 크기는 1m 이상이어야 합니다.")
         Integer widthMeter,
@@
         `@Schema`(description = "구장 세로 크기 (m)", example = "20")
+        `@Min`(value = 1, message = "구장 세로 크기는 1m 이상이어야 합니다.")
         Integer heightMeter,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/be/sportizebe/domain/facility/dto/request/FacilityUpdateRequest.java`
around lines 37 - 41, The DTO FacilityUpdateRequest allows widthMeter and
heightMeter to be zero or negative; add bean validation to enforce positive
dimensions by annotating the Integer fields widthMeter and heightMeter with an
appropriate constraint such as `@Min`(1) or `@Positive` (and import
javax.validation.constraints.*), and ensure the controller uses `@Valid` on the
request parameter so invalid values are rejected before persistence.

Comment on lines +39 to +57
@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;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# First, let's explore the repository structure to find migration-related directories
find . -type d \( -name "*migration*" -o -name "*liquibase*" -o -name "*flyway*" -o -name "*sql*" -o -name "db" \) 2>/dev/null | head -20

Repository: Sportize/be

Length of output: 37


🏁 Script executed:

# Search for database migration files with common patterns
git ls-files | grep -E "\.(sql|xml|yaml|yml)$" | grep -iE "(migration|liquibase|flyway|sql)" | head -30

Repository: Sportize/be

Length of output: 37


🏁 Script executed:

# Search for sports_facilities table references in the codebase
rg -i "sports_facilities" --type sql --type xml --type yaml -n

Repository: Sportize/be

Length of output: 37


🏁 Script executed:

# Check for Liquibase or Flyway configuration in Gradle files
rg -i "liquibase|flyway" --type gradle --type text -A 3 -B 1

Repository: Sportize/be

Length of output: 83


🏁 Script executed:

# Search for any DEFAULT or migration-related content related to the new columns
rg -i "(has_toilet|has_vending_machine|has_shower|parking_type|wheelchair_accessible|width_meter|height_meter)" -n

Repository: Sportize/be

Length of output: 37


🏁 Script executed:

# List the overall directory structure
ls -la && echo "---" && find . -type d -maxdepth 3 | head -40

Repository: Sportize/be

Length of output: 1528


🏁 Script executed:

# Look for any SQL files anywhere in the repository
find . -name "*.sql" -o -name "*.ddl" 2>/dev/null

Repository: Sportize/be

Length of output: 37


🏁 Script executed:

# Check the build.gradle or gradle files for database/migration configuration
find . -name "*.gradle" -o -name "*.gradle.kts" | head -5

Repository: Sportize/be

Length of output: 87


🏁 Script executed:

# Look at the root build.gradle or build.gradle.kts
find . -maxdepth 2 -name "build.gradle*" -exec cat {} \;

Repository: Sportize/be

Length of output: 1969


🏁 Script executed:

# Check if there's any database configuration or JPA/Hibernate setup
rg -i "jpa|hibernate|database|datasource|migration" -A 2 --type gradle --type yaml --type xml | head -50

Repository: Sportize/be

Length of output: 324


🏁 Script executed:

# Look for application configuration files
find ./src -name "application*.properties" -o -name "application*.yml" -o -name "application*.yaml"

Repository: Sportize/be

Length of output: 37


🏁 Script executed:

# Check application.properties content
find ./src -name "application*.properties" -exec cat {} \;

Repository: Sportize/be

Length of output: 37


🏁 Script executed:

# Check application.yml content
find ./src -name "application*.yml" -o -name "application*.yaml" | head -5 | xargs cat 2>/dev/null

Repository: Sportize/be

Length of output: 37


🏁 Script executed:

# Look for schema.sql or data.sql initialization files
find ./src -name "schema*.sql" -o -name "data.sql" -o -name "init*.sql"

Repository: Sportize/be

Length of output: 37


🏁 Script executed:

# Read the SportsFacility.java entity to check for defaults
cat -n ./src/main/java/com/be/sportizebe/domain/facility/entity/SportsFacility.java

Repository: Sportize/be

Length of output: 3494


기존 데이터를 위한 NOT NULL 컬럼 마이그레이션 및 DEFAULT 값 설정이 필요합니다.

sports_facilities 테이블에 7개의 NOT NULL 컬럼이 데이터베이스 기본값 없이 추가되고 있습니다:

  • hasToilet, hasVendingMachine, hasShower, wheelchairAccessible (primitive boolean - DEFAULT 없음)
  • parkingType (Enum 타입 - DEFAULT 없음)

현재 저장소에는 Liquibase/Flyway 마이그레이션 프레임워크가 없으며, 데이터베이스 스키마 초기화 파일(schema.sql, data.sql) 또는 DEFAULT 값 정의도 없습니다. 기존 sports_facilities 데이터가 있는 경우, 이 컬럼들을 추가할 때 스키마 적용 실패 또는 제약 조건 위반이 발생할 수 있습니다.

다음 중 하나를 적용하세요:

  • Liquibase/Flyway 마이그레이션 파일에 DEFAULT 값 및 UPDATE 백필 처리 추가
  • 또는 entity에 columnDefinition = "DEFAULT 값" 또는 @ColumnDefault 적용
  • 또는 Hibernate ddl-auto=create-drop 대신 적절한 마이그레이션 전략 도입
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/be/sportizebe/domain/facility/entity/SportsFacility.java`
around lines 39 - 57, The new NOT NULL fields in SportsFacility (hasToilet,
hasVendingMachine, hasShower, wheelchairAccessible, parkingType) need default
values or a backfill migration to avoid schema apply failures for existing rows;
either add explicit column defaults on the entity (e.g., `@Column`(nullable =
false, columnDefinition="boolean default false") or `@ColumnDefault`("false") for
the four booleans and a sensible default string for parkingType) and ensure the
Java fields have matching initial values, or create a proper migration
(Liquibase/Flyway) that adds the columns with DEFAULT clauses and performs an
UPDATE backfill before dropping defaults — update the SportsFacility class
fields and/or add the migration so schema changes are safe for preexisting data.

Comment on lines +45 to +46
@Schema(description = "남/녀 혼성 허용 여부", example = "false")
boolean mixedGender
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

mixedGender를 primitive로 두면 필드 누락이 조용히 false 처리됩니다.

Line 46은 요청에서 필드가 빠져도 검증 없이 false로 들어가서, 클라이언트 누락과 의도적 false를 구분할 수 없습니다. 필수 입력이라면 Boolean + @NotNull``로 명시해 주세요.

💡 제안 수정안
-        `@Schema`(description = "남/녀 혼성 허용 여부", example = "false")
-        boolean mixedGender
+        `@Schema`(description = "남/녀 혼성 허용 여부", example = "false")
+        `@NotNull`(message = "혼성 허용 여부는 필수입니다.")
+        Boolean mixedGender
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Schema(description = "남/녀 혼성 허용 여부", example = "false")
boolean mixedGender
`@Schema`(description = "남/녀 혼성 허용 여부", example = "false")
`@NotNull`(message = "혼성 허용 여부는 필수입니다.")
Boolean mixedGender
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/com/be/sportizebe/domain/match/dto/request/MatchCreateRequest.java`
around lines 45 - 46, The mixedGender field in MatchCreateRequest is a primitive
boolean so missing request values silently default to false; change its type
from primitive boolean to the wrapper Boolean (field name mixedGender in class
MatchCreateRequest) and, if the field is required, annotate it with `@NotNull`
(and update imports) so you can distinguish absent values from an explicit
false; also update any related `@Schema` or validation annotations/examples
accordingly.

Comment on lines +6 to +8
CLOSED, // 매칭 시작됨 (scheduledAt 이후, 참여 불가) -> "지금 진행중인 매칭" 탭 보여줄 때
COMPLETED, // 매칭 종료 (scheduledAt + durationMinutes 이후) -> "매칭 완료 후 리뷰/평점. 포인트 지금 등 사이드 이펙트 필요 시COM
CANCELLED // Admin 취소
Copy link
Copy Markdown

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
# 목적: CLOSED/COMPLETED 상태를 "읽는 곳"과 "쓰기(전환)하는 곳"을 분리 확인
# 기대: enum 선언/비교문 외에 status 대입 또는 setStatus 경로가 최소 1개 이상 존재

echo "=== Search 1: MatchStatus.CLOSED/COMPLETED 읽기 패턴 ==="
rg -nP --type=java 'MatchStatus\.(CLOSED|COMPLETED)' -C2

echo ""
echo "=== Search 2: 상태 대입/setStatus 쓰기 패턴 ==="
rg -nP --type=java '(status\s*=\s*MatchStatus\.(CLOSED|COMPLETED)|setStatus\s*\(\s*MatchStatus\.(CLOSED|COMPLETED)\s*\))' -C3

Repository: Sportize/be

Length of output: 899


🏁 Script executed:

#!/bin/bash

echo "=== Search 3: 모든 setStatus 호출 찾기 (모든 인자값) ==="
rg -nP --type=java 'setStatus\s*\(' -C3

echo ""
echo "=== Search 4: Match 엔티티 클래스 찾기 ==="
fd -e java -path "*/match/entity/*Match*" -o -path "*/match/*Match.java"

echo ""
echo "=== Search 5: `@Scheduled` 또는 status 상태 전환 로직 ==="
rg -nP --type=java '@Scheduled|status\s*=' -C2 | head -100

Repository: Sportize/be

Length of output: 7093


🏁 Script executed:

#!/bin/bash

echo "=== MatchRoom.java 전체 내용 ==="
cat -n src/main/java/com/be/sportizebe/domain/match/entity/MatchRoom.java

echo ""
echo "=== CLOSED 상태만 명시적으로 검색 ==="
rg -nP --type=java 'CLOSED' -C3

echo ""
echo "=== COMPLETED 상태만 명시적으로 검색 ==="
rg -nP --type=java 'COMPLETED' -C3

Repository: Sportize/be

Length of output: 6946


CLOSED/COMPLETED 상태 전환 write 경로 존재하지 않습니다. 구현이 필요합니다.

enum에는 정의되어 있지만, 실제로 이 상태로 전환하는 코드가 없습니다. MatchRoom 엔티티에는 join(), leave(), cancel() 메서드만 있고, CLOSED/COMPLETED로 변경하는 로직이 전혀 없습니다. MatchServiceImpl에서 이 상태들을 guard 조건으로 체크하고 있지만(lines 136-137), 이 상태들은 절대 도달할 수 없는 dead code입니다.

다음 구현이 필요합니다:

  • scheduledAt 이후 CLOSED 상태로 자동 전환하는 로직 (스케줄 태스크 또는 이벤트 리스너)
  • scheduledAt + durationMinutes 이후 COMPLETED 상태로 자동 전환하는 로직

현재 상태로는 "진행중인 매칭" 탭 분류와 리뷰/평점/포인트 지급 같은 사이드 이펙트가 정상 작동하지 않습니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/be/sportizebe/domain/match/entity/MatchStatus.java` around
lines 6 - 8, The enum states CLOSED and COMPLETED are never reached because
there is no write path to transition MatchRoom to those states; add a scheduled
transition mechanism that (1) after scheduledAt flips the MatchRoom status to
CLOSED and persists it (invoke a new method on MatchRoom like markClosed() or
setStatus(CLOSED) and save via MatchRepository), and (2) after scheduledAt +
durationMinutes flips to COMPLETED and persists it (invoke markCompleted() and
save), and ensure the scheduler/event listener also triggers related side
effects (trigger review/points/ratings workflows) that MatchServiceImpl
currently guards for; implement either a Spring `@Scheduled` task or domain event
listener that queries by scheduledAt/durationMinutes, updates statuses, and
saves so the existing guard checks in MatchServiceImpl become reachable.

Comment on lines +130 to +142
@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();
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

취소된 매칭에 재참여 가능한 경로가 남아 있습니다.

cancelMatch에서 Line 141로 CANCELLED 전환은 되지만, joinMatch(Line 53 이후)에 상태 차단이 없어 취소된 매칭에도 참가자가 추가될 수 있습니다.

🛠️ 제안 수정안
@@
     public void joinMatch(Long matchId, Long userId) {
@@
         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);
+        }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/com/be/sportizebe/domain/match/service/MatchServiceImpl.java`
around lines 130 - 142, The cancelMatch correctly sets MatchStatus.CANCELLED via
matchRoom.cancel(), but joinMatch currently lacks a guard so users can still
join cancelled matches; update the joinMatch method to check
matchRoom.getStatus() and disallow joining when status is CANCELLED, CLOSED, or
COMPLETED (mirror the checks used in cancelMatch), and throw the appropriate
CustomException (e.g., MatchErrorCode.MATCH_CANNOT_JOIN or add a new error code
if missing) before allowing participant addition.

@angoroa angoroa merged commit 87c0a35 into develop Mar 2, 2026
1 check passed
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