Skip to content

Conversation

@polyglot-k
Copy link
Contributor

@polyglot-k polyglot-k commented Aug 6, 2025

✨ 구현한 기능

📢 논의하고 싶은 내용

🎸 기타

Summary by CodeRabbit

  • New Features

    • Added support for guest users to submit applications via a new endpoint.
    • Introduced guest application data validation and transformation logic.
    • Added new whitelist entry to allow guest application submissions.
    • New error message for failed user saves.
  • Improvements

    • Centralized and streamlined application processing logic for both registered and guest users.
    • Enhanced exam application amount calculation based on selected options.
    • Improved handling and logging of virtual account creation and deposit events.
    • Refined event handling for deposit success and failure scenarios.
  • Bug Fixes

    • Enforced subject selection validation for applications.
  • Refactor

    • Delegated virtual account processing to dedicated components for better maintainability.
    • Updated method signatures and data structures for clarity and consistency.

…nd include applicationId in CreateVirtualAccountRequest
@coderabbitai
Copy link

coderabbitai bot commented Aug 6, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Caution

Review failed

The pull request is closed.

Walkthrough

This update introduces guest application support and refactors application and virtual account processing. It adds new DTOs, methods, and endpoints for guest users, centralizes shared logic, and modularizes virtual account event handling. Several new classes and methods are added for mapping, validation, and event publishing, and some existing APIs and entities are extended with new parameters and fields.

Changes

Cohort / File(s) Change Summary
Guest Application Feature
src/main/java/life/mosu/mosuserver/presentation/application/dto/ApplicationGuestRequest.java, src/main/java/life/mosu/mosuserver/presentation/application/ApplicationController.java, src/main/java/life/mosu/mosuserver/application/application/ApplicationService.java, src/main/java/life/mosu/mosuserver/application/user/UserService.java, src/main/java/life/mosu/mosuserver/global/filter/Whitelist.java
Adds guest application endpoint, DTO, and service logic. Introduces guest user creation, validation, and application handling. Updates whitelist for guest endpoint.
Application Processing Refactor
src/main/java/life/mosu/mosuserver/application/application/ApplicationService.java, src/main/java/life/mosu/mosuserver/application/application/dto/RegisterApplicationCommand.java, src/main/java/life/mosu/mosuserver/application/application/processor/RegisterApplicationStepProcessor.java
Centralizes application processing logic in a shared method. Updates command and processor DTOs for handling lists of exam applications.
Virtual Account Modularization
src/main/java/life/mosu/mosuserver/application/virtualaccount/VirtualAccountService.java, src/main/java/life/mosu/mosuserver/application/virtualaccount/VirtualAccountLogService.java, src/main/java/life/mosu/mosuserver/application/virtualaccount/processor/CreateVirtualAccountProcessor.java, src/main/java/life/mosu/mosuserver/application/virtualaccount/event/DepositEventPublisher.java, src/main/java/life/mosu/mosuserver/application/virtualaccount/event/DepositEventHandler.java, src/main/java/life/mosu/mosuserver/application/virtualaccount/event/DepositSuccessEventHandler.java, src/main/java/life/mosu/mosuserver/application/virtualaccount/event/DepositFailureEventHandler.java, src/main/java/life/mosu/mosuserver/application/virtualaccount/handler/DepositFailureEventHandler.java, src/main/java/life/mosu/mosuserver/domain/virtualaccount/service/DepositEventMapper.java
Refactors virtual account creation and event handling into processor and publisher classes. Adds event mapping, new event handler, and updates log service and event handler locations. Removes deprecated handler.
Domain & Entity Extensions
src/main/java/life/mosu/mosuserver/domain/examapplication/repository/ExamApplicationJpaRepository.java, src/main/java/life/mosu/mosuserver/domain/examapplication/service/ExamApplicationAmountCalculator.java, src/main/java/life/mosu/mosuserver/domain/virtualaccount/VirtualAccountLogJpaEntity.java, src/main/java/life/mosu/mosuserver/domain/profile/entity/Gender.java
Adds new calculator, repository query, entity field, and enum method for extended business logic and data mapping.
DTO and Payload Updates
src/main/java/life/mosu/mosuserver/presentation/virtualaccount/dto/CreateVirtualAccountRequest.java, src/main/java/life/mosu/mosuserver/infra/toss/dto/TossVirtualAccountPayload.java
Adds new fields to DTOs and updates payload factory method to accept dynamic amount.
Error Handling
src/main/java/life/mosu/mosuserver/global/exception/ErrorCode.java
Adds new error code for user save failure.
Import/Package Adjustments
src/main/java/life/mosu/mosuserver/application/virtualaccount/VirtualAccountCallbackService.java
Updates import paths for event handlers.

Sequence Diagram(s)

sequenceDiagram
    participant Guest as Guest User
    participant Controller as ApplicationController
    participant Service as ApplicationService
    participant UserService
    participant QuotaManager as ExamQuotaCacheManager

    Guest->>Controller: POST /applications/guest (ApplicationGuestRequest)
    Controller->>Service: applyByGuest(request)
    Service->>UserService: saveUser(request.toUserJpaEntity())
    UserService-->>Service: userId
    Service->>QuotaManager: incrementQuota(examId)
    Service->>Service: handleApplication(userId, ...)
    Service-->>Controller: CreateApplicationResponse
    Controller-->>Guest: 201 Created (ApiResponseWrapper)
Loading
sequenceDiagram
    participant System as System
    participant VAService as VirtualAccountService
    participant Processor as CreateVirtualAccountProcessor
    participant Publisher as DepositEventPublisher

    System->>VAService: create(CreateVirtualAccountRequest)
    VAService->>Processor: process(request)
    Processor-->>VAService: VirtualAccountResponse
    VAService-->>System: VirtualAccountResponse

    System->>VAService: onDepositEvent(DepositEventRequest)
    VAService->>Publisher: publish(request)
    Publisher-->>VAService: (void)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Possibly related PRs

  • mosu-dev/mosu-server#137: Refactors ApplicationService and restructures application processing; both PRs modify the same class and relate to application logic.
  • mosu-dev/mosu-server#154: Adds userId to RegisterApplicationCommand and updates ApplicationService usage; closely related to user and application processing logic.
  • mosu-dev/mosu-server#124: Refactors ApplicationService apply method; related as both address application processing logic.

Suggested labels

우선순위 중

Suggested reviewers

  • wlgns12370
  • jbh010204

Poem

A guest may now apply with ease,
Through code refactored, changes breeze!
Virtual accounts now modular and neat,
New handlers and mappers make it complete.
With fields and flows all freshly spun,
This rabbit cheers: the work is done!
🐇✨

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cd4cf35 and 947f2b1.

📒 Files selected for processing (1)
  • src/main/java/life/mosu/mosuserver/application/virtualaccount/processor/CreateVirtualAccountProcessor.java (1 hunks)
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/guest-application

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@polyglot-k polyglot-k linked an issue Aug 6, 2025 that may be closed by this pull request
Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Summary of Changes

Hello @polyglot-k, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces the capability for non-member users to apply for exams, streamlining the application process by automatically managing guest user accounts. A key enhancement is the integration of exam quota updates with virtual account payment statuses, ensuring that exam slots are accurately reflected and freed up upon payment failures. Furthermore, the virtual account system has undergone significant refactoring to improve its architecture and allow for dynamic calculation of payment amounts based on application specifics.

Highlights

  • Guest Application Feature: A new feature has been implemented allowing non-member users to apply for exams. This includes automatic creation of a temporary user account for the guest and processing their application.
  • Dynamic Exam Quota Management: The system now dynamically updates exam quotas based on virtual account payment events. Specifically, if a virtual account deposit fails or is canceled, the corresponding exam slot is automatically freed up by decreasing the quota.
  • Virtual Account System Refactoring: The virtual account creation and deposit event handling logic has been significantly refactored. Responsibilities are now distributed among dedicated processors and event publishers/handlers, enhancing modularity and maintainability.
  • Dynamic Virtual Account Amount Calculation: Virtual account creation now calculates the payment amount dynamically based on the specific exam application details, such as whether lunch is included, rather than using a fixed amount.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments or fill out our survey to provide feedback.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces functionality for non-member applications and virtual account payments, including logic to update exam quotas. The refactoring to use processors and event handlers for virtual account logic is well-executed and improves the overall design. A critical transactional issue with cache updates that could lead to data inconsistency was identified. There are also important points regarding API correctness, potential legal risks from hardcoded consent values, and a hardcoded amount that need to be addressed. Addressing these points will significantly improve the robustness and quality of the new features.

Copy link

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

🧹 Nitpick comments (4)
src/main/java/life/mosu/mosuserver/domain/profile/entity/Gender.java (1)

16-22: Consider improving null safety and case handling.

The implementation is functionally correct, but consider these improvements:

  1. Null safety: The method doesn't handle null input, which could cause NPE
  2. Case sensitivity: Consider case-insensitive matching for better user experience

Apply this diff for better robustness:

 public static Gender fromName(String genderName) {
+    if (genderName == null) {
+        throw new IllegalArgumentException("Gender name cannot be null");
+    }
     return Arrays.stream(Gender.values())
-            .filter(g -> g.getGenderName().equals(genderName))
+            .filter(g -> g.getGenderName().equalsIgnoreCase(genderName.trim()))
             .findFirst()
             .orElseThrow(
                     () -> new IllegalArgumentException("Invalid gender name: " + genderName));
 }
src/main/java/life/mosu/mosuserver/domain/examapplication/service/ExamApplicationAmountCalculator.java (1)

12-16: Logic is correct, consider minor readability improvement.

The amount calculation logic is sound and handles the lunch option correctly. The use of .equals(Boolean.TRUE) is good defensive programming for null safety.

Consider this minor refactor for improved readability:

 public int calculate(ExamApplicationJpaEntity application) {
-    return application.getIsLunchChecked().equals(Boolean.TRUE) ?
-            BASE_AMOUNT + LUNCH_AMOUNT :
-            BASE_AMOUNT;
+    int totalAmount = BASE_AMOUNT;
+    if (Boolean.TRUE.equals(application.getIsLunchChecked())) {
+        totalAmount += LUNCH_AMOUNT;
+    }
+    return totalAmount;
 }
src/main/java/life/mosu/mosuserver/presentation/application/ApplicationController.java (1)

41-41: Consider renaming query parameter for clarity.

The query parameter userId might be confusing for guest applications since guests don't have traditional user IDs. Consider using applicationId to be more explicit about what the parameter represents.

-                .queryParam("userId", response.applicationId())
+                .queryParam("applicationId", response.applicationId())
src/main/java/life/mosu/mosuserver/application/application/dto/RegisterApplicationCommand.java (1)

11-11: Consider renaming field to match its plural nature.

The field examApplication is singular but holds a List<ExamApplicationRequest>. Consider renaming it to examApplications for better clarity and consistency.

-        List<ExamApplicationRequest> examApplication,
+        List<ExamApplicationRequest> examApplications,
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5ac5c16 and cbc87b1.

📒 Files selected for processing (24)
  • src/main/java/life/mosu/mosuserver/application/application/ApplicationService.java (2 hunks)
  • src/main/java/life/mosu/mosuserver/application/application/dto/RegisterApplicationCommand.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/application/application/processor/RegisterApplicationStepProcessor.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/application/user/UserService.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/application/virtualaccount/VirtualAccountCallbackService.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/application/virtualaccount/VirtualAccountLogService.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/application/virtualaccount/VirtualAccountService.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/application/virtualaccount/event/DepositEventHandler.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/application/virtualaccount/event/DepositEventPublisher.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/application/virtualaccount/event/DepositFailureEventHandler.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/application/virtualaccount/event/DepositSuccessEventHandler.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/application/virtualaccount/handler/DepositFailureEventHandler.java (0 hunks)
  • src/main/java/life/mosu/mosuserver/application/virtualaccount/processor/CreateVirtualAccountProcessor.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/domain/examapplication/repository/ExamApplicationJpaRepository.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/domain/examapplication/service/ExamApplicationAmountCalculator.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/domain/profile/entity/Gender.java (2 hunks)
  • src/main/java/life/mosu/mosuserver/domain/virtualaccount/VirtualAccountLogJpaEntity.java (3 hunks)
  • src/main/java/life/mosu/mosuserver/domain/virtualaccount/service/DepositEventMapper.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/global/exception/ErrorCode.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/global/filter/Whitelist.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/infra/toss/dto/TossVirtualAccountPayload.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/presentation/application/ApplicationController.java (2 hunks)
  • src/main/java/life/mosu/mosuserver/presentation/application/dto/ApplicationGuestRequest.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/presentation/virtualaccount/dto/CreateVirtualAccountRequest.java (1 hunks)
💤 Files with no reviewable changes (1)
  • src/main/java/life/mosu/mosuserver/application/virtualaccount/handler/DepositFailureEventHandler.java
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/main/java/life/mosu/mosuserver/application/virtualaccount/event/DepositFailureEventHandler.java (1)
src/main/java/life/mosu/mosuserver/presentation/virtualaccount/dto/event/DepositFailureEvent.java (1)
  • DepositFailureEvent (5-14)
src/main/java/life/mosu/mosuserver/domain/virtualaccount/service/DepositEventMapper.java (2)
src/main/java/life/mosu/mosuserver/presentation/virtualaccount/dto/event/DepositFailureEvent.java (1)
  • DepositFailureEvent (5-14)
src/main/java/life/mosu/mosuserver/presentation/virtualaccount/dto/event/DepositSuccessEvent.java (1)
  • DepositSuccessEvent (5-14)
🔇 Additional comments (22)
src/main/java/life/mosu/mosuserver/global/exception/ErrorCode.java (1)

46-46: LGTM! Error code follows established conventions.

The new USER_SAVE_FAILED error code is properly positioned within the user-related errors section and follows the established pattern with appropriate HTTP status code and descriptive Korean message.

src/main/java/life/mosu/mosuserver/application/virtualaccount/event/DepositSuccessEventHandler.java (1)

1-1: LGTM! Package reorganization improves code structure.

Moving the event handler from handler to event package is a good organizational improvement that better groups event-related components together.

src/main/java/life/mosu/mosuserver/application/virtualaccount/VirtualAccountCallbackService.java (1)

3-4: LGTM! Import statements updated correctly for package reorganization.

The import statements have been properly updated to reflect the movement of event handlers from the handler to event package, maintaining functionality while improving code organization.

src/main/java/life/mosu/mosuserver/application/application/processor/RegisterApplicationStepProcessor.java (1)

28-28: LGTM! Method access updated for improved command structure.

The change from field access to method call reflects the improved RegisterApplicationCommand structure, likely now implemented as a record. This change supports the enhanced functionality for handling multiple exam applications while maintaining clean, encapsulated access to the data.

src/main/java/life/mosu/mosuserver/application/virtualaccount/event/DepositEventHandler.java (1)

1-6: LGTM! Clean generic interface design.

The interface follows good design principles with a clear, focused responsibility and proper generic typing. The package move to event aligns well with the architectural shift to event-driven processing.

src/main/java/life/mosu/mosuserver/presentation/virtualaccount/dto/CreateVirtualAccountRequest.java (1)

3-8: LGTM! Clean DTO extension with proper field positioning.

The addition of applicationId as the first field makes logical sense for identification purposes and aligns with the requirement to link virtual accounts to applications. The record structure remains clean and well-organized.

src/main/java/life/mosu/mosuserver/domain/examapplication/repository/ExamApplicationJpaRepository.java (1)

156-163: Approval: Query and Entities Verified

LGTM! The JPQL query in ExamApplicationJpaRepository.java (lines 156–163) correctly joins on applicationId, filters by orderId, and excludes deleted records. Returning an Optional<ExamApplicationJpaEntity> is appropriate for potentially missing data.

• Confirmed VirtualAccountLogJpaEntity.applicationId is defined in
src/main/java/life/mosu/mosuserver/domain/virtualaccount/VirtualAccountLogJpaEntity.java (line 27).
• Query structure and return type are both correct.

src/main/java/life/mosu/mosuserver/infra/toss/dto/TossVirtualAccountPayload.java (1)

19-20: All ofPartnership callers updated – change approved

The search shows only one call site in CreateVirtualAccountProcessor.java and it’s passing the new amount parameter correctly. No further updates are needed.

src/main/java/life/mosu/mosuserver/application/virtualaccount/event/DepositEventPublisher.java (1)

10-21: LGTM! Well-designed event publisher.

The DepositEventPublisher follows good architectural practices:

  • Clear separation of concerns between mapping and publishing
  • Proper use of dependency injection
  • Simple, focused method implementation
  • Good encapsulation of event publishing logic
src/main/java/life/mosu/mosuserver/application/virtualaccount/VirtualAccountLogService.java (1)

23-32: Approved: All callers updated to include applicationId

Verified via an rg search that the only external invocation in
src/main/java/life/mosu/mosuserver/application/virtualaccount/processor/CreateVirtualAccountProcessor.java
already passes request.applicationId() to saveVirtualAccountLog. No other callers were found.

src/main/java/life/mosu/mosuserver/application/virtualaccount/event/DepositFailureEventHandler.java (1)

21-32: Review complete: findByOrderId exists – LGTM

Verified that ExamApplicationJpaRepository declares the method at line 163 in
src/main/java/life/mosu/mosuserver/domain/examapplication/repository/ExamApplicationJpaRepository.java:

@Query("""
    SELECT e …
      JOIN VirtualAccountLogJpaEntity v ON e.applicationId = v.applicationId
     WHERE v.orderId = :orderId
""")
Optional<ExamApplicationJpaEntity> findByOrderId(String orderId);

The DepositFailureEventHandler implementation is solid—no further changes needed.

src/main/java/life/mosu/mosuserver/domain/virtualaccount/service/DepositEventMapper.java (1)

14-23: LGTM - Clean event mapping implementation!

The switch expression correctly maps deposit event statuses to appropriate domain events. The use of static factory methods and proper exception handling for invalid statuses follows good practices.

src/main/java/life/mosu/mosuserver/domain/virtualaccount/VirtualAccountLogJpaEntity.java (2)

26-27: LGTM - Proper field addition with consistent mapping.

The new applicationId field is correctly added with proper JPA column mapping and follows the existing entity patterns.


48-62: LGTM - Constructor and factory method updated consistently.

The constructor and static factory method are properly updated to include the new applicationId parameter, maintaining consistency with the existing builder pattern.

src/main/java/life/mosu/mosuserver/application/virtualaccount/VirtualAccountService.java (1)

15-24: Excellent refactoring - improved separation of concerns!

The delegation to specialized components (CreateVirtualAccountProcessor and DepositEventPublisher) follows good design principles and improves maintainability and testability while preserving the public API.

src/main/java/life/mosu/mosuserver/application/virtualaccount/processor/CreateVirtualAccountProcessor.java (1)

30-62: Well-structured processor with good separation of concerns.

The process method clearly orchestrates the virtual account creation flow with proper error handling and clean separation of responsibilities. Each step is focused and uses appropriate services.

src/main/java/life/mosu/mosuserver/application/application/dto/RegisterApplicationCommand.java (1)

15-32: LGTM! Well-designed factory methods with good backward compatibility.

The two factory methods provide excellent flexibility - one for handling lists directly and an overloaded version that wraps a single request in a list. This design maintains backward compatibility while supporting the new multi-application feature.

src/main/java/life/mosu/mosuserver/application/application/ApplicationService.java (2)

46-54: LGTM! Good refactoring to reduce duplication.

The extraction of shared logic into handleApplication is a clean refactoring that eliminates code duplication between regular and guest application flows.


69-93: LGTM! Well-structured centralized processing logic.

The handleApplication method effectively consolidates the common application processing steps with proper validation ordering and clear separation of concerns.

src/main/java/life/mosu/mosuserver/presentation/application/dto/ApplicationGuestRequest.java (3)

65-75: LGTM! Clear subject validation with appropriate error handling.

The subject validation correctly ensures exactly 2 subjects are selected and throws a meaningful error for invalid counts.


85-93: LGTM! Secure password generation implementation.

The password generation uses SecureRandom and includes a good mix of characters (uppercase, lowercase, and digits) which provides adequate security for temporary guest passwords.


81-83: Database uniqueness constraint already in place

Verified that the login_id column on UserJpaEntity is annotated with @Column(name = "login_id", unique = true), so any UUID collision—even with an 8-character substring—will be rejected by the database.

• File: src/main/java/life/mosu/mosuserver/domain/user/entity/UserJpaEntity.java:34

@Column(name = "login_id", unique = true, length = 50)

No further changes are required unless you’d like to increase the substring length for added headroom; collisions will always be caught by the DB constraint.

Comment on lines +40 to +46
public Long saveUser(UserJpaEntity user) {
Long userId = userJpaRepository.save(user).getId();
if (userId == null) {
throw new CustomRuntimeException(ErrorCode.USER_SAVE_FAILED);
}
return userId;
}
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Consider transaction handling and verify null check necessity.

The implementation looks good, but consider these improvements:

  1. Add @Transactional annotation - This method performs a database write operation and should be transactional.
  2. Verify null check necessity - JPA repositories typically return entities with generated IDs after save. A null ID might indicate entity configuration issues rather than save failures.

Apply this diff to add transaction handling:

+    @Transactional
     public Long saveUser(UserJpaEntity user) {

Let me verify if the null ID check is actually necessary by examining the UserJpaEntity configuration:


🏁 Script executed:

#!/bin/bash
# Description: Check UserJpaEntity ID configuration to verify if null check is necessary
# Expected: Find @GeneratedValue or similar ID generation strategy

ast-grep --pattern $'@Entity
$$$
class UserJpaEntity {
  $$$
  @Id
  $$$
  Long $_id$$$;
  $$$
}'

Length of output: 98


🏁 Script executed:

#!/bin/bash
# Locate the UserJpaEntity source file and inspect its ID configuration
FILE=$(rg -l "class UserJpaEntity" --glob "*.java")
echo "UserJpaEntity file found at: $FILE"
# Show entity annotation, ID field, and any generation strategy
rg -n "@Entity" "$FILE"
rg -n "@Id" "$FILE"
rg -n "@GeneratedValue" "$FILE"

Length of output: 691


Transaction Management & Redundant Null‐Check in saveUser

The JPA entity is configured with

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)

so a non-null ID is guaranteed after a successful save(). Also, Spring Data JPA’s save() is already @Transactional. You can simplify and clarify the service method by:

Removing the redundant null check
Optionally annotating the service method with @Transactional if you plan to combine multiple repository calls in the same transaction

Locations to update:

  • File: src/main/java/life/mosu/mosuserver/application/user/UserService.java
  • Method: public Long saveUser(UserJpaEntity user)

Proposed diff:

-    public Long saveUser(UserJpaEntity user) {
-        Long userId = userJpaRepository.save(user).getId();
-        if (userId == null) {
-            throw new CustomRuntimeException(ErrorCode.USER_SAVE_FAILED);
-        }
-        return userId;
-    }
+    @Transactional  // optional if you’ll add more operations here
+    public Long saveUser(UserJpaEntity user) {
+        return userJpaRepository.save(user).getId();
+    }
🤖 Prompt for AI Agents
In src/main/java/life/mosu/mosuserver/application/user/UserService.java around
lines 40 to 46, remove the redundant null check for userId after saving the user
entity since the ID is guaranteed to be non-null by JPA. Simplify the method by
directly returning the saved user's ID. Optionally, add the @Transactional
annotation to the saveUser method if you plan to include multiple repository
operations in one transaction.

orderId, request.customerName(), request.customerEmail(), bankCode, amount
);

CreateVirtualAccountResponse response = tossClient.createVirtualAccount(payload);
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Consider adding error handling for external service calls.

The Toss client call could potentially fail due to network issues or service unavailability. Consider adding appropriate error handling or retry logic for better resilience.

Let me check if there's existing error handling in the Toss client:


🏁 Script executed:

#!/bin/bash
# Description: Check for error handling in TossVirtualAccountClient
# Expected: Find error handling or exception declarations

rg -A 10 -B 5 "class TossVirtualAccountClient" --type java
rg -A 5 "createVirtualAccount" --type java

Length of output: 3465


Add error handling and resilience around the Toss API call

The createVirtualAccount invocation in CreateVirtualAccountProcessor currently lets any RestClientException (or underlying HTTP errors) bubble up. We should wrap this call to:

  • Catch and log failures from tossClient.createVirtualAccount(payload)
  • Apply retry logic (e.g. Spring Retry) or fallback behavior
  • Surface a clear, domain‐specific exception if all retries fail

Locations to update:

  • src/main/java/life/mosu/mosuserver/application/virtualaccount/processor/CreateVirtualAccountProcessor.java:47

Suggested diff:

-        CreateVirtualAccountResponse response = tossClient.createVirtualAccount(payload);
+        CreateVirtualAccountResponse response;
+        try {
+            response = tossClient.createVirtualAccount(payload);
+        } catch (RestClientException ex) {
+            log.error("Failed to create Toss virtual account (applicationId={}, orderId={})",
+                      request.applicationId(), orderId, ex);
+            // TODO: retry or fallback logic here (e.g. Spring Retry)
+            throw new VirtualAccountCreationException(
+                "Could not create Toss virtual account", ex);
+        }
📝 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
CreateVirtualAccountResponse response = tossClient.createVirtualAccount(payload);
CreateVirtualAccountResponse response;
try {
response = tossClient.createVirtualAccount(payload);
} catch (RestClientException ex) {
log.error("Failed to create Toss virtual account (applicationId={}, orderId={})",
request.applicationId(), orderId, ex);
// TODO: retry or fallback logic here (e.g. Spring Retry)
throw new VirtualAccountCreationException(
"Could not create Toss virtual account", ex);
}
🤖 Prompt for AI Agents
In
src/main/java/life/mosu/mosuserver/application/virtualaccount/processor/CreateVirtualAccountProcessor.java
at line 47, the call to tossClient.createVirtualAccount(payload) lacks error
handling and resilience. Wrap this call in a try-catch block to catch
RestClientException, log the error details, and implement retry logic using
Spring Retry or a similar mechanism. If all retries fail, throw a clear,
domain-specific exception to indicate the failure to create a virtual account.

@polyglot-k polyglot-k merged commit e461efd into develop Aug 6, 2025
2 of 3 checks 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