From 2d7a0661c4b0e89c1ca0b422266af42e058c2cb2 Mon Sep 17 00:00:00 2001 From: Andrew Date: Mon, 17 Aug 2026 15:28:24 -0400 Subject: [PATCH 1/2] Add match cycle DTOs with derived counts and isDraft --- .../dto/cycle/CreateMatchCycleRequest.java | 6 +++ .../dto/cycle/MatchCycleDetailQuery.java | 3 ++ .../match/dto/cycle/MatchCycleListQuery.java | 5 +++ .../match/dto/cycle/MatchCycleResponse.java | 45 +++++++++++++++++++ .../dto/cycle/UpdateMatchCycleRequest.java | 5 +++ 5 files changed, 64 insertions(+) create mode 100644 src/main/java/org/patinanetwork/patchats/api/match/dto/cycle/CreateMatchCycleRequest.java create mode 100644 src/main/java/org/patinanetwork/patchats/api/match/dto/cycle/MatchCycleDetailQuery.java create mode 100644 src/main/java/org/patinanetwork/patchats/api/match/dto/cycle/MatchCycleListQuery.java create mode 100644 src/main/java/org/patinanetwork/patchats/api/match/dto/cycle/MatchCycleResponse.java create mode 100644 src/main/java/org/patinanetwork/patchats/api/match/dto/cycle/UpdateMatchCycleRequest.java diff --git a/src/main/java/org/patinanetwork/patchats/api/match/dto/cycle/CreateMatchCycleRequest.java b/src/main/java/org/patinanetwork/patchats/api/match/dto/cycle/CreateMatchCycleRequest.java new file mode 100644 index 00000000..1b675cca --- /dev/null +++ b/src/main/java/org/patinanetwork/patchats/api/match/dto/cycle/CreateMatchCycleRequest.java @@ -0,0 +1,6 @@ +package org.patinanetwork.patchats.api.match.dto.cycle; + +import jakarta.validation.constraints.NotNull; +import java.time.Instant; + +public record CreateMatchCycleRequest(@NotNull Instant runAt, String period) {} diff --git a/src/main/java/org/patinanetwork/patchats/api/match/dto/cycle/MatchCycleDetailQuery.java b/src/main/java/org/patinanetwork/patchats/api/match/dto/cycle/MatchCycleDetailQuery.java new file mode 100644 index 00000000..b9a1b4b3 --- /dev/null +++ b/src/main/java/org/patinanetwork/patchats/api/match/dto/cycle/MatchCycleDetailQuery.java @@ -0,0 +1,3 @@ +package org.patinanetwork.patchats.api.match.dto.cycle; + +public record MatchCycleDetailQuery(String memberIndustry, String status) {} diff --git a/src/main/java/org/patinanetwork/patchats/api/match/dto/cycle/MatchCycleListQuery.java b/src/main/java/org/patinanetwork/patchats/api/match/dto/cycle/MatchCycleListQuery.java new file mode 100644 index 00000000..a0662962 --- /dev/null +++ b/src/main/java/org/patinanetwork/patchats/api/match/dto/cycle/MatchCycleListQuery.java @@ -0,0 +1,5 @@ +package org.patinanetwork.patchats.api.match.dto.cycle; + +import java.time.Instant; + +public record MatchCycleListQuery(String period, Instant startTime, Instant endTime) {} diff --git a/src/main/java/org/patinanetwork/patchats/api/match/dto/cycle/MatchCycleResponse.java b/src/main/java/org/patinanetwork/patchats/api/match/dto/cycle/MatchCycleResponse.java new file mode 100644 index 00000000..88093688 --- /dev/null +++ b/src/main/java/org/patinanetwork/patchats/api/match/dto/cycle/MatchCycleResponse.java @@ -0,0 +1,45 @@ +package org.patinanetwork.patchats.api.match.dto.cycle; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.time.Instant; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.ToString; +import org.patinanetwork.patchats.api.match.db.models.MatchCycle; + +@Getter +@Builder +@ToString +@EqualsAndHashCode +public class MatchCycleResponse { + + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) + private final Integer matchCycleId; + + @Schema(requiredMode = Schema.RequiredMode.REQUIRED, nullable = true) + private final String period; + + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) + private final Instant runAt; + + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) + private final boolean isDraft; + + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) + private final Integer totalMembers; + + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) + private final Integer totalMatched; + + public static MatchCycleResponse from(final MatchCycle cycle) { + return MatchCycleResponse.builder() + .matchCycleId(cycle.getId()) + .period(cycle.getPeriod()) + .runAt(cycle.getRunAt()) + .isDraft(cycle.isDraft()) + .totalMembers(cycle.getTotalMembers()) + .totalMatched(cycle.getTotalMatched()) + .build(); + } +} diff --git a/src/main/java/org/patinanetwork/patchats/api/match/dto/cycle/UpdateMatchCycleRequest.java b/src/main/java/org/patinanetwork/patchats/api/match/dto/cycle/UpdateMatchCycleRequest.java new file mode 100644 index 00000000..12289e6f --- /dev/null +++ b/src/main/java/org/patinanetwork/patchats/api/match/dto/cycle/UpdateMatchCycleRequest.java @@ -0,0 +1,5 @@ +package org.patinanetwork.patchats.api.match.dto.cycle; + +import java.time.Instant; + +public record UpdateMatchCycleRequest(Instant runAt, String period, Boolean isDraft) {} From 59a3e5f09db2a09a61eea3a31801d502d8ed9be0 Mon Sep 17 00:00:00 2001 From: Andrew Date: Mon, 24 Aug 2026 13:24:25 -0400 Subject: [PATCH 2/2] Add DTOs and exceptions for upcoming match endpoints --- .../patchats/api/match/MatchController.java | 1 + .../dto/cycle/MatchCycleDetailResponse.java | 22 ++++++++++ .../match/dto/cycle/MatchCycleResponse.java | 2 - .../dto/match/BulkCreateMatchesRequest.java | 7 ++++ .../api/match/dto/match/MatchListQuery.java | 6 +++ .../api/match/dto/match/MatchResponse.java | 41 +++++++++++++++++++ .../dto/match/UpdateMatchFeedbackRequest.java | 5 +++ .../dto/match/UpdateMatchStatusRequest.java | 5 +++ .../common/web/ApiExceptionHandler.java | 6 +++ .../web/exception/MatchNotFoundException.java | 9 ++++ 10 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/patinanetwork/patchats/api/match/MatchController.java create mode 100644 src/main/java/org/patinanetwork/patchats/api/match/dto/cycle/MatchCycleDetailResponse.java create mode 100644 src/main/java/org/patinanetwork/patchats/api/match/dto/match/BulkCreateMatchesRequest.java create mode 100644 src/main/java/org/patinanetwork/patchats/api/match/dto/match/MatchListQuery.java create mode 100644 src/main/java/org/patinanetwork/patchats/api/match/dto/match/MatchResponse.java create mode 100644 src/main/java/org/patinanetwork/patchats/api/match/dto/match/UpdateMatchFeedbackRequest.java create mode 100644 src/main/java/org/patinanetwork/patchats/api/match/dto/match/UpdateMatchStatusRequest.java create mode 100644 src/main/java/org/patinanetwork/patchats/common/web/exception/MatchNotFoundException.java diff --git a/src/main/java/org/patinanetwork/patchats/api/match/MatchController.java b/src/main/java/org/patinanetwork/patchats/api/match/MatchController.java new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src/main/java/org/patinanetwork/patchats/api/match/MatchController.java @@ -0,0 +1 @@ + diff --git a/src/main/java/org/patinanetwork/patchats/api/match/dto/cycle/MatchCycleDetailResponse.java b/src/main/java/org/patinanetwork/patchats/api/match/dto/cycle/MatchCycleDetailResponse.java new file mode 100644 index 00000000..34aacad4 --- /dev/null +++ b/src/main/java/org/patinanetwork/patchats/api/match/dto/cycle/MatchCycleDetailResponse.java @@ -0,0 +1,22 @@ +package org.patinanetwork.patchats.api.match.dto.cycle; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.util.List; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.ToString; +import org.patinanetwork.patchats.api.match.dto.match.AdminMatchResponse; + +@Getter +@Builder +@ToString +@EqualsAndHashCode +public class MatchCycleDetailResponse { + + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) + private final MatchCycleResponse cycle; + + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) + private final List matches; +} diff --git a/src/main/java/org/patinanetwork/patchats/api/match/dto/cycle/MatchCycleResponse.java b/src/main/java/org/patinanetwork/patchats/api/match/dto/cycle/MatchCycleResponse.java index 88093688..06b2104d 100644 --- a/src/main/java/org/patinanetwork/patchats/api/match/dto/cycle/MatchCycleResponse.java +++ b/src/main/java/org/patinanetwork/patchats/api/match/dto/cycle/MatchCycleResponse.java @@ -38,8 +38,6 @@ public static MatchCycleResponse from(final MatchCycle cycle) { .period(cycle.getPeriod()) .runAt(cycle.getRunAt()) .isDraft(cycle.isDraft()) - .totalMembers(cycle.getTotalMembers()) - .totalMatched(cycle.getTotalMatched()) .build(); } } diff --git a/src/main/java/org/patinanetwork/patchats/api/match/dto/match/BulkCreateMatchesRequest.java b/src/main/java/org/patinanetwork/patchats/api/match/dto/match/BulkCreateMatchesRequest.java new file mode 100644 index 00000000..9dbaa833 --- /dev/null +++ b/src/main/java/org/patinanetwork/patchats/api/match/dto/match/BulkCreateMatchesRequest.java @@ -0,0 +1,7 @@ +package org.patinanetwork.patchats.api.match.dto.match; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import java.util.List; + +public record BulkCreateMatchesRequest(@Valid @NotEmpty List matches) {} diff --git a/src/main/java/org/patinanetwork/patchats/api/match/dto/match/MatchListQuery.java b/src/main/java/org/patinanetwork/patchats/api/match/dto/match/MatchListQuery.java new file mode 100644 index 00000000..e9d5dbec --- /dev/null +++ b/src/main/java/org/patinanetwork/patchats/api/match/dto/match/MatchListQuery.java @@ -0,0 +1,6 @@ +package org.patinanetwork.patchats.api.match.dto.match; + +import java.time.Instant; +import java.util.UUID; + +public record MatchListQuery(UUID memberId, String period, Instant startTime, Instant endTime, String status) {} diff --git a/src/main/java/org/patinanetwork/patchats/api/match/dto/match/MatchResponse.java b/src/main/java/org/patinanetwork/patchats/api/match/dto/match/MatchResponse.java new file mode 100644 index 00000000..17e22807 --- /dev/null +++ b/src/main/java/org/patinanetwork/patchats/api/match/dto/match/MatchResponse.java @@ -0,0 +1,41 @@ +package org.patinanetwork.patchats.api.match.dto.match; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.util.UUID; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.ToString; +import org.patinanetwork.patchats.api.match.db.models.Match; + +@Getter +@Builder +@ToString +@EqualsAndHashCode +public class MatchResponse { + + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) + private final UUID matchId; + + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) + private final UUID memberAId; + + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) + private final UUID memberBId; + + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) + private final String month; + + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) + private final String status; + + public static MatchResponse from(final Match match, final String month) { + return MatchResponse.builder() + .matchId(match.getId()) + .memberAId(match.getMemberAId()) + .memberBId(match.getMemberBId()) + .month(month) + .status(match.getStatus()) + .build(); + } +} diff --git a/src/main/java/org/patinanetwork/patchats/api/match/dto/match/UpdateMatchFeedbackRequest.java b/src/main/java/org/patinanetwork/patchats/api/match/dto/match/UpdateMatchFeedbackRequest.java new file mode 100644 index 00000000..292eaa9b --- /dev/null +++ b/src/main/java/org/patinanetwork/patchats/api/match/dto/match/UpdateMatchFeedbackRequest.java @@ -0,0 +1,5 @@ +package org.patinanetwork.patchats.api.match.dto.match; + +import jakarta.validation.constraints.NotBlank; + +public record UpdateMatchFeedbackRequest(@NotBlank String feedback) {} diff --git a/src/main/java/org/patinanetwork/patchats/api/match/dto/match/UpdateMatchStatusRequest.java b/src/main/java/org/patinanetwork/patchats/api/match/dto/match/UpdateMatchStatusRequest.java new file mode 100644 index 00000000..ec923f48 --- /dev/null +++ b/src/main/java/org/patinanetwork/patchats/api/match/dto/match/UpdateMatchStatusRequest.java @@ -0,0 +1,5 @@ +package org.patinanetwork.patchats.api.match.dto.match; + +import jakarta.validation.constraints.NotBlank; + +public record UpdateMatchStatusRequest(@NotBlank String status) {} diff --git a/src/main/java/org/patinanetwork/patchats/common/web/ApiExceptionHandler.java b/src/main/java/org/patinanetwork/patchats/common/web/ApiExceptionHandler.java index 90dcf481..dc306a9a 100644 --- a/src/main/java/org/patinanetwork/patchats/common/web/ApiExceptionHandler.java +++ b/src/main/java/org/patinanetwork/patchats/common/web/ApiExceptionHandler.java @@ -6,6 +6,7 @@ import org.patinanetwork.patchats.common.web.exception.EmailNotResendableException; import org.patinanetwork.patchats.common.web.exception.EmailTemplateNotFoundException; import org.patinanetwork.patchats.common.web.exception.MatchCycleNotFoundException; +import org.patinanetwork.patchats.common.web.exception.MatchNotFoundException; import org.patinanetwork.patchats.common.web.exception.MemberDuplicateException; import org.patinanetwork.patchats.common.web.exception.MemberNotFoundException; import org.patinanetwork.patchats.common.web.exception.ValidationException; @@ -64,6 +65,11 @@ public ResponseEntity> handleMatchCycleNotFound(final MatchCy return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ApiResponder.failure(ex.getMessage())); } + @ExceptionHandler(MatchNotFoundException.class) + public ResponseEntity> handleMatchNotFound(final MatchNotFoundException ex) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ApiResponder.failure(ex.getMessage())); + } + private String formatError(final FieldError error) { return error.getField() + " " + error.getDefaultMessage(); } diff --git a/src/main/java/org/patinanetwork/patchats/common/web/exception/MatchNotFoundException.java b/src/main/java/org/patinanetwork/patchats/common/web/exception/MatchNotFoundException.java new file mode 100644 index 00000000..ff8afff7 --- /dev/null +++ b/src/main/java/org/patinanetwork/patchats/common/web/exception/MatchNotFoundException.java @@ -0,0 +1,9 @@ +package org.patinanetwork.patchats.common.web.exception; + +import java.util.UUID; + +public class MatchNotFoundException extends RuntimeException { + public MatchNotFoundException(UUID id) { + super("Match with ID " + id + " not found"); + } +}