Skip to content

MOSU-123 refactor: 설계 변경으로 인한 관리자 기능 변경#125

Merged
wlgns12370 merged 6 commits intodevelopfrom
refactor/mosu-123
Jul 22, 2025
Merged

MOSU-123 refactor: 설계 변경으로 인한 관리자 기능 변경#125
wlgns12370 merged 6 commits intodevelopfrom
refactor/mosu-123

Conversation

@wlgns12370
Copy link
Contributor

@wlgns12370 wlgns12370 commented Jul 22, 2025

✨ 구현한 기능

  • 설계 변경으로 인한 관리자 기능 변경

📢 논의하고 싶은 내용

  • x

🎸 기타

  • x

Summary by CodeRabbit

  • New Features

    • Admin panel endpoints now return real data for student lists, applications, and school lunch counts.
    • Added Excel export for student and application lists from the admin panel.
    • New endpoint for refund data added (currently in development).
    • Enhanced API documentation for admin endpoints.
    • Added static factory method for school lunch response creation.
  • Refactor

    • Major shift from a school-centric to an exam-centric data model across application, payment, and refund management.
    • Initialization logic updated to generate exam-based demo data instead of school-based.
    • Several admin DTOs and records updated for improved clarity and data representation.
    • Admin service class uncommented and integrated into controller.
    • Changed data types for lunch selection and related fields from ID to boolean flag.
    • Updated payment and refund entity fields to align with exam-centric model.
    • Refactored admin DTOs to use Java records for conciseness.
    • Adjusted subject collections from lists of objects to sets of subject names.
  • Bug Fixes

    • Lunch selection is now handled as a boolean flag instead of an ID, ensuring more accurate data capture.
  • Style/Documentation

    • Improved API documentation and schema descriptions for admin endpoints and filters.
    • Removed phone number pattern validations from filters and updated example formats.

@coderabbitai
Copy link

coderabbitai bot commented Jul 22, 2025

Walkthrough

This update migrates the admin, application, payment, refund, and initialization modules from a school/application-centric model to an exam/exam-application-centric model. It replaces lunch selection from an ID to a boolean, updates DTOs, queries, and entity relationships, and refactors the database initializer and admin controller/services to match the new domain structure.

Changes

Files/Groups Change Summary
.../application/admin/AdminService.java, .../domain/admin/RefundQueryRepositoryImpl.java Uncommented and re-enabled; updated to new exam-centric domain and repository structure.
.../application/examapplication/ExamApplicationService.java, .../dto/ExamTicketResponse.java Changed subject collection from List to Set; updated mapping and imports accordingly.
.../application/examapplication/dto/RegisterExamApplicationEvent.java, .../application/dto/ExamApplicationRequest.java Changed lunch selection from Long lunchId to boolean isLunchChecked; updated mapping and method signatures.
.../domain/admin/ApplicationQueryRepositoryImpl.java Fully refactored: queries and mappings now use exam/exam-application domain; removed school-centric logic.
.../domain/payment/PaymentJpaEntity.java, .../application/payment/PaymentFailureHandler.java Changed applicationSchoolId to applicationId throughout; updated field names and mapping logic.
.../domain/examapplication/ExamApplicationJpaEntity.java Replaced lunchId field with boolean isLunchChecked; updated constructors and factory methods.
.../domain/refund/RefundJpaEntity.java Renamed applicationSchoolId to examApplicationId; updated column names and constructor.
.../global/initializer/DatabaseInitializer.java Completely rewritten to initialize exam/exam-application-centric data; removed school-centric logic.
.../presentation/admin/AdminController.java Activated service calls; integrated AdminService; enabled actual data retrieval and Excel export.
.../presentation/admin/AdminControllerDocs.java Updated API docs, summaries, and parameter descriptions; added refund count endpoint.
.../presentation/admin/dto/ApplicationExcelDto.java Refactored from class to record; same fields and annotations, new concise syntax.
.../presentation/admin/dto/ApplicationFilter.java, .../dto/StudentFilter.java Removed @PhoneNumberPattern from phone fields; updated schema examples/descriptions.
.../presentation/admin/dto/ApplicationListResponse.java Changed lunch field type from String to Boolean.
.../presentation/admin/dto/SchoolLunchResponse.java Added static factory method of for instantiation.

Sequence Diagram(s)

sequenceDiagram
    participant AdminController
    participant AdminService
    participant ApplicationQueryRepo
    participant RefundQueryRepo
    participant PaymentRepo
    participant ExamApplicationRepo

    AdminController->>AdminService: getApplications(filter, pageable)
    AdminService->>ApplicationQueryRepo: searchAllApplications(filter, pageable)
    ApplicationQueryRepo->>ExamApplicationRepo: query exam applications
    ExamApplicationRepo-->>ApplicationQueryRepo: exam application data
    ApplicationQueryRepo-->>AdminService: application responses
    AdminService-->>AdminController: application responses

    AdminController->>AdminService: getLunchCounts()
    AdminService->>ApplicationQueryRepo: searchAllSchoolLunches()
    ApplicationQueryRepo->>ExamApplicationRepo: query lunch counts
    ExamApplicationRepo-->>ApplicationQueryRepo: lunch count data
    ApplicationQueryRepo-->>AdminService: lunch count responses
    AdminService-->>AdminController: lunch count responses

    AdminController->>AdminService: getRefundCounts(pageable)
    AdminService->>RefundQueryRepo: searchAllRefunds(pageable)
    RefundQueryRepo->>ExamApplicationRepo: query refund data
    ExamApplicationRepo-->>RefundQueryRepo: refund data
    RefundQueryRepo-->>AdminService: refund responses
    AdminService-->>AdminController: refund responses
Loading

Estimated code review effort

4 (~90 minutes)

Possibly related PRs

  • #74: Modifies PaymentFailureHandler to use getApplicationSchoolId() instead of getApplicationId(), directly related to the current PR's changes in the same class and method.
  • #60: Introduced and extended AdminService with application query methods, which this PR now fully activates and adapts.
  • #81: Adds refund query functionality and refund methods to AdminService, extending the service that this PR reactivates.

Suggested reviewers

  • jbh010204
  • chominju02

Poem

In fields of code where rabbits roam,
We hopped from schools to exams as home.
Lunch is now a simple choice,
Boolean flags—no longer a voice!
DTOs and queries realigned,
Spring’s new flow, robustly designed.
🥕 Cheers to code, refactored fine!


📜 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 3539a3f and 2fb3b00.

📒 Files selected for processing (1)
  • src/main/java/life/mosu/mosuserver/presentation/admin/dto/ApplicationListResponse.java (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/main/java/life/mosu/mosuserver/presentation/admin/dto/ApplicationListResponse.java
✨ Finishing Touches
  • 📝 Generate Docstrings

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.
    • @coderabbitai modularize this function.
  • 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.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

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

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

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 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.

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 @wlgns12370, 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 implements a major architectural change by refactoring the core domain model related to exam applications, payments, and refunds. The primary goal is to align the system with a new design, which involved updating database entities, query repositories, service logic, and API endpoints. This ensures that the administrative functionalities operate correctly and efficiently with the revised data structure.

Highlights

  • Core Data Model Refactoring: The underlying data model for exam applications, payments, and refunds has been significantly refactored. This includes migrating from an ApplicationSchool centric model to a new structure centered around ExamApplication and Exam entities. Payments and refunds are now directly linked to Application and ExamApplication respectively.
  • Admin Functionality Activation and Update: Previously commented-out admin service logic and API endpoints have been activated and updated to reflect the new data model. This enables full functionality for retrieving student lists, application details, school lunch counts, and refund information through the admin panel.
  • Simplified Lunch Option Handling: The handling of lunch options during exam application has been simplified from using a lunchId (presumably an ID for a specific lunch option) to a straightforward boolean isLunchChecked, indicating whether lunch is selected or not.
  • Data Initialization Overhaul: The database initializer has been completely rewritten to populate dummy data that aligns with the new Exam, ExamApplication, and Payment entities, ensuring consistency with the updated design.
  • API Documentation and DTO Adjustments: API documentation (Swagger/OpenAPI) and various Data Transfer Objects (DTOs) have been updated to match the refactored data structures and endpoint behaviors, including changes to ApplicationExcelDto, ApplicationListResponse, and ExamTicketResponse.
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 a significant refactoring of the domain model, moving from a School-based application structure to an Exam-based one. This impacts entities like Application, Payment, and Refund, and introduces new entities like ExamApplication and ExamSubject. The admin-facing services, controllers, and queries have been updated accordingly to reflect these design changes. The changes are extensive and generally move towards a more normalized and flexible data model. However, I've found a couple of critical issues in the new QueryDSL implementations in ApplicationQueryRepositoryImpl and RefundQueryRepositoryImpl that will cause runtime errors due to incorrect join conditions or incomplete queries. There are also some medium-severity suggestions for improving code quality and ensuring input validation. Please address the critical issues before merging.

.from(examApplication)
.leftJoin(exam).on(examApplication.examId.eq(exam.id))
.leftJoin(application).on(examApplication.applicationId.eq(application.id))
.leftJoin(payment).on(payment.applicationId.eq(examApplication.id))

Choose a reason for hiding this comment

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

critical

The join condition for the payment table appears to be incorrect. It's currently joining on payment.applicationId.eq(examApplication.id). Based on the data model, payment.applicationId stores the ID of an ApplicationJpaEntity, but it's being compared with examApplication.id, which is the ID of an ExamApplicationJpaEntity. This will likely result in incorrect data or no data being fetched for payments.

The join should be made against application.id.

Suggested change
.leftJoin(payment).on(payment.applicationId.eq(examApplication.id))
.leftJoin(payment).on(payment.applicationId.eq(application.id))

refund.createdAt,
refund.agreedAt,
// payment.paymentMethod,
refund.reason

Choose a reason for hiding this comment

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

critical

The query is missing a join to the payment table, and payment.paymentMethod is commented out in the select clause. This will cause tuple.get(payment.paymentMethod) to fail. Although there is a TODO comment, this code is currently broken and should be fixed before merging. Please add the join to the payment table and include payment.paymentMethod in the selection.

        return queryFactory
                .select(
                        refund.id,
                        examApplication.examNumber,
                        profile.userName,
                        profile.phoneNumber,
                        refund.createdAt,
                        refund.agreedAt,
                        payment.paymentMethod,
                        refund.reason
                )
                .from(refund)
                .leftJoin(examApplication).on(refund.examApplicationId.eq(examApplication.id))
                .leftJoin(application).on(examApplication.applicationId.eq(application.id))
                .leftJoin(profile).on(profile.userId.eq(application.userId))
                .leftJoin(payment).on(payment.applicationId.eq(application.id));

.examNumber(String.format("MOSU-%d-%d", application.getId(),
exam.getId()))
.isLunchChecked(
((j % 2 == 0) ? true : false)

Choose a reason for hiding this comment

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

medium

This boolean assignment can be simplified for better readability. The ternary operator (condition ? true : false) is redundant and can be replaced by the condition itself.

                                .isLunchChecked(j % 2 == 0)

Comment on lines +12 to 13
@Schema(description = "전화번호 필터", example = "010-1234-5678")
String phone,

Choose a reason for hiding this comment

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

medium

The @PhoneNumberPattern validation annotation has been removed from the phone field. Was this intentional? Removing it might weaken input validation and allow incorrectly formatted phone numbers to be processed. If validation is still required, please consider re-adding it or ensuring it's handled elsewhere.

Comment on lines 11 to 12
@Schema(description = "전화번호 필터", example = "01012345678")
@PhoneNumberPattern
String phone,

Choose a reason for hiding this comment

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

medium

Similar to ApplicationFilter, the @PhoneNumberPattern validation annotation has been removed from the phone field. Could you please confirm if this was intentional? This change could affect input validation for phone numbers.

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

🔭 Outside diff range comments (1)
src/main/java/life/mosu/mosuserver/application/payment/PaymentFailureHandler.java (1)

25-39: Fix inconsistent variable naming and verify event parameter alignment.

The variable naming suggests a mismatch with the domain model changes:

  1. missingAppSchoolIds should be renamed to missingAppIds since it now contains application IDs, not school IDs
  2. The event method applicationSchoolIds() and parameter name appSchoolId suggest they still reference school IDs, which may be inconsistent with the new domain model

Verify that the event structure has been updated to match the new domain model:

-        List<Long> missingAppSchoolIds = event.applicationSchoolIds().stream()
-                .filter(appSchoolId -> !existingAppIds.contains(appSchoolId))
+        List<Long> missingAppIds = event.applicationIds().stream()
+                .filter(appId -> !existingAppIds.contains(appId))
                 .toList();

         // 실패 신규 엔티티 생성 ( 배치 후속 처리 필요 )
-        List<PaymentJpaEntity> newPayments = missingAppSchoolIds.stream()
-                .map(appSchoolId -> PaymentJpaEntity.ofFailure(
-                        appSchoolId,
+        List<PaymentJpaEntity> newPayments = missingAppIds.stream()
+                .map(appId -> PaymentJpaEntity.ofFailure(
+                        appId,
                         event.orderId(),
                         event.status(),
                         event.totalAmount()))
                 .toList();
🧹 Nitpick comments (2)
src/main/java/life/mosu/mosuserver/presentation/admin/dto/ApplicationFilter.java (1)

12-12: LGTM - Improved phone number format, but consider consistency across DTOs.

The change to hyphenated phone number format ("010-1234-5678") improves readability. However, there's an inconsistency with other DTOs like StudentExcelDto (line 15 in src/main/java/life/mosu/mosuserver/presentation/admin/dto/StudentExcelDto.java) which still uses the unhyphenated format ("01012345678").

Consider standardizing the phone number format across all DTOs for consistency:

// In StudentExcelDto.java
@Schema(description = "전화번호", example = "010-1234-5678")
src/main/java/life/mosu/mosuserver/presentation/admin/dto/StudentFilter.java (1)

14-15: Track completion of sorting functionality

The schema description change to "개발중" (in development) indicates the sorting feature is incomplete. Ensure this is tracked and completed as part of the refactoring effort.

Consider creating a TODO or tracking issue for completing the sorting functionality to avoid leaving it in an incomplete state.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between c889967 and ea79857.

📒 Files selected for processing (19)
  • src/main/java/life/mosu/mosuserver/application/admin/AdminService.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/application/examapplication/ExamApplicationService.java (3 hunks)
  • src/main/java/life/mosu/mosuserver/application/examapplication/dto/RegisterExamApplicationEvent.java (2 hunks)
  • src/main/java/life/mosu/mosuserver/application/payment/PaymentFailureHandler.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/domain/admin/ApplicationQueryRepositoryImpl.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/domain/admin/RefundQueryRepositoryImpl.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/domain/examapplication/ExamApplicationJpaEntity.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/domain/payment/PaymentJpaEntity.java (4 hunks)
  • src/main/java/life/mosu/mosuserver/domain/refund/RefundJpaEntity.java (3 hunks)
  • src/main/java/life/mosu/mosuserver/global/initializer/DatabaseInitializer.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/presentation/admin/AdminController.java (4 hunks)
  • src/main/java/life/mosu/mosuserver/presentation/admin/AdminControllerDocs.java (3 hunks)
  • src/main/java/life/mosu/mosuserver/presentation/admin/dto/ApplicationExcelDto.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/presentation/admin/dto/ApplicationFilter.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/presentation/admin/dto/ApplicationListResponse.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/presentation/admin/dto/ExamTicketResponse.java (3 hunks)
  • src/main/java/life/mosu/mosuserver/presentation/admin/dto/SchoolLunchResponse.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/presentation/admin/dto/StudentFilter.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/presentation/application/dto/ExamApplicationRequest.java (1 hunks)
🧬 Code Graph Analysis (3)
src/main/java/life/mosu/mosuserver/presentation/admin/dto/ApplicationFilter.java (1)
src/main/java/life/mosu/mosuserver/presentation/admin/dto/StudentExcelDto.java (1)
  • Schema (8-45)
src/main/java/life/mosu/mosuserver/presentation/admin/dto/ApplicationExcelDto.java (1)
src/main/java/life/mosu/mosuserver/presentation/admin/dto/StudentExcelDto.java (1)
  • Schema (8-45)
src/main/java/life/mosu/mosuserver/domain/refund/RefundJpaEntity.java (2)
src/main/java/life/mosu/mosuserver/domain/payment/PaymentJpaEntity.java (1)
  • Entity (18-102)
src/main/java/life/mosu/mosuserver/domain/application/ApplicationJpaEntity.java (1)
  • Entity (15-52)
🧰 Additional context used
🧬 Code Graph Analysis (3)
src/main/java/life/mosu/mosuserver/presentation/admin/dto/ApplicationFilter.java (1)
src/main/java/life/mosu/mosuserver/presentation/admin/dto/StudentExcelDto.java (1)
  • Schema (8-45)
src/main/java/life/mosu/mosuserver/presentation/admin/dto/ApplicationExcelDto.java (1)
src/main/java/life/mosu/mosuserver/presentation/admin/dto/StudentExcelDto.java (1)
  • Schema (8-45)
src/main/java/life/mosu/mosuserver/domain/refund/RefundJpaEntity.java (2)
src/main/java/life/mosu/mosuserver/domain/payment/PaymentJpaEntity.java (1)
  • Entity (18-102)
src/main/java/life/mosu/mosuserver/domain/application/ApplicationJpaEntity.java (1)
  • Entity (15-52)
🔇 Additional comments (29)
src/main/java/life/mosu/mosuserver/application/payment/PaymentFailureHandler.java (1)

22-22: LGTM - Consistent with domain model changes.

The change from getApplicationSchoolId() to getApplicationId() aligns with the broader domain model refactoring from school-centric to exam-centric model.

src/main/java/life/mosu/mosuserver/presentation/admin/dto/SchoolLunchResponse.java (1)

16-19: LGTM - Clean factory method implementation.

The static factory method follows standard Java conventions and provides a clean way to create instances of the record. The implementation is straightforward and appropriate for a simple DTO.

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

4-5: LGTM - Appropriate imports for the collection type changes.

The import additions support the new Set collection type and stream operations used in the updated subject handling logic.


63-65: LGTM - Improved subject representation.

The change from List<Subject> to Set<String> provides several benefits:

  • Prevents duplicate subjects in the response
  • Simplifies the DTO by using string names instead of full domain objects
  • Reduces coupling between service and domain layers

The mapping logic correctly extracts subject names from the domain entities.

src/main/java/life/mosu/mosuserver/presentation/application/dto/ExamApplicationRequest.java (2)

7-7: LGTM: Clean domain model simplification

The change from Long lunchId to boolean isLunchChecked appropriately simplifies the lunch selection from a specific ID reference to a boolean flag, aligning with the exam-centric domain model refactoring.


10-12: LGTM: Method correctly updated for new parameter

The toTargetExam() method properly passes the new boolean parameter, maintaining consistency with the domain model changes.

src/main/java/life/mosu/mosuserver/presentation/admin/dto/ExamTicketResponse.java (3)

5-5: LGTM: Appropriate import update

Import correctly updated from List to Set to support the field type change.


21-21: LGTM: Set usage is semantically correct for subjects

Changing from List<Subject> to Set<String> is a good design decision:

  • Set prevents duplicate subjects, which is semantically correct
  • String representation simplifies the DTO by removing domain object dependencies
  • Aligns with the exam-centric domain model refactoring

32-32: LGTM: Factory method parameter updated consistently

The static factory method parameter correctly matches the field type change to Set<String>.

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

21-28: LGTM: Proper Spring service configuration

Good use of Spring annotations and constructor-based dependency injection. The service properly declares its dependencies on the query repository implementations.


30-55: LGTM: Clean delegation pattern

The service methods appropriately delegate to specialized repository implementations. While the service layer is thin, it provides a good abstraction that allows for future business logic addition without changing the controller interface.

src/main/java/life/mosu/mosuserver/presentation/admin/dto/ApplicationExcelDto.java (2)

11-31: LGTM: Good modernization to Java record

The conversion from a traditional class to a record is a good modernization that:

  • Eliminates boilerplate code (constructors, getters, equals, hashCode)
  • Maintains all necessary annotations for schema documentation and Excel export
  • Preserves field semantics and types appropriately

The inline annotations are acceptable for a DTO, though they create longer lines.


22-23: Excel generation logic verified

The lunch and subjects fields are correctly handled in ApplicationQueryRepositoryImpl.mapToExcel(...):

  • lunchName is retrieved via tuple.get(exam.lunchName) and passed as the DTO’s lunch String.
  • subjects are converted from Set<Subject> to Set<String> via subjects.stream().map(Subject::getSubjectName).collect(...).

No further changes are required.

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

30-31: LGTM: Lunch field simplification is well-designed.

The change from Long lunchId to boolean isLunchChecked simplifies the lunch selection model and makes the intent clearer. The column mapping to lunch_checked is appropriate.

src/main/java/life/mosu/mosuserver/presentation/admin/AdminController.java (5)

36-36: LGTM: Service dependency properly injected.

The AdminService dependency is correctly injected using constructor injection with @RequiredArgsConstructor.


42-45: LGTM: Service integration and pagination defaults.

The service integration is properly implemented and the default page size of 10 is reasonable for admin interfaces.


59-64: LGTM: Excel download functionality well-implemented.

The Excel download implementation is clean and follows good practices:

  • Proper content type and encoding handling
  • Correct use of SimpleExcelFile with generic type
  • Direct streaming to response output

94-99: LGTM: Consistent Excel implementation pattern.

The application Excel download follows the same well-structured pattern as the student Excel download.


103-109: Complete the refund endpoint implementation.

The refund endpoint still has the service call commented out and returns null data, making it incomplete compared to other endpoints.

Should this endpoint be fully implemented as part of this PR, or is it intentionally left as a stub for future implementation?

src/main/java/life/mosu/mosuserver/application/examapplication/dto/RegisterExamApplicationEvent.java (3)

17-17: LGTM: Consistent mapping of boolean lunch selection.

The update to map isLunchChecked instead of lunchId is consistent with the entity changes and maintains proper data flow.


27-27: LGTM: Entity creation properly updated.

The toEntity() method correctly passes the boolean isLunchChecked value to the entity creation method.


32-35: LGTM: TargetExam record updated consistently.

The nested TargetExam record properly reflects the change from Long lunchId to boolean isLunchChecked, maintaining consistency across the domain model.

src/main/java/life/mosu/mosuserver/domain/refund/RefundJpaEntity.java (3)

27-28: LGTM: Field renaming aligns with domain model changes.

The renaming from applicationSchoolId to examApplicationId is consistent with the broader refactoring to an exam-centric domain model.


30-31: LGTM: Simplified column naming.

The column name change from refund_reason to reason simplifies the naming convention while maintaining clarity.


40-50: Verify database migration scripts for column renames

I couldn’t locate any migrations that rename the old columns (application_school_idexam_application_id, refund_reasonreason). Please ensure your database migration includes these changes. For example, check under src/main/resources/db/migration (or wherever migrations live) for a script like:

  • ALTER TABLE refund RENAME COLUMN application_school_id TO exam_application_id;
  • ALTER TABLE refund RENAME COLUMN refund_reason TO reason;
src/main/java/life/mosu/mosuserver/domain/payment/PaymentJpaEntity.java (4)

29-30: LGTM: Consistent field renaming.

The renaming from applicationSchoolId to applicationId improves clarity and aligns with the domain model refactoring. The column mapping remaining as application_id maintains database compatibility.


51-58: LGTM: Constructor properly updated.

The constructor parameter and field assignment are consistently updated to use the new applicationId name.


67-82: LGTM: Static factory methods updated consistently.

Both the parameter name and builder method call are properly updated to use applicationId throughout the of method.


85-97: LGTM: Failure factory method updated consistently.

The ofFailure method is also properly updated with the new parameter name and builder method call.

Comment on lines +56 to +78
public Page<ApplicationListResponse> searchAllApplications(ApplicationFilter filter,
Pageable pageable) {

JPAQuery<Tuple> query = baseQuery()
.where(
buildNameCondition(filter.name()),
buildPhoneCondition(filter.phone())
)
.offset(pageable.getOffset())
.limit(pageable.getPageSize());

List<ApplicationListResponse> content = query.fetch().stream()
.map(tuple -> {
Long appSchoolId = tuple.get(examApplication.id);
Set<Subject> subjects = appSchoolId != null
? findSubjectsByExamApplicationId(appSchoolId)
: new HashSet<>();
return mapToResponse(tuple, subjects);
})
.toList();

return new PageImpl<>(content, pageable, content.size());
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Incorrect pagination total count

The total count is calculated incorrectly, using the page size instead of the actual total count from the database.

Calculate the total count properly:

     public Page<ApplicationListResponse> searchAllApplications(ApplicationFilter filter,
             Pageable pageable) {
+        long total = baseQuery()
+                .where(
+                        buildNameCondition(filter.name()),
+                        buildPhoneCondition(filter.phone())
+                )
+                .fetchCount();

         JPAQuery<Tuple> query = baseQuery()
                 .where(
                         buildNameCondition(filter.name()),
                         buildPhoneCondition(filter.phone())
                 )
                 .offset(pageable.getOffset())
                 .limit(pageable.getPageSize());

         List<ApplicationListResponse> content = query.fetch().stream()
                 .map(tuple -> {
                     Long appSchoolId = tuple.get(examApplication.id);
                     Set<Subject> subjects = appSchoolId != null
                             ? findSubjectsByExamApplicationId(appSchoolId)
                             : new HashSet<>();
                     return mapToResponse(tuple, subjects);
                 })
                 .toList();

-        return new PageImpl<>(content, pageable, content.size());
+        return new PageImpl<>(content, pageable, total);
     }
📝 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
public Page<ApplicationListResponse> searchAllApplications(ApplicationFilter filter,
Pageable pageable) {
JPAQuery<Tuple> query = baseQuery()
.where(
buildNameCondition(filter.name()),
buildPhoneCondition(filter.phone())
)
.offset(pageable.getOffset())
.limit(pageable.getPageSize());
List<ApplicationListResponse> content = query.fetch().stream()
.map(tuple -> {
Long appSchoolId = tuple.get(examApplication.id);
Set<Subject> subjects = appSchoolId != null
? findSubjectsByExamApplicationId(appSchoolId)
: new HashSet<>();
return mapToResponse(tuple, subjects);
})
.toList();
return new PageImpl<>(content, pageable, content.size());
}
public Page<ApplicationListResponse> searchAllApplications(ApplicationFilter filter,
Pageable pageable) {
long total = baseQuery()
.where(
buildNameCondition(filter.name()),
buildPhoneCondition(filter.phone())
)
.fetchCount();
JPAQuery<Tuple> query = baseQuery()
.where(
buildNameCondition(filter.name()),
buildPhoneCondition(filter.phone())
)
.offset(pageable.getOffset())
.limit(pageable.getPageSize());
List<ApplicationListResponse> content = query.fetch().stream()
.map(tuple -> {
Long appSchoolId = tuple.get(examApplication.id);
Set<Subject> subjects = appSchoolId != null
? findSubjectsByExamApplicationId(appSchoolId)
: new HashSet<>();
return mapToResponse(tuple, subjects);
})
.toList();
return new PageImpl<>(content, pageable, total);
}
🤖 Prompt for AI Agents
In
src/main/java/life/mosu/mosuserver/domain/admin/ApplicationQueryRepositoryImpl.java
around lines 56 to 78, the pagination total count is incorrectly set to the
current page size instead of the actual total number of records. Fix this by
executing a separate count query that matches the filtering conditions to get
the total count from the database, and use that count value when constructing
the PageImpl object instead of content.size().

Comment on lines +217 to +249
private ApplicationExcelDto mapToExcel(Tuple tuple, Set<Subject> subjects) {
Set<String> subjectNames = subjects.stream()
.map(Subject::getSubjectName)
.collect(Collectors.toSet());

String lunchName = tuple.get(exam.lunchName);
String genderName = tuple.get(profile.gender).getGenderName();
String gradeName = tuple.get(profile.grade).getGradeName();
String educationName = tuple.get(profile.education).getEducationName();
String appliedAt = tuple.get(application.createdAt)
.format(EXCEL_DT_FORMATTER);

return new ApplicationExcelDto(
tuple.get(payment.paymentKey),
tuple.get(examApplication.examNumber),
tuple.get(profile.userName),
genderName,
tuple.get(profile.birth),
tuple.get(profile.phoneNumber),
tuple.get(application.parentPhoneNumber),
educationName,
tuple.get(profile.schoolInfo.schoolName),
gradeName,
lunchName,
subjectNames,
tuple.get(exam.schoolName),
tuple.get(exam.examDate),
tuple.get(examTicketImage.fileName),
tuple.get(payment.paymentStatus),
tuple.get(payment.paymentMethod),
appliedAt
);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Missing exam.lunchName in query selection

The mapToExcel method accesses exam.lunchName but it's not selected in the base query.

Add exam.lunchName to the select clause in baseQuery:

                 .select(
                         examApplication.id,
                         payment.paymentKey,
                         examApplication.examNumber,
                         profile.userName,
                         profile.gender,
                         profile.birth,
                         profile.phoneNumber,
                         application.parentPhoneNumber,
                         profile.education,
                         profile.schoolInfo.schoolName,
                         profile.grade,
                         exam.schoolName,
                         exam.examDate,
+                        exam.lunchName,
                         examApplication.isLunchChecked,
                         examTicketImage.s3Key,
                         examTicketImage.fileName,
                         payment.paymentStatus,
                         payment.paymentMethod,
                         application.createdAt
                 )
🤖 Prompt for AI Agents
In
src/main/java/life/mosu/mosuserver/domain/admin/ApplicationQueryRepositoryImpl.java
around lines 217 to 249, the mapToExcel method uses exam.lunchName but this
field is not included in the base query's select clause. To fix this, add
exam.lunchName to the select clause of the baseQuery so that it is fetched and
available in the tuple passed to mapToExcel.


@Override
public Page<RefundListResponse> searchAllRefunds(Pageable pageable) {
long total = baseQuery().fetch().size();
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Inefficient total count calculation

The current implementation fetches all records just to count them, which is inefficient for large datasets.

Use a dedicated count query instead:

-        long total = baseQuery().fetch().size();
+        long total = baseQuery().fetchCount();
📝 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
long total = baseQuery().fetch().size();
long total = baseQuery().fetchCount();
🤖 Prompt for AI Agents
In
src/main/java/life/mosu/mosuserver/domain/admin/RefundQueryRepositoryImpl.java
at line 36, replace the current total count calculation that fetches all records
and then counts them with a more efficient dedicated count query method. Use a
query that directly returns the count of records without fetching the entire
dataset to improve performance on large data sets.

Comment on lines +50 to +67
private JPAQuery<Tuple> baseQuery() {
return queryFactory
.select(
refund.id,
examApplication.examNumber,
profile.userName,
profile.phoneNumber,
refund.createdAt,
refund.agreedAt,
// payment.paymentMethod,
refund.reason
)
.from(refund)
.leftJoin(examApplication).on(refund.examApplicationId.eq(examApplication.id))
.leftJoin(application).on(examApplication.applicationId.eq(application.id))
.leftJoin(profile).on(profile.userId.eq(application.userId));
//TODO: payment method join
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Missing payment join causes NullPointerException

The query doesn't join with the payment table, but mapToResponse attempts to access payment.paymentMethod from the tuple, which will result in a NullPointerException.

Either add the payment join or remove the payment method from the select and response:

                .from(refund)
                .leftJoin(examApplication).on(refund.examApplicationId.eq(examApplication.id))
                .leftJoin(application).on(examApplication.applicationId.eq(application.id))
-               .leftJoin(profile).on(profile.userId.eq(application.userId));
-        //TODO: payment method join
+               .leftJoin(profile).on(profile.userId.eq(application.userId))
+               .leftJoin(payment).on(payment.applicationId.eq(application.id));
📝 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
private JPAQuery<Tuple> baseQuery() {
return queryFactory
.select(
refund.id,
examApplication.examNumber,
profile.userName,
profile.phoneNumber,
refund.createdAt,
refund.agreedAt,
// payment.paymentMethod,
refund.reason
)
.from(refund)
.leftJoin(examApplication).on(refund.examApplicationId.eq(examApplication.id))
.leftJoin(application).on(examApplication.applicationId.eq(application.id))
.leftJoin(profile).on(profile.userId.eq(application.userId));
//TODO: payment method join
}
private JPAQuery<Tuple> baseQuery() {
return queryFactory
.select(
refund.id,
examApplication.examNumber,
profile.userName,
profile.phoneNumber,
refund.createdAt,
refund.agreedAt,
// payment.paymentMethod,
refund.reason
)
.from(refund)
.leftJoin(examApplication).on(refund.examApplicationId.eq(examApplication.id))
.leftJoin(application).on(examApplication.applicationId.eq(application.id))
.leftJoin(profile).on(profile.userId.eq(application.userId))
.leftJoin(payment).on(payment.applicationId.eq(application.id));
}
🤖 Prompt for AI Agents
In
src/main/java/life/mosu/mosuserver/domain/admin/RefundQueryRepositoryImpl.java
between lines 50 and 67, the query selects paymentMethod but does not join the
payment table, causing a NullPointerException when accessing paymentMethod in
mapToResponse. Fix this by adding a left join to the payment table on the
appropriate key and include payment.paymentMethod in the select clause, or
alternatively remove payment.paymentMethod from both the select clause and the
response mapping to avoid referencing a missing join.

Comment on lines +69 to +81
private RefundListResponse mapToResponse(Tuple tuple) {
PaymentMethod paymentMethod = tuple.get(payment.paymentMethod);
return new RefundListResponse(
tuple.get(refund.id),
tuple.get(examApplication.examNumber),
tuple.get(profile.userName),
tuple.get(profile.phoneNumber),
formatDate(tuple.get(refund.createdAt)),
formatDate(tuple.get(refund.agreedAt)),
paymentMethod != null ? paymentMethod.getName() : "N/A",
tuple.get(refund.reason)
);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Remove unnecessary payment method retrieval

Since payment.paymentMethod is not selected in the query, this line will always return null or throw an exception.

Remove the unnecessary retrieval and directly use "N/A":

     private RefundListResponse mapToResponse(Tuple tuple) {
-        PaymentMethod paymentMethod = tuple.get(payment.paymentMethod);
         return new RefundListResponse(
                 tuple.get(refund.id),
                 tuple.get(examApplication.examNumber),
                 tuple.get(profile.userName),
                 tuple.get(profile.phoneNumber),
                 formatDate(tuple.get(refund.createdAt)),
                 formatDate(tuple.get(refund.agreedAt)),
-                paymentMethod != null ? paymentMethod.getName() : "N/A",
+                "N/A", // TODO: Implement payment method retrieval
                 tuple.get(refund.reason)
         );
     }
📝 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
private RefundListResponse mapToResponse(Tuple tuple) {
PaymentMethod paymentMethod = tuple.get(payment.paymentMethod);
return new RefundListResponse(
tuple.get(refund.id),
tuple.get(examApplication.examNumber),
tuple.get(profile.userName),
tuple.get(profile.phoneNumber),
formatDate(tuple.get(refund.createdAt)),
formatDate(tuple.get(refund.agreedAt)),
paymentMethod != null ? paymentMethod.getName() : "N/A",
tuple.get(refund.reason)
);
}
private RefundListResponse mapToResponse(Tuple tuple) {
return new RefundListResponse(
tuple.get(refund.id),
tuple.get(examApplication.examNumber),
tuple.get(profile.userName),
tuple.get(profile.phoneNumber),
formatDate(tuple.get(refund.createdAt)),
formatDate(tuple.get(refund.agreedAt)),
"N/A", // TODO: Implement payment method retrieval
tuple.get(refund.reason)
);
}
🤖 Prompt for AI Agents
In
src/main/java/life/mosu/mosuserver/domain/admin/RefundQueryRepositoryImpl.java
between lines 69 and 81, the code attempts to retrieve payment.paymentMethod
from the tuple, but this field is not selected in the query, causing it to
always be null or throw an exception. Remove the retrieval of paymentMethod from
the tuple and replace the conditional expression with a direct use of the string
"N/A" in the RefundListResponse constructor.

Comment on lines +37 to 43
public ExamApplicationJpaEntity(Long applicationId, Long examId, boolean isLunchChecked,
String examNumber) {
this.applicationId = applicationId;
this.examId = examId;
this.lunchId = lunchId;
this.isLunchChecked = isLunchChecked;
this.examNumber = examNumber;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix constructor parameter inconsistency.

The constructor accepts an examNumber parameter, but the static create method on lines 45-52 doesn't provide this parameter, potentially leaving examNumber as null for entities created through the factory method.

Consider one of these approaches:

  1. Add examNumber parameter to the create method
  2. Make examNumber optional in the constructor and set a default value
  3. Remove examNumber from the constructor if it's set separately via grantExamNumber
 public static ExamApplicationJpaEntity create(Long applicationId, Long examId,
-            boolean isLunchChecked) {
+            boolean isLunchChecked, String examNumber) {
     return ExamApplicationJpaEntity.builder()
             .applicationId(applicationId)
             .examId(examId)
             .isLunchChecked(isLunchChecked)
+            .examNumber(examNumber)
             .build();
 }
📝 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
public ExamApplicationJpaEntity(Long applicationId, Long examId, boolean isLunchChecked,
String examNumber) {
this.applicationId = applicationId;
this.examId = examId;
this.lunchId = lunchId;
this.isLunchChecked = isLunchChecked;
this.examNumber = examNumber;
}
public static ExamApplicationJpaEntity create(Long applicationId,
Long examId,
boolean isLunchChecked,
String examNumber) {
return ExamApplicationJpaEntity.builder()
.applicationId(applicationId)
.examId(examId)
.isLunchChecked(isLunchChecked)
.examNumber(examNumber)
.build();
}
🤖 Prompt for AI Agents
In
src/main/java/life/mosu/mosuserver/domain/examapplication/ExamApplicationJpaEntity.java
around lines 37 to 43, the constructor requires an examNumber parameter, but the
static create method does not supply it, causing examNumber to be null for
created entities. To fix this, either add an examNumber parameter to the create
method and pass it to the constructor, or modify the constructor to make
examNumber optional with a default value, or remove examNumber from the
constructor entirely if it is intended to be set later via grantExamNumber.

Comment on lines +214 to +227
boolean isLunchChecked = (exam.getLunchPrice() != null) && random.nextBoolean();

totalAmount += BASE_EXAM_FEE;

ExamApplicationJpaEntity examApplication = examApplicationRepository.save(
ExamApplicationJpaEntity.builder()
.applicationId(application.getId())
.examId(exam.getId())
.examNumber(String.format("MOSU-%d-%d", application.getId(),
exam.getId()))
.isLunchChecked(
((j % 2 == 0) ? true : false)
)
.build()
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Redundant lunch selection logic

The isLunchChecked value is set twice with different logic - first based on lunch availability and random selection, then overridden with index-based alternation.

Remove the redundant assignment:

                 boolean isLunchChecked = (exam.getLunchPrice() != null) && random.nextBoolean();

                 totalAmount += BASE_EXAM_FEE;

                 ExamApplicationJpaEntity examApplication = examApplicationRepository.save(
                         ExamApplicationJpaEntity.builder()
                                 .applicationId(application.getId())
                                 .examId(exam.getId())
                                 .examNumber(String.format("MOSU-%d-%d", application.getId(),
                                         exam.getId()))
-                                .isLunchChecked(
-                                        ((j % 2 == 0) ? true : false)
-                                )
+                                .isLunchChecked(isLunchChecked)
                                 .build()
                 );
📝 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
boolean isLunchChecked = (exam.getLunchPrice() != null) && random.nextBoolean();
totalAmount += BASE_EXAM_FEE;
ExamApplicationJpaEntity examApplication = examApplicationRepository.save(
ExamApplicationJpaEntity.builder()
.applicationId(application.getId())
.examId(exam.getId())
.examNumber(String.format("MOSU-%d-%d", application.getId(),
exam.getId()))
.isLunchChecked(
((j % 2 == 0) ? true : false)
)
.build()
boolean isLunchChecked = (exam.getLunchPrice() != null) && random.nextBoolean();
totalAmount += BASE_EXAM_FEE;
ExamApplicationJpaEntity examApplication = examApplicationRepository.save(
ExamApplicationJpaEntity.builder()
.applicationId(application.getId())
.examId(exam.getId())
.examNumber(String.format("MOSU-%d-%d", application.getId(),
exam.getId()))
.isLunchChecked(isLunchChecked)
.build()
);
🤖 Prompt for AI Agents
In
src/main/java/life/mosu/mosuserver/global/initializer/DatabaseInitializer.java
around lines 214 to 227, the isLunchChecked variable is assigned twice with
conflicting logic—first using lunch availability and randomness, then
overwritten by an index-based boolean. Remove the redundant assignment inside
the builder where isLunchChecked is set using the index check, and instead use
the previously computed isLunchChecked value to ensure consistent and intended
lunch selection logic.

Comment on lines +77 to +83
@Operation(summary = "환불 신청 수 조회 (구현중)", description = "환불 신청 수 조회 입니다")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "환불 신청 수 조회 성공")
})
public ResponseEntity<ApiResponseWrapper<Page<RefundListResponse>>> getRefundCounts(
@PageableDefault(size = 15) Pageable pageable
);
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

Complete the implementation of getRefundCounts

The endpoint is marked as "구현중" (under development). Ensure this is implemented before merging.


🏁 Script executed:

#!/bin/bash
# Check if the getRefundCounts method is implemented in AdminController
ast-grep --pattern 'public ResponseEntity<ApiResponseWrapper<Page<RefundListResponse>>> getRefundCounts($_) {
  $$$
}'

Length of output: 120


🏁 Script executed:

#!/bin/bash
# Search for any references or implementations of getRefundCounts across the codebase
rg -n "getRefundCounts(" --color never

Length of output: 123


🏁 Script executed:

#!/bin/bash
# Search for all occurrences of getRefundCounts across the codebase to verify its implementation
rg -F -n "getRefundCounts" --color never

Length of output: 379


🏁 Script executed:

#!/bin/bash
# Show context around getRefundCounts in AdminController.java to confirm its implementation status
rg -n -C5 "getRefundCounts" src/main/java/life/mosu/mosuserver/presentation/admin/AdminController.java

Length of output: 645


Implement the getRefundCounts endpoint before merging

The getRefundCounts method in AdminController currently returns a null payload and comments out the service call. Please replace the stub with a real implementation:

• File: src/main/java/life/mosu/mosuserver/presentation/admin/AdminController.java
Lines 103–108

Suggested diff:

@@ -103,7 +103,7 @@ public ResponseEntity<ApiResponseWrapper<Page<RefundListResponse>>> getRefundCoun
-//        Page<RefundListResponse> result = adminService.getRefunds(pageable);
-        return ResponseEntity.ok(
-                ApiResponseWrapper.success(HttpStatus.OK, "환불 신청 수 조회 성공", null));
+        Page<RefundListResponse> result = adminService.getRefunds(pageable);
+        return ResponseEntity.ok(
+                ApiResponseWrapper.success(HttpStatus.OK, "환불 신청 수 조회 성공", result));

Additionally, update the OpenAPI docs in AdminControllerDocs.java to remove “(구현중)” once implemented.

🤖 Prompt for AI Agents
In src/main/java/life/mosu/mosuserver/presentation/admin/AdminController.java
lines 103 to 108, replace the stub implementation of getRefundCounts with a real
service call that fetches the refund counts and returns them in the
ResponseEntity. Then, in
src/main/java/life/mosu/mosuserver/presentation/admin/AdminControllerDocs.java
lines 77 to 83, update the @Operation summary to remove “(구현중)” to reflect that
the endpoint is now implemented.

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

♻️ Duplicate comments (2)
src/main/java/life/mosu/mosuserver/domain/admin/ApplicationQueryRepositoryImpl.java (2)

56-78: Pagination total count is still incorrect.

This is the same issue previously identified - the total count uses content.size() instead of the actual database count.


217-249: Missing exam.lunchName in query selection - same issue as before.

The mapToExcel method accesses exam.lunchName on line 222, but this field is still not included in the baseQuery select clause.

🧹 Nitpick comments (1)
src/main/java/life/mosu/mosuserver/domain/admin/ApplicationQueryRepositoryImpl.java (1)

94-117: Consider using inner joins instead of right joins.

The query logic is correct, but using rightJoin operations is unconventional for this aggregation. Consider using innerJoin since you're filtering on conditions that require all entities to exist.

-                .rightJoin(exam).on(examApplication.examId.eq(exam.id))
-                .rightJoin(application).on(application.id.eq(examApplication.applicationId))
-                .rightJoin(payment).on(application.id.eq(payment.applicationId))
+                .innerJoin(exam).on(examApplication.examId.eq(exam.id))
+                .innerJoin(application).on(application.id.eq(examApplication.applicationId))
+                .innerJoin(payment).on(application.id.eq(payment.applicationId))
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between ea79857 and 3539a3f.

📒 Files selected for processing (1)
  • src/main/java/life/mosu/mosuserver/domain/admin/ApplicationQueryRepositoryImpl.java (1 hunks)
🔇 Additional comments (1)
src/main/java/life/mosu/mosuserver/domain/admin/ApplicationQueryRepositoryImpl.java (1)

142-149: Join conditions look correct.

The payment join condition has been properly implemented using application.id, which correctly links payments to applications.

@wlgns12370 wlgns12370 merged commit 763f872 into develop Jul 22, 2025
2 checks passed
@wlgns12370 wlgns12370 deleted the refactor/mosu-123 branch July 22, 2025 13:54
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