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
12 changes: 12 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
up:
docker compose -f docker/docker-compose.local.yml up -d

down:
docker compose -f docker/docker-compose.local.yml down

restart:
docker compose -f docker/docker-compose.local.yml down && \
docker compose -f docker/docker-compose.local.yml up -d

logs:
docker compose -f docker/docker-compose.local.yml logs -f
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.be.sportizebe.domain.match.dto.request.MatchNearRequest;
import com.be.sportizebe.domain.match.dto.response.MatchDetailResponse;
import com.be.sportizebe.domain.match.dto.response.MatchNearResponse;
import com.be.sportizebe.domain.match.dto.response.MyMatchResponse;
import com.be.sportizebe.domain.match.service.MatchService;
import com.be.sportizebe.global.cache.dto.UserAuthInfo;
import com.be.sportizebe.global.response.BaseResponse;
Expand Down Expand Up @@ -65,7 +66,16 @@ public ResponseEntity<BaseResponse<Void>> leaveMatch(
return ResponseEntity.ok(BaseResponse.success("매칭 취소 성공", null));
}

@Operation(summary = "내 주변 매칭 목록 조회", description = "매칭상태가 OPEN인 매칭들만 보여준다.")
@Operation(summary = "내가 참여 중인 매칭 목록", description = "JOINED 상태인 매칭만 반환한다.")
@GetMapping("/me")
public ResponseEntity<BaseResponse<List<MyMatchResponse>>> getMyMatches(
@AuthenticationPrincipal UserAuthInfo userAuthInfo
) {
List<MyMatchResponse> response = matchService.getMyMatches(userAuthInfo.getId());
return ResponseEntity.ok(BaseResponse.success("내 매칭 목록 조회 성공", response));
}

@Operation(summary = "내 주변 매칭 목록 조회", description = "매칭상태가 OPEN인 매칭들만 보여준다.")
@GetMapping("/near")
public ResponseEntity<BaseResponse<List<MatchNearResponse>>> getNearMatches(
@ParameterObject @Valid @ModelAttribute MatchNearRequest request
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package com.be.sportizebe.domain.match.dto.response;

import com.be.sportizebe.common.enums.SportType;
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 io.swagger.v3.oas.annotations.media.Schema;

import java.time.LocalDateTime;

@Schema(description = "내 매칭 이력 응답")
public record MyMatchResponse(

@Schema(description = "매칭방 ID", example = "42")
Long matchId,

@Schema(description = "스포츠 종류", example = "SOCCER")
SportType sportsName,

@Schema(description = "체육시설 ID", example = "7")
Long facilityId,

@Schema(description = "최대 인원", example = "12")
int maxMembers,

@Schema(description = "현재 인원", example = "8")
int curMembers,

@Schema(description = "매칭 상태", example = "OPEN")
MatchStatus matchStatus,

@Schema(description = "매칭 시작 일시", example = "2026-03-10T18:00:00")
LocalDateTime scheduledAt,

@Schema(description = "진행 시간(분)", example = "60")
int durationMinutes,

@Schema(description = "참가비", example = "5000")
int entryFee,

@Schema(description = "내 참가 상태 (JOINED: 참여 중, LEFT: 취소)", example = "JOINED")
MatchParticipantStatus participantStatus,

@Schema(description = "참가 일시", example = "2026-03-07T12:00:00")
LocalDateTime joinedAt
) {
public static MyMatchResponse from(MatchParticipant participant) {
MatchRoom room = participant.getMatchRoom();
return new MyMatchResponse(
room.getId(),
room.getSportsName(),
room.getFacilityId(),
room.getMaxMembers(),
room.getCurMembers(),
room.getStatus(),
room.getScheduledAt(),
room.getDurationMinutes(),
room.getEntryFee(),
participant.getStatus(),
participant.getJoinedAt()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import com.be.sportizebe.domain.match.entity.MatchRoom;
import com.be.sportizebe.domain.user.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;
import java.util.Optional;
Expand All @@ -25,4 +27,9 @@ public interface MatchParticipantRepository extends JpaRepository<MatchParticipa

// 특정 유저의 특정 매칭방 참가 이력 단건 조회 (상태 무관)
Optional<MatchParticipant> findByMatchRoomAndUser(MatchRoom matchRoom, User user);

// 내 참여 중인 매칭 목록 (JOINED, N+1 방지 fetch join)
@Query("SELECT mp FROM MatchParticipant mp JOIN FETCH mp.matchRoom WHERE mp.user.id = :userId AND mp.status = :status ORDER BY mp.joinedAt DESC")
List<MatchParticipant> findAllByUserIdAndStatusFetch(@Param("userId") Long userId, @Param("status") MatchParticipantStatus status);

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import com.be.sportizebe.domain.match.dto.response.MatchDetailResponse;
import com.be.sportizebe.domain.match.dto.response.MatchNearResponse;
import com.be.sportizebe.domain.match.dto.response.MatchResponse;
import com.be.sportizebe.domain.user.entity.User;
import com.be.sportizebe.domain.match.dto.response.MyMatchResponse;

import java.util.List;

Expand All @@ -23,4 +23,6 @@ public interface MatchService {

void deleteMatch(Long matchId); // 매칭 삭제 (관리자 전용)

List<MyMatchResponse> getMyMatches(Long userId); // 참여 중인 매칭 목록

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.be.sportizebe.domain.match.dto.response.MatchDetailResponse;
import com.be.sportizebe.domain.match.dto.response.MatchNearResponse;
import com.be.sportizebe.domain.match.dto.response.MatchResponse;
import com.be.sportizebe.domain.match.dto.response.MyMatchResponse;
import com.be.sportizebe.domain.match.entity.MatchParticipant;
import com.be.sportizebe.domain.match.entity.MatchParticipantStatus;
import com.be.sportizebe.domain.match.entity.MatchRoom;
Expand Down Expand Up @@ -135,6 +136,16 @@ public void deleteMatch(Long matchId) {
}

@Override
@Transactional(readOnly = true)
public List<MyMatchResponse> getMyMatches(Long userId) {
return matchParticipantRepository
.findAllByUserIdAndStatusFetch(userId, MatchParticipantStatus.JOINED)
.stream()
.map(MyMatchResponse::from)
.toList();
}

@Override
@Transactional(readOnly = true)
public List<MatchNearResponse> getNearMatches(MatchNearRequest request) {
String sportsName = request.getSportsName() == null
Expand Down