Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
9e17857
refactor: 아이디 찾기 휴대폰 번호 비교시 U Prefix 추가
chominju02 Aug 23, 2025
86b9170
refactor: 아이디 찾기 시 phoneNumberUtil 사용
chominju02 Aug 23, 2025
d0a3eeb
refactor: 아아디 찾기 시 카카오 사용자일 경우 error 추가
chominju02 Aug 23, 2025
c8c22ba
Merge pull request #359 from mosu-dev/refactor/mosu-358
chominju02 Aug 23, 2025
dd9540b
MOSU-360 refactor: 문의 답변 시 "관리자" 고정적으로 명시
jbh010204 Aug 23, 2025
935c887
feat(config): restructure application configuration files and add new…
polyglot-k Aug 23, 2025
df0a1e7
feat(application): add static factory method for ApplicationContext a…
polyglot-k Aug 23, 2025
0a1cf8d
feat(tests): add unit tests for GetApplicationsStepProcessor
polyglot-k Aug 23, 2025
837c739
MOSU-360 fix: 문의 답변 시 "관리자" 고정적으로 명시
jbh010204 Aug 23, 2025
24b5758
feat(tests): add unit tests for Refund processing components
polyglot-k Aug 23, 2025
727d61f
refactor(tests): remove unnecessary blank line in GetApplicationsStep…
polyglot-k Aug 23, 2025
0b8846c
feat(tests): add unit tests for IdStream functionality
polyglot-k Aug 23, 2025
c15eeab
feat(ci): update GitHub Actions workflow to separate build and test jobs
polyglot-k Aug 23, 2025
a750e71
feat(tests): add unit tests for ApplicationValidator functionality
polyglot-k Aug 23, 2025
718b1a9
Merge pull request #361 from mosu-dev/refactor/mosu-360
jbh010204 Aug 23, 2025
5cff4f7
Merge branch 'develop' of https://github.com/mosu-dev/mosu-server int…
polyglot-k Aug 23, 2025
3403f48
feat(tests): add unit tests for Inquiry services and repositories
jbh010204 Aug 23, 2025
3776e5e
feat(tests): add unit tests for Payment services and repositories
jbh010204 Aug 23, 2025
a8a66fa
feat(tests): add unit tests for FaqService
jbh010204 Aug 23, 2025
16e53be
feat(tests): add unit tests for various services and configurations
jbh010204 Aug 23, 2025
55d9a0b
feat(tests): add unit tests for ApplicationValidator functionality
polyglot-k Aug 23, 2025
ec94654
fix : 백업 폴더 제거
polyglot-k Aug 23, 2025
6ed7a8f
feat(ci): update GitHub Actions workflow to combine build and test jobs
polyglot-k Aug 23, 2025
e9c91e0
fix: correct package name from 'vaildator' to 'validator' in Applicat…
polyglot-k Aug 23, 2025
929e98f
Merge pull request #364 from mosu-dev/feat/test
polyglot-k Aug 23, 2025
ceebc49
feat: add application status update on deposit success event handling
polyglot-k Aug 24, 2025
6141749
fix: ensure application status is only changed to APPROVED if current…
polyglot-k Aug 24, 2025
fb22412
Merge pull request #365 from mosu-dev/feat/fix-deposit
polyglot-k Aug 24, 2025
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
13 changes: 11 additions & 2 deletions .github/workflows/docker-pr-build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ on:
branches: [ develop ]

jobs:
build-and-deploy:
build-and-test:
runs-on: ubuntu-latest

steps:
Expand Down Expand Up @@ -34,5 +34,14 @@ jobs:
git clone https://x-access-token:${{ secrets.GH_PAT }}@github.com/mosu-dev/mosu-kmc-jar.git temp-jar
cp temp-jar/*.jar libs/

- name: Build with Gradle
- name: Build without tests
run: ./gradlew build -x test

- name: Run tests
run: ./gradlew test

- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: build-artifacts
path: build/libs/*.jar
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

import life.mosu.mosuserver.domain.application.entity.ApplicationJpaEntity;
import life.mosu.mosuserver.domain.exam.entity.ExamJpaEntity;
import life.mosu.mosuserver.domain.examapplication.entity.ExamApplicationJpaEntity;
Expand All @@ -34,6 +33,13 @@ public ApplicationContext(
this(applications, examApplications, Map.of(), Map.of(), Map.of(), Map.of());
}

public static ApplicationContext of(
List<ApplicationJpaEntity> applications,
List<ExamApplicationWithStatus> examApplications
) {
return new ApplicationContext(applications, examApplications);
}

public ApplicationContext fetchExams(Function<List<Long>, List<ExamJpaEntity>> fetcher) {
Map<Long, ExamJpaEntity> newExamMap = fetcher.apply(
examApplications.stream()
Expand All @@ -42,37 +48,44 @@ public ApplicationContext fetchExams(Function<List<Long>, List<ExamJpaEntity>> f
.toList()
).stream().collect(Collectors.toMap(ExamJpaEntity::getId, Function.identity()));

return new ApplicationContext(applications, examApplications, newExamMap, subjectMap, paymentMap, refundMap);
return new ApplicationContext(applications, examApplications, newExamMap, subjectMap,
paymentMap, refundMap);
}

public ApplicationContext fetchSubjects(Function<List<Long>, List<ExamSubjectJpaEntity>> fetcher) {
public ApplicationContext fetchSubjects(
Function<List<Long>, List<ExamSubjectJpaEntity>> fetcher) {
Map<Long, List<ExamSubjectJpaEntity>> newSubjectMap = fetcher.apply(
examApplications.stream()
.map(e -> e.examApplication().getId())
.toList()
).stream().collect(Collectors.groupingBy(ExamSubjectJpaEntity::getExamApplicationId));

return new ApplicationContext(applications, examApplications, examMap, newSubjectMap, paymentMap, refundMap);
return new ApplicationContext(applications, examApplications, examMap, newSubjectMap,
paymentMap, refundMap);
}

public ApplicationContext fetchPayments(Function<List<Long>, List<PaymentJpaEntity>> fetcher) {
Map<Long, PaymentJpaEntity> newPaymentMap = fetcher.apply(
examApplications.stream()
.map(e -> e.examApplication().getId())
.toList()
).stream().collect(Collectors.toMap(PaymentJpaEntity::getExamApplicationId, Function.identity()));
).stream().collect(
Collectors.toMap(PaymentJpaEntity::getExamApplicationId, Function.identity()));

return new ApplicationContext(applications, examApplications, examMap, subjectMap, newPaymentMap, refundMap);
return new ApplicationContext(applications, examApplications, examMap, subjectMap,
newPaymentMap, refundMap);
}

public ApplicationContext fetchRefunds(Function<List<Long>, List<RefundJpaEntity>> fetcher) {
Map<Long, RefundJpaEntity> newRefundMap = fetcher.apply(
examApplications.stream()
.map(e -> e.examApplication().getId())
.toList()
).stream().collect(Collectors.toMap(RefundJpaEntity::getExamApplicationId, Function.identity()));
).stream().collect(
Collectors.toMap(RefundJpaEntity::getExamApplicationId, Function.identity()));

return new ApplicationContext(applications, examApplications, examMap, subjectMap, paymentMap, newRefundMap);
return new ApplicationContext(applications, examApplications, examMap, subjectMap,
paymentMap, newRefundMap);
}

public List<ApplicationResponse> assemble() {
Expand All @@ -88,10 +101,13 @@ public List<ApplicationResponse> assemble() {
.toList();
}

private Map.Entry<Long, ExamApplicationResponse> createExamApplicationResponse(ExamApplicationWithStatus item) {
private Map.Entry<Long, ExamApplicationResponse> createExamApplicationResponse(
ExamApplicationWithStatus item) {
ExamApplicationJpaEntity examApp = item.examApplication();
ExamJpaEntity exam = examMap.get(examApp.getExamId());
if (exam == null) return null;
if (exam == null) {
return null;
}

Set<String> subjects = subjectMap.getOrDefault(examApp.getId(), List.of()).stream()
.map(s -> s.getSubject().getSubjectName()).collect(Collectors.toSet());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import life.mosu.mosuserver.application.application.processor.GetApplicationsStepProcessor;
import life.mosu.mosuserver.application.application.processor.RegisterApplicationStepProcessor;
import life.mosu.mosuserver.application.application.processor.SaveExamTicketStepProcessor;
import life.mosu.mosuserver.application.application.vaildator.ApplicationValidator;
import life.mosu.mosuserver.application.application.validator.ApplicationValidator;
import life.mosu.mosuserver.application.exam.cache.ExamQuotaCacheManager;
import life.mosu.mosuserver.application.user.UserService;
import life.mosu.mosuserver.domain.application.entity.ApplicationJpaEntity;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package life.mosu.mosuserver.application.application.vaildator;
package life.mosu.mosuserver.application.application.validator;

import java.time.LocalDateTime;
import java.util.HashSet;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static life.mosu.mosuserver.global.util.EncodeUtil.passwordEncode;

import life.mosu.mosuserver.domain.user.entity.AuthProvider;
import life.mosu.mosuserver.domain.user.entity.UserJpaEntity;
import life.mosu.mosuserver.domain.user.repository.UserJpaRepository;
import life.mosu.mosuserver.global.exception.CustomRuntimeException;
Expand Down Expand Up @@ -42,11 +43,13 @@ public ChangePasswordResponse changePassword(ChangePasswordRequest request,
@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
public FindLoginIdResponse findLoginId(FindLoginIdRequest request) {
UserJpaEntity user = userJpaRepository.findByNameAndPhoneNumber(request.name(),
request.phoneNumber())
PhoneNumberUtil.formatPhoneNumber(request.phoneNumber()))
.orElseThrow(() -> new CustomRuntimeException(ErrorCode.NOT_FOUND_LOGIN_ID));

if (user.getProvider() == AuthProvider.KAKAO) {
throw new CustomRuntimeException(ErrorCode.KAKAO_ACCOUNT_DUPLICATED);
}
return FindLoginIdResponse.from(user.getLoginId());

}

@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@


import life.mosu.mosuserver.application.virtualaccount.VirtualAccountLogService;
import life.mosu.mosuserver.domain.application.entity.ApplicationStatus;
import life.mosu.mosuserver.domain.application.repository.ApplicationJpaRepository;
import life.mosu.mosuserver.domain.examapplication.repository.ExamApplicationJpaRepository;
import life.mosu.mosuserver.domain.virtualaccount.DepositStatus;
import life.mosu.mosuserver.domain.virtualaccount.VirtualAccountLogJpaEntity;
Expand All @@ -25,7 +27,7 @@ public class DepositSuccessEventHandler implements DepositEventHandler<DepositSu
private final MailNotifier<DepositSuccessMailRequest> mailer;
private final NotifyEventPublisher notifier;
private final ExamApplicationJpaRepository examApplicationJpaRepository;

private final ApplicationJpaRepository applicationJpaRepository;
@Override
@Transactional
public void handle(DepositSuccessEvent event) {
Expand All @@ -38,6 +40,12 @@ public void handle(DepositSuccessEvent event) {
.orElseThrow(
() -> new CustomRuntimeException(ErrorCode.EXAM_APPLICATION_NOT_FOUND));

var application = applicationJpaRepository.findById(log.getApplicationId())
.orElseThrow(
() -> new CustomRuntimeException(ErrorCode.APPLICATION_LIST_NOT_FOUND));
if (application.getStatus() == ApplicationStatus.PENDING) {
application.changeStatus(ApplicationStatus.APPROVED);
}
Comment on lines +43 to +48

Choose a reason for hiding this comment

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

high

가상계좌 입금 성공 시 신청(Application)의 상태를 PENDING에서 APPROVED로 변경하는 로직이 추가되어 데이터 정합성을 높이는 좋은 개선입니다.

다만, 이 로직이 추가되면서 바로 뒤에 이어지는 알림 생성 로직(LunaNotificationEvent.create(...))에서 잠재적인 문제가 발생할 수 있어 보입니다.

  1. 알림 유형 고정: 현재 LunaNotificationStatus.APPLICATION_GUEST_SUCCESS로 알림 유형이 고정되어 있습니다. 만약 로그인한 일반 사용자가 가상계좌로 결제하는 경우에도 게스트용 알림이 발송될 수 있어 사용자에게 혼란을 줄 수 있습니다.
  2. 단일 시험 정보만 사용: 하나의 신청(application)에 여러 시험(exam)이 포함될 수 있지만, findFirst()를 사용하여 첫 번째 시험 정보(exam.getId())만 알림에 사용하고 있습니다. 이로 인해 사용자는 전체 신청 건 중 일부에 대한 정보만 받게 될 수 있습니다.

추가하신 로직과 함께 주변 코드의 상호작용을 고려하여, 사용자의 유형(게스트/일반 회원)을 구분하고 신청에 포함된 모든 시험 정보를 올바르게 처리하도록 알림 로직을 개선하는 것을 검토해 보시는 것이 좋겠습니다.

LunaNotificationEvent lunaNotificationEvent = LunaNotificationEvent.create(
LunaNotificationStatus.APPLICATION_GUEST_SUCCESS,
exam.getUserId(), exam.getId());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ public enum ErrorCode {

// ID 찾기 관련
NOT_FOUND_LOGIN_ID(HttpStatus.NOT_FOUND, "해당 아이디를 찾을 수 없습니다.", CriticalLevel.LOW),
KAKAO_ACCOUNT_DUPLICATED(HttpStatus.CONFLICT, "카카오로 가입한 사용자입니다", CriticalLevel.LOW),

//결제 API 실패
PAYMENT_API_ERROR(HttpStatus.BAD_REQUEST, "결제 API 호출에 실패하였습니다.", CriticalLevel.CRITICAL),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public InquiryAnswerJpaEntity toEntity(Long postId, UserJpaEntity user) {
.title(title)
.content(content)
.userId(user.getId())
.author(user.getName())
.author("관리자")

Choose a reason for hiding this comment

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

medium

"관리자"라는 문자열이 하드코딩되어 있습니다. 유지보수성을 높이기 위해, 이와 같은 상수는 별도의 상수 클래스나 final static 필드로 정의하여 사용하는 것이 좋습니다. 이렇게 하면 나중에 작성자명을 변경해야 할 때 한 곳만 수정하면 되므로 실수를 줄일 수 있습니다.

예시:

public final class AdminConstants {
    public static final String ADMIN_AUTHOR_NAME = "관리자";
    private AdminConstants() {}
}

사용:

.author(AdminConstants.ADMIN_AUTHOR_NAME)

.build();
}
}
57 changes: 0 additions & 57 deletions src/test/java/life/mosu/mosuserver/FaqServiceTest.java

This file was deleted.

12 changes: 0 additions & 12 deletions src/test/java/life/mosu/mosuserver/MosuServerApplicationTests.java

This file was deleted.

Loading