-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: 각 모듈별 docker파일 분리 * fix: chat_member 엔티티 image_url 제거 * feat: 채팅방 생성 repo & service 정의 * feat: 채팅 멤버 생성 service 정의 * test: 채팅방 생성 컨트롤러 단위 테스트 성공 시나리오 작성 * feat: chat_room_request dto 정의 * feat: chat_room craete controller * feat: chat_room_usecase 및 request & response schema 추가 * fix: controller success response 추가 * test: chat_room_fixture * fix: chat_room_res detail dto to_string 수정 * fix: controller 내 usecase final 키워드 추가 * feat: 채팅방 역할 상수 정의 * fix: chat_memeber role 필드 추가 * fix: chat_room create dto to_entity 메서드 static 제거 * feat: chat_member entity 정적 팩토리 메서드 추가 * feat: 채팅방 생성 서비스 로직 구현 * feat: chat_room_mapper 정의 * test: 채팅방 생성 통합 테스트 구현 * fix: 채팅방 생성 요청 background_image_url pattern 수정 * feat: 채팅방 생성 요청 캐싱 entity * feat: 생성 지연 채팅방 서비스 로직 * fix: pended_chat_room user_id 필드 추가 및 유효성 검사 & to_chat_room 메서드 추가 * fix: chat_room_req pend, create 요청 분리 * fix: 캐싱된 채팅방 정보 예외 정의 * fix: 채팅방 생성 서비스 로직 대기, 생성 메서드 분리 * feat: external-api 모듈 guid config 의존성 추가 * fix: pended_chat_room hash code 수정 * fix: 사용자 아이디로 캐싱된 정보 조회 -> 사용자 권한 예외 제거 가능하므로 삭제 * fix: controller 및 usecase 요청 분리 * test: controller 단위 테스트 pend, create 분리 * feat: 채팅방 entity pk auto_increment 속성 제거 * test: chat_room_fixture url 정보 수정 * fix: 캐싱된 채팅방 정보 로깅 추가 * test: 채팅방 생성 시나리오 테스트 수정 * fix: 채팅방 멤버 생성 시, entity 반환하도록 chat_member_service 로직 수정 * feat: 채팅방 저장 시, image url 변환 작업 수행 로직 추가 * test: aws_adapter mock bean 설정 추가 * feat: 채팅방 swagger group 등록 * docs: 채팅방 생성 대기 및 확정 api 스웨거 문서 작성 * chore: 불필요한 dockerfile 모두 제거 * chore: socket-relay dockerfile 복구
- Loading branch information
1 parent
f46a3e1
commit 7650f4a
Showing
26 changed files
with
819 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
# Common 모듈 빌드 | ||
FROM openjdk:17 AS common-builder | ||
WORKDIR /app | ||
|
||
COPY gradlew . | ||
COPY gradle gradle | ||
COPY build.gradle . | ||
COPY settings.gradle . | ||
COPY pennyway-common pennyway-common | ||
RUN chmod +x ./gradlew | ||
|
||
|
||
COPY pennyway-common pennyway-common | ||
COPY build.gradle settings.gradle gradlew ./ | ||
COPY gradle gradle | ||
RUN ./gradlew :pennyway-common:build -x test | ||
|
||
# Infra 모듈 빌드 | ||
FROM openjdk:17 AS infra-builder | ||
WORKDIR /app | ||
COPY --from=common-builder /app/pennyway-common/build/libs/*.jar lib/ | ||
COPY pennyway-infra pennyway-infra | ||
COPY build.gradle settings.gradle gradlew ./ | ||
COPY gradle gradle | ||
RUN ./gradlew :pennyway-infra:build -x test | ||
|
||
# Domain 모듈 빌드 | ||
FROM openjdk:17 AS domain-builder | ||
WORKDIR /app | ||
COPY --from=common-builder /app/pennyway-common/build/libs/*.jar lib/ | ||
COPY --from=infra-builder /app/pennyway-infra/build/libs/*.jar lib/ | ||
COPY pennyway-domain pennyway-domain | ||
COPY build.gradle settings.gradle gradlew ./ | ||
COPY gradle gradle | ||
RUN ./gradlew :pennyway-domain:build -x test | ||
|
||
# 최종 실행 이미지 | ||
FROM openjdk:17 | ||
|
||
WORKDIR /app | ||
|
||
# 빌드된 JAR 파일 복사 | ||
COPY --from=common-builder /app/pennyway-common/build/libs/*.jar common.jar | ||
COPY --from=infra-builder /app/pennyway-infra/build/libs/*.jar infra.jar | ||
COPY --from=domain-builder /app/pennyway-domain/build/libs/*.jar domain.jar | ||
|
||
# 클래스패스 설정 | ||
ENV CLASSPATH=/app/common.jar:/app/infra.jar:/app/domain.jar |
31 changes: 31 additions & 0 deletions
31
pennyway-app-external-api/src/main/java/kr/co/pennyway/api/apis/chat/api/ChatRoomApi.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package kr.co.pennyway.api.apis.chat.api; | ||
|
||
import io.swagger.v3.oas.annotations.Operation; | ||
import io.swagger.v3.oas.annotations.media.Content; | ||
import io.swagger.v3.oas.annotations.media.Schema; | ||
import io.swagger.v3.oas.annotations.media.SchemaProperty; | ||
import io.swagger.v3.oas.annotations.responses.ApiResponse; | ||
import io.swagger.v3.oas.annotations.tags.Tag; | ||
import kr.co.pennyway.api.apis.chat.dto.ChatRoomReq; | ||
import kr.co.pennyway.api.apis.chat.dto.ChatRoomRes; | ||
import kr.co.pennyway.api.common.annotation.ApiExceptionExplanation; | ||
import kr.co.pennyway.api.common.annotation.ApiResponseExplanations; | ||
import kr.co.pennyway.api.common.security.authentication.SecurityUserDetails; | ||
import kr.co.pennyway.domain.common.redis.chatroom.PendedChatRoomErrorCode; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.security.core.annotation.AuthenticationPrincipal; | ||
import org.springframework.web.bind.annotation.RequestBody; | ||
|
||
@Tag(name = "[채팅방 API]") | ||
public interface ChatRoomApi { | ||
@Operation(summary = "[1] 채팅방 생성 대기 요청", method = "POST", description = "채팅방 배경 이미지를 제외한 모든 정보를 서버에 저장하기 위한 API. 성공 시, 채팅방 아이디를 반환하며, 5분 후에 저장된 자동 삭제된다.") | ||
@ApiResponse(responseCode = "200", description = "채팅방 생성 대기 요청 성공", content = @Content(schemaProperties = @SchemaProperty(name = "chatRoomId", schema = @Schema(implementation = Long.class)))) | ||
ResponseEntity<?> postChatRoom(@RequestBody ChatRoomReq.Pend request, @AuthenticationPrincipal SecurityUserDetails user); | ||
|
||
@Operation(summary = "[2] 채팅방 생성", method = "POST", description = "채팅방 배경 이미지를 전달하여 `[1] 채팅방 생성 대기 요청`의 요청을 확정짓는다. 저장된 채팅방 정보를 반환한다.") | ||
@ApiResponse(responseCode = "200", description = "채팅방 생성 성공", content = @Content(schemaProperties = @SchemaProperty(name = "chatRoom", schema = @Schema(implementation = ChatRoomRes.Detail.class)))) | ||
@ApiResponseExplanations(errors = { | ||
@ApiExceptionExplanation(value = PendedChatRoomErrorCode.class, constant = "NOT_FOUND", name = "채팅방 정보 탐색 실패", description = "사용자가 생성한 채팅방 정보가 존재하지 않는 경우 발생하며, 이 경우 채팅방 생성 요청은 재시도 없이 실패 처리해야 한다.") | ||
}) | ||
ResponseEntity<?> createChatRoom(@RequestBody ChatRoomReq.Create request, @AuthenticationPrincipal SecurityUserDetails user); | ||
} |
40 changes: 40 additions & 0 deletions
40
...xternal-api/src/main/java/kr/co/pennyway/api/apis/chat/controller/ChatRoomController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package kr.co.pennyway.api.apis.chat.controller; | ||
|
||
import kr.co.pennyway.api.apis.chat.api.ChatRoomApi; | ||
import kr.co.pennyway.api.apis.chat.dto.ChatRoomReq; | ||
import kr.co.pennyway.api.apis.chat.usecase.ChatRoomUseCase; | ||
import kr.co.pennyway.api.common.response.SuccessResponse; | ||
import kr.co.pennyway.api.common.security.authentication.SecurityUserDetails; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.security.access.prepost.PreAuthorize; | ||
import org.springframework.security.core.annotation.AuthenticationPrincipal; | ||
import org.springframework.web.bind.annotation.PostMapping; | ||
import org.springframework.web.bind.annotation.RequestBody; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
@Slf4j | ||
@RestController | ||
@RequiredArgsConstructor | ||
@RequestMapping("/v2/chat-rooms") | ||
public class ChatRoomController implements ChatRoomApi { | ||
private static final String CHAT_ROOM_ID = "chatRoomId"; | ||
private static final String CHAT_ROOM = "chatRoom"; | ||
private final ChatRoomUseCase chatRoomUseCase; | ||
|
||
@Override | ||
@PostMapping("/pend") | ||
@PreAuthorize("isAuthenticated()") | ||
public ResponseEntity<?> postChatRoom(@RequestBody ChatRoomReq.Pend request, @AuthenticationPrincipal SecurityUserDetails user) { | ||
return ResponseEntity.ok(SuccessResponse.from(CHAT_ROOM_ID, chatRoomUseCase.pendChatRoom(request, user.getUserId()))); | ||
} | ||
|
||
@Override | ||
@PostMapping("") | ||
@PreAuthorize("isAuthenticated()") | ||
public ResponseEntity<?> createChatRoom(@RequestBody ChatRoomReq.Create request, @AuthenticationPrincipal SecurityUserDetails user) { | ||
return ResponseEntity.ok(SuccessResponse.from(CHAT_ROOM, chatRoomUseCase.createChatRoom(request, user.getUserId()))); | ||
} | ||
} |
35 changes: 35 additions & 0 deletions
35
pennyway-app-external-api/src/main/java/kr/co/pennyway/api/apis/chat/dto/ChatRoomReq.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package kr.co.pennyway.api.apis.chat.dto; | ||
|
||
import io.swagger.v3.oas.annotations.media.Schema; | ||
import jakarta.validation.constraints.NotBlank; | ||
import jakarta.validation.constraints.Pattern; | ||
import jakarta.validation.constraints.Size; | ||
import kr.co.pennyway.domain.common.redis.chatroom.PendedChatRoom; | ||
|
||
public final class ChatRoomReq { | ||
@Schema(title = "채팅방 생성 요청 - 대기") | ||
public record Pend( | ||
@NotBlank | ||
@Size(min = 1, max = 50) | ||
@Schema(description = "채팅방 제목. NULL 혹은 공백은 허용하지 않으며, 1~50자 이내의 문자열이어야 한다.", example = "페니웨이") | ||
String title, | ||
@Size(min = 1, max = 100) | ||
@Schema(description = "채팅방 설명. NULL을 허용하며, 문자가 존재할 시 공백 허용 없이 1~100자 이내의 문자열이어야 한다.", example = "페니웨이 채팅방입니다.") | ||
String description, | ||
@Schema(description = "채팅방 비밀번호. NULL을 허용한다. 비밀번호는 6자리 정수만 허용", example = "123456") | ||
@Size(min = 6, max = 6) | ||
Integer password | ||
) { | ||
public PendedChatRoom toEntity(Long id, Long userId) { | ||
return PendedChatRoom.of(id, userId, title, description, password); | ||
} | ||
} | ||
|
||
@Schema(title = "채팅방 생성 요청 - 확정") | ||
public record Create( | ||
@Schema(description = "채팅방 배경 이미지 URL. NULL을 허용한다.", example = "delete/chatroom/{chatroom_id}/{uuid}_{timestamp}.{ext}") | ||
@Pattern(regexp = "^delete/.*", message = "채팅방 배경 이미지 URL은 delete/로 시작해야 합니다.") | ||
String backgroundImageUrl | ||
) { | ||
} | ||
} |
44 changes: 44 additions & 0 deletions
44
pennyway-app-external-api/src/main/java/kr/co/pennyway/api/apis/chat/dto/ChatRoomRes.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package kr.co.pennyway.api.apis.chat.dto; | ||
|
||
import com.fasterxml.jackson.annotation.JsonFormat; | ||
import com.fasterxml.jackson.databind.annotation.JsonSerialize; | ||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; | ||
import io.swagger.v3.oas.annotations.media.Schema; | ||
import kr.co.pennyway.domain.domains.chatroom.domain.ChatRoom; | ||
|
||
import java.time.LocalDateTime; | ||
import java.util.Objects; | ||
|
||
public final class ChatRoomRes { | ||
@Schema(description = "채팅방 상세 정보") | ||
public record Detail( | ||
@Schema(description = "채팅방 ID", type = "long") | ||
Long id, | ||
@Schema(description = "채팅방 제목") | ||
String title, | ||
@Schema(description = "채팅방 설명") | ||
String description, | ||
@Schema(description = "채팅방 배경 이미지 URL") | ||
String backgroundImageUrl, | ||
@Schema(description = "채팅방 비공개 여부") | ||
boolean isPrivate, | ||
@Schema(description = "채팅방 참여자 수") | ||
int participantCount, | ||
@Schema(description = "채팅방 개설일") | ||
@JsonSerialize(using = LocalDateTimeSerializer.class) | ||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") | ||
LocalDateTime createdAt | ||
) { | ||
public static Detail from(ChatRoom chatRoom, int participantCount) { | ||
return new Detail( | ||
chatRoom.getId(), | ||
chatRoom.getTitle(), | ||
Objects.toString(chatRoom.getDescription(), ""), | ||
Objects.toString(chatRoom.getBackgroundImageUrl(), ""), | ||
chatRoom.getPassword() != null, | ||
participantCount, | ||
chatRoom.getCreatedAt() | ||
); | ||
} | ||
} | ||
} |
12 changes: 12 additions & 0 deletions
12
...ay-app-external-api/src/main/java/kr/co/pennyway/api/apis/chat/mapper/ChatRoomMapper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package kr.co.pennyway.api.apis.chat.mapper; | ||
|
||
import kr.co.pennyway.api.apis.chat.dto.ChatRoomRes; | ||
import kr.co.pennyway.common.annotation.Mapper; | ||
import kr.co.pennyway.domain.domains.chatroom.domain.ChatRoom; | ||
|
||
@Mapper | ||
public final class ChatRoomMapper { | ||
public static ChatRoomRes.Detail toChatRoomResDetail(ChatRoom chatRoom, int participantCount) { | ||
return ChatRoomRes.Detail.from(chatRoom, participantCount); | ||
} | ||
} |
78 changes: 78 additions & 0 deletions
78
...-external-api/src/main/java/kr/co/pennyway/api/apis/chat/service/ChatRoomSaveService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
package kr.co.pennyway.api.apis.chat.service; | ||
|
||
import kr.co.pennyway.api.apis.chat.dto.ChatRoomReq; | ||
import kr.co.pennyway.api.common.storage.AwsS3Adapter; | ||
import kr.co.pennyway.domain.common.redis.chatroom.PendedChatRoom; | ||
import kr.co.pennyway.domain.common.redis.chatroom.PendedChatRoomErrorCode; | ||
import kr.co.pennyway.domain.common.redis.chatroom.PendedChatRoomErrorException; | ||
import kr.co.pennyway.domain.common.redis.chatroom.PendedChatRoomService; | ||
import kr.co.pennyway.domain.domains.chatroom.domain.ChatRoom; | ||
import kr.co.pennyway.domain.domains.chatroom.service.ChatRoomService; | ||
import kr.co.pennyway.domain.domains.member.domain.ChatMember; | ||
import kr.co.pennyway.domain.domains.member.service.ChatMemberService; | ||
import kr.co.pennyway.domain.domains.member.type.ChatMemberRole; | ||
import kr.co.pennyway.domain.domains.user.domain.User; | ||
import kr.co.pennyway.domain.domains.user.exception.UserErrorCode; | ||
import kr.co.pennyway.domain.domains.user.exception.UserErrorException; | ||
import kr.co.pennyway.domain.domains.user.service.UserService; | ||
import kr.co.pennyway.infra.client.aws.s3.ObjectKeyType; | ||
import kr.co.pennyway.infra.client.guid.IdGenerator; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@Slf4j | ||
@Service | ||
@RequiredArgsConstructor | ||
public class ChatRoomSaveService { | ||
private final UserService userService; | ||
private final ChatRoomService chatRoomService; | ||
private final ChatMemberService chatMemberService; | ||
private final PendedChatRoomService pendedChatRoomService; | ||
|
||
private final AwsS3Adapter awsS3Adapter; | ||
private final IdGenerator<Long> idGenerator; | ||
|
||
/** | ||
* 채팅방 생성 정보를 캐싱한다. | ||
* 해당 요청은 {@link #createChatRoom(ChatRoomReq.Create, Long)}를 통해 채팅방을 확정할 수 있다. | ||
* | ||
* @return 캐싱된 채팅방의 ID | ||
*/ | ||
@Transactional | ||
public Long pendChatRoom(ChatRoomReq.Pend request, Long userId) { | ||
Long chatRoomId = idGenerator.generate(); | ||
log.info("Chat room ID: {}", chatRoomId); | ||
PendedChatRoom info = pendedChatRoomService.create(request.toEntity(chatRoomId, userId)); | ||
log.info("Pended chat room: {}", info); | ||
|
||
return chatRoomId; | ||
} | ||
|
||
/** | ||
* 캐싱된 채팅방을 확정하고 채팅방을 생성한다. | ||
* 채팅방을 생성한 사용자는 채팅방의 관리자로 설정된다. | ||
* | ||
* @throws PendedChatRoomErrorException: {@link PendedChatRoomErrorCode#NOT_FOUND} - 캐싱된 채팅방이 존재하지 않을 경우 | ||
*/ | ||
@Transactional | ||
public ChatRoom createChatRoom(ChatRoomReq.Create request, Long userId) { | ||
PendedChatRoom pendedChatRoom = pendedChatRoomService.readByUserId(userId) | ||
.orElseThrow(() -> new PendedChatRoomErrorException(PendedChatRoomErrorCode.NOT_FOUND)); | ||
|
||
String originImageUrl = null; | ||
if (request.backgroundImageUrl() != null) { | ||
originImageUrl = awsS3Adapter.saveImage(request.backgroundImageUrl(), ObjectKeyType.CHAT_PROFILE); | ||
} | ||
|
||
ChatRoom chatRoom = chatRoomService.create(pendedChatRoom.toChatRoom(originImageUrl)); | ||
|
||
User user = userService.readUser(userId).orElseThrow(() -> new UserErrorException(UserErrorCode.NOT_FOUND)); | ||
ChatMember member = ChatMember.of(user.getName(), user, chatRoom, ChatMemberRole.ADMIN); | ||
|
||
chatMemberService.create(member); | ||
|
||
return chatRoom; | ||
} | ||
} |
25 changes: 25 additions & 0 deletions
25
...-app-external-api/src/main/java/kr/co/pennyway/api/apis/chat/usecase/ChatRoomUseCase.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package kr.co.pennyway.api.apis.chat.usecase; | ||
|
||
import kr.co.pennyway.api.apis.chat.dto.ChatRoomReq; | ||
import kr.co.pennyway.api.apis.chat.dto.ChatRoomRes; | ||
import kr.co.pennyway.api.apis.chat.mapper.ChatRoomMapper; | ||
import kr.co.pennyway.api.apis.chat.service.ChatRoomSaveService; | ||
import kr.co.pennyway.common.annotation.UseCase; | ||
import kr.co.pennyway.domain.domains.chatroom.domain.ChatRoom; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
@UseCase | ||
@RequiredArgsConstructor | ||
public class ChatRoomUseCase { | ||
private final ChatRoomSaveService chatRoomSaveService; | ||
|
||
public Long pendChatRoom(ChatRoomReq.Pend request, Long userId) { | ||
return chatRoomSaveService.pendChatRoom(request, userId); | ||
} | ||
|
||
public ChatRoomRes.Detail createChatRoom(ChatRoomReq.Create request, Long userId) { | ||
ChatRoom chatRoom = chatRoomSaveService.createChatRoom(request, userId); | ||
|
||
return ChatRoomMapper.toChatRoomResDetail(chatRoom, 1); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.