Skip to content

Conversation

@chominju02
Copy link
Contributor

@chominju02 chominju02 commented Aug 6, 2025

✨ 구현한 기능

📢 논의하고 싶은 내용

  • 결제, 환불 시 현재 신청 인원이 변경될 텐데, 이 때마다 examStatus 를 open, close로 매번 변경하는게 좋을지
  • deadline이 지난 시험들은 다 close 처리해야하는데 어떤식으로 처리하면 좋을지

🎸 기타

Summary by CodeRabbit

  • New Features

    • Added the ability for administrators to close exam venues via a new PATCH endpoint.
    • Exams now have an explicit status (OPEN or CLOSED) that can be managed.
  • Improvements

    • Enhanced validation logic for exam applications to consider exam status and deadlines more accurately.
    • Improved transaction management for exam-related operations to ensure data integrity.
  • Bug Fixes

    • Addressed edge cases where closed exams or exams past their deadline could be incorrectly processed.

@chominju02 chominju02 self-assigned this Aug 6, 2025
@coderabbitai
Copy link

coderabbitai bot commented Aug 6, 2025

Walkthrough

This change introduces an ExamStatus enum and related status-handling logic to the exam domain. The ExamJpaEntity now tracks its open/closed state, with a new method for status transition. Validation logic is refactored to operate on full ExamJpaEntity objects, and a PATCH endpoint is added for admins to close exams. Transactional annotations are applied to exam service methods.

Changes

Cohort / File(s) Change Summary
Exam Status Enum Introduction
src/main/java/life/mosu/mosuserver/domain/exam/entity/ExamStatus.java
Added new ExamStatus enum with OPEN and CLOSED values to represent exam recruitment status.
Exam Entity Status Field & Methods
src/main/java/life/mosu/mosuserver/domain/exam/entity/ExamJpaEntity.java
Added examStatus field, persisted as a string, defaulting to OPEN. Added close() method to update status to CLOSED.
Exam Service Enhancements
src/main/java/life/mosu/mosuserver/application/exam/ExamService.java
Added transactional annotations to all public methods. Introduced a close(Long examId) method to set exam status to closed, throwing exception if not found.
Validation Refactor
src/main/java/life/mosu/mosuserver/application/application/vaildator/ApplicationValidator.java
Refactored examNotFull and examDateNotPassed to accept lists of ExamJpaEntity instead of IDs; updated logic to use entity fields and status, including cache lookups for application counts.
Application Service Update
src/main/java/life/mosu/mosuserver/application/application/ApplicationService.java
Injected ExamJpaRepository; updated validation calls to use entity objects instead of IDs; fetches entities before validation.
Exam Controller Endpoint
src/main/java/life/mosu/mosuserver/presentation/exam/ExamController.java
Added PATCH /exams/{examId} endpoint for admins to close exams, calling the new service method and returning a success response.

Sequence Diagram(s)

sequenceDiagram
    participant Admin as Admin User
    participant Controller as ExamController
    participant Service as ExamService
    participant Repo as ExamJpaRepository
    participant Entity as ExamJpaEntity

    Admin->>Controller: PATCH /exams/{examId}
    Controller->>Service: close(examId)
    Service->>Repo: findById(examId)
    Repo-->>Service: ExamJpaEntity
    Service->>Entity: close()
    Entity-->>Service: (status set to CLOSED)
    Service-->>Controller: (void)
    Controller-->>Admin: 200 OK, "Exam venue closed"
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~18 minutes

Possibly related PRs

  • mosu-dev/mosu-server#182: Refactors and introduces the initial examNotFull validator, which is further refactored in this PR to use entity objects.
  • mosu-dev/mosu-server#146: Adds exam date validation inside ApplicationService.apply using exam IDs; related to validation logic changes.
  • mosu-dev/mosu-server#124: Refactors ApplicationService validation and data retrieval, related to this PR's changes in how validation uses full entity objects.

Poem

🐇 Hopping through code with a joyful cheer,
Exams now open or closed, it’s clear!
Admins patch swiftly, closing the gate,
Validation refined — no room for debate.
With enums and methods, our system’s alive,
In Mosu’s garden, the changes thrive! 🌸

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 d48fc68 and 8a00199.

📒 Files selected for processing (1)
  • src/main/java/life/mosu/mosuserver/application/application/ApplicationService.java (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/java/life/mosu/mosuserver/application/application/ApplicationService.java
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/mosu-205

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.

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 @chominju02, 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!

I've implemented a new feature that allows administrators to close exams, preventing further applications. This involved introducing an ExamStatus to track the state of an exam and updating the application validation logic to respect this new status. Additionally, I've refined existing validation checks for exam dates and capacity, ensuring they use the most current exam information and handle the new closed status.

Highlights

  • New Exam Status Management: Introduced an ExamStatus enum (OPEN, CLOSED) to manage exam availability, providing a clear state for each exam.
  • Exam Entity Enhancements: Added the examStatus field to ExamJpaEntity and implemented utility methods (close() and open()) to programmatically change an exam's status.
  • Admin Exam Closing Functionality: Implemented a new admin-only PATCH endpoint (/api/v1/exams/{examId}) that allows administrators to explicitly close specific exams, preventing further applications.
  • Application Validation Improvements: Updated the application validation logic to prevent users from applying to exams that are either full, past their deadline, or explicitly marked as CLOSED.
  • Date Validation Precision: Refactored exam date validation to use LocalDateTime and the exam's deadlineTime for more precise and accurate checks, moving away from LocalDate.
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 feature for administrators to manually close an exam for applications. The implementation is solid, adding a new examStatus to the ExamJpaEntity and updating the application validation logic accordingly. The refactoring in ApplicationService to fetch exam entities once and pass them to the validator is a good performance improvement.

Regarding your discussion points:

  1. It's a good design to keep the examStatus for manual admin control separate from the automatic capacity-based logic. The current implementation correctly checks both conditions, and I would recommend keeping it this way to avoid complexity and unexpected behavior (e.g., an admin-closed exam reopening automatically).
  2. For handling exams with past deadlines, implementing a scheduled job (e.g., using Spring's @Scheduled annotation) is a common and effective approach. This job could run periodically to find exams whose deadlineTime has passed and update their examStatus to CLOSED.

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

🧹 Nitpick comments (3)
src/main/java/life/mosu/mosuserver/presentation/exam/ExamController.java (1)

74-80: LGTM! Well-structured admin endpoint.

The endpoint follows established patterns with proper authorization and consistent response handling. Consider refining the success message for clarity.

Consider updating the message for better clarity:

-                ApiResponseWrapper.success(HttpStatus.OK, "시험장 마감 성공"));
+                ApiResponseWrapper.success(HttpStatus.OK, "시험 마감 성공"));

This makes it clearer that the exam itself is being closed rather than just the venue.

src/main/java/life/mosu/mosuserver/application/exam/ExamService.java (1)

30-30: Consider using REQUIRED propagation for read operations.

While SUPPORTS propagation works, consider using REQUIRED instead to ensure consistent transaction behavior across the application.

-@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
+@Transactional(readOnly = true)

REQUIRED is the default and ensures the method always runs within a transaction context, providing more predictable behavior.

Also applies to: 44-44, 51-51

src/main/java/life/mosu/mosuserver/application/application/vaildator/ApplicationValidator.java (1)

83-106: Consider more specific error handling for cache misses.

The method correctly checks both exam status and capacity. However, using the same error code for both missing current applications and missing max capacity could make debugging difficult.

Consider using different error codes or including contextual information:

 public void examNotFull(List<ExamJpaEntity> exams) {
     boolean isFull = exams.stream()
             .anyMatch(exam -> {
 
                 if (exam.getExamStatus() == ExamStatus.CLOSED) {
                     return true;
                 }
 
                 Long currentApplications = examQuotaCacheManager.getCurrentApplications(
                                 exam.getId())
                         .orElseThrow(() -> new CustomRuntimeException(
-                                ErrorCode.EXAM_QUOTA_NOT_FOUND));
+                                ErrorCode.EXAM_QUOTA_NOT_FOUND,
+                                "Current applications not found for exam: " + exam.getId()));
 
                 Long maxCapacity = examQuotaCacheManager.getMaxCapacity(exam.getId())
                         .orElseThrow(() -> new CustomRuntimeException(
-                                ErrorCode.EXAM_QUOTA_NOT_FOUND));
+                                ErrorCode.EXAM_QUOTA_NOT_FOUND,
+                                "Max capacity not found for exam: " + exam.getId()));
 
                 return currentApplications >= maxCapacity;
             });
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between e461efd and daf37a0.

📒 Files selected for processing (6)
  • src/main/java/life/mosu/mosuserver/application/application/ApplicationService.java (3 hunks)
  • src/main/java/life/mosu/mosuserver/application/application/vaildator/ApplicationValidator.java (2 hunks)
  • src/main/java/life/mosu/mosuserver/application/exam/ExamService.java (4 hunks)
  • src/main/java/life/mosu/mosuserver/domain/exam/entity/ExamJpaEntity.java (2 hunks)
  • src/main/java/life/mosu/mosuserver/domain/exam/entity/ExamStatus.java (1 hunks)
  • src/main/java/life/mosu/mosuserver/presentation/exam/ExamController.java (2 hunks)
🔇 Additional comments (11)
src/main/java/life/mosu/mosuserver/domain/exam/entity/ExamStatus.java (1)

3-6: LGTM! Clean enum implementation.

The enum is well-structured with descriptive Korean comments that clearly explain the status meanings.

src/main/java/life/mosu/mosuserver/presentation/exam/ExamController.java (1)

14-14: LGTM! Proper import addition.

Adding PatchMapping import to support the new endpoint.

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

15-16: LGTM! Proper imports for entity-based validation.

Adding necessary imports to support the refactored validation approach.


37-37: LGTM! Repository injection for exam fetching.

Injecting ExamJpaRepository to enable entity-based validation.

src/main/java/life/mosu/mosuserver/domain/exam/entity/ExamJpaEntity.java (3)

57-59: LGTM! Proper enum field implementation.

The examStatus field is correctly implemented with appropriate JPA annotations and a sensible default value.


86-90: LGTM! Well-implemented status transition method.

The close() method properly checks current status before updating, preventing unnecessary database updates and maintaining clean state transitions.


92-96: LGTM! Consistent status transition implementation.

The open() method follows the same pattern as close() with proper guard clauses.

src/main/java/life/mosu/mosuserver/application/exam/ExamService.java (3)

8-9: LGTM! Proper imports for exception handling and transaction management.

Adding necessary imports for the new functionality.

Also applies to: 14-15


24-24: LGTM! Proper transactional annotations for write operations.

Adding @transactional to write operations ensures proper transaction management.

Also applies to: 63-63, 68-68


69-73: LGTM! Proper implementation of close operation.

The method correctly handles entity retrieval with appropriate error handling and delegates to the domain method for status update.

src/main/java/life/mosu/mosuserver/application/application/vaildator/ApplicationValidator.java (1)

3-3: Import changes look good.

The new imports for LocalDateTime and ExamStatus are appropriate for the updated validation logic.

Also applies to: 12-12

Comment on lines 82 to 84
List<ExamJpaEntity> exams = examJpaRepository.findAllById(examIds);
validator.examNotFull(exams);
validator.examDateNotPassed(exams);
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

Verify exam existence before validation.

The refactoring to entity-based validation is good, but findAllById may return fewer entities than requested IDs if some exams don't exist. Consider validating that all requested exams were found.


🏁 Script executed:

#!/bin/bash
# Check if there's existing validation for exam existence in ApplicationValidator
ast-grep --pattern 'class ApplicationValidator {
  $$$
}'

Length of output: 59


🏁 Script executed:

#!/bin/bash
# Locate where the validator methods are defined
rg -n "examNotFull" -n src
rg -n "examDateNotPassed" -n src

# Find any Validator classes in the codebase
rg -n "class .*Validator" -n src

Length of output: 798


Add an existence check for all requested exams before running other validators

Currently, findAllById(examIds) will silently drop any IDs that don’t exist, which means you may be validating a subset of exams without noticing the missing ones. You should explicitly verify that the size of the returned list matches the number of requested IDs, and throw a clear exception if not.

• In src/main/java/life/mosu/mosuserver/application/application/ApplicationService.java (around lines 82–84), insert something like:

       List<ExamJpaEntity> exams = examJpaRepository.findAllById(examIds);
+      if (exams.size() != examIds.size()) {
+          throw new EntityNotFoundException(
+              "Some exams not found for IDs: " +
+              examIds.stream()
+                     .filter(id -> exams.stream().noneMatch(e -> e.getId().equals(id)))
+                     .collect(Collectors.toList())
+          );
+      }
       validator.examNotFull(exams);
       validator.examDateNotPassed(exams);

This ensures you fail fast if any requested exam is missing before proceeding with capacity or date checks.

📝 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
List<ExamJpaEntity> exams = examJpaRepository.findAllById(examIds);
validator.examNotFull(exams);
validator.examDateNotPassed(exams);
List<ExamJpaEntity> exams = examJpaRepository.findAllById(examIds);
if (exams.size() != examIds.size()) {
throw new EntityNotFoundException(
"Some exams not found for IDs: " +
examIds.stream()
.filter(id -> exams.stream().noneMatch(e -> e.getId().equals(id)))
.collect(Collectors.toList())
);
}
validator.examNotFull(exams);
validator.examDateNotPassed(exams);
🤖 Prompt for AI Agents
In
src/main/java/life/mosu/mosuserver/application/application/ApplicationService.java
around lines 82 to 84, add a check after retrieving exams with findAllById to
verify that the number of exams returned matches the number of requested
examIds. If the sizes differ, throw a clear exception indicating some exams were
not found. This ensures you detect missing exams before running further
validations like examNotFull and examDateNotPassed.

Comment on lines 74 to 81
public void examDateNotPassed(List<ExamJpaEntity> exams) {
boolean hasPassedExam = exams.stream()
.anyMatch(exam -> exam.getExamDate().isBefore(LocalDate.now()));
.anyMatch(exam -> exam.getDeadlineTime().isBefore(LocalDateTime.now()));

if (hasPassedExam) {
throw new CustomRuntimeException(ErrorCode.EXAM_DATE_PASSED);
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Consider timezone handling and deadline boundary behavior.

The deadline comparison has two potential issues:

  1. Using LocalDateTime.now() assumes the server's local timezone matches the deadline's timezone. Consider using ZonedDateTime or ensuring consistent timezone handling.
  2. The isBefore() check rejects applications at the exact deadline moment. Consider using isBefore() or isEqual() to allow applications until the deadline expires.
 public void examDateNotPassed(List<ExamJpaEntity> exams) {
     boolean hasPassedExam = exams.stream()
-            .anyMatch(exam -> exam.getDeadlineTime().isBefore(LocalDateTime.now()));
+            .anyMatch(exam -> exam.getDeadlineTime().isBefore(LocalDateTime.now()) || 
+                             exam.getDeadlineTime().isEqual(LocalDateTime.now()));
📝 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 void examDateNotPassed(List<ExamJpaEntity> exams) {
boolean hasPassedExam = exams.stream()
.anyMatch(exam -> exam.getExamDate().isBefore(LocalDate.now()));
.anyMatch(exam -> exam.getDeadlineTime().isBefore(LocalDateTime.now()));
if (hasPassedExam) {
throw new CustomRuntimeException(ErrorCode.EXAM_DATE_PASSED);
}
}
public void examDateNotPassed(List<ExamJpaEntity> exams) {
boolean hasPassedExam = exams.stream()
.anyMatch(exam -> exam.getDeadlineTime().isBefore(LocalDateTime.now()) ||
exam.getDeadlineTime().isEqual(LocalDateTime.now()));
if (hasPassedExam) {
throw new CustomRuntimeException(ErrorCode.EXAM_DATE_PASSED);
}
}
🤖 Prompt for AI Agents
In
src/main/java/life/mosu/mosuserver/application/application/vaildator/ApplicationValidator.java
around lines 74 to 81, the exam deadline comparison uses LocalDateTime.now()
which may cause timezone inconsistencies and excludes the exact deadline moment.
To fix this, update the code to use ZonedDateTime or another timezone-aware time
class consistent with the exam deadlines, and modify the condition to check if
the deadline is before or equal to the current time to allow applications up to
the deadline.

Comment on lines +91 to +99
Long currentApplications = examQuotaCacheManager.getCurrentApplications(
exam.getId())
.orElseThrow(() -> new CustomRuntimeException(
ErrorCode.EXAM_QUOTA_NOT_FOUND));

Long maxCapacity = examQuotaCacheManager.getMaxCapacity(exam.getId())
.orElseThrow(() -> new CustomRuntimeException(
ErrorCode.EXAM_QUOTA_NOT_FOUND));

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

Verify cache synchronization with exam status changes.

Since the validation relies on cached values for application counts and capacities, ensure that the cache is properly invalidated or updated when:

  1. An admin manually closes/opens an exam
  2. The exam status changes due to reaching capacity
  3. Applications are added or removed (payment/refund scenarios mentioned in PR objectives)

🏁 Script executed:

#!/bin/bash
# Description: Check how ExamQuotaCacheManager handles cache updates

# Find cache update/invalidation methods
echo "=== Searching for cache update methods in ExamQuotaCacheManager ==="
rg -A 5 "class ExamQuotaCacheManager" 

# Check for cache invalidation on exam status changes
echo "=== Searching for cache invalidation on status changes ==="
rg -A 3 "(invalidate|evict|update|refresh).*cache" --glob "**/*Cache*.java"

# Check ExamService for cache handling when closing exams
echo "=== Checking ExamService close method for cache updates ==="
ast-grep --pattern 'close($$$) {
  $$$
}'

Length of output: 1294


Cache Invalidation Missing for ExamQuotaCacheManager

I didn’t find any eviction or refresh calls in ExamQuotaCacheManager or related services when an exam’s status or its application count changes. Without explicit cache invalidation:

  • Closed exams may still report old quotas
  • Capacity changes from new applications or refunds won’t be reflected
  • Auto-closure on expiry won’t clear stale entries

To address this, add cache eviction calls at these touchpoints:

• After manually closing/opening an exam
File: src/main/java/life/mosu/mosuserver/application/exam/service/ExamService.java

public void closeExam(Long examId) {
    ExamJpaEntity exam = examRepository.findById(examId)…
    exam.setStatus(EXAM_STATUS.CLOSED);
    examRepository.save(exam);
    // Invalidate cached quotas
    examQuotaCacheManager.invalidate(examId.toString());
}

• When an application is created or canceled (payment/refund)
File: src/main/java/life/mosu/mosuserver/application/application/service/ApplicationService.java

public void createApplication(…) {
    …
    examQuotaCacheManager.invalidate(examId.toString());
}
public void refundApplication(…) {
    …
    examQuotaCacheManager.invalidate(examId.toString());
}

• If you implement automatic expiry-driven closure, ensure it also calls
examQuotaCacheManager.invalidate(examId.toString());

🤖 Prompt for AI Agents
In
src/main/java/life/mosu/mosuserver/application/application/vaildator/ApplicationValidator.java
lines 91-99, the cache for exam quotas is read but never invalidated, leading to
stale data issues. To fix this, add cache eviction calls in ExamService.java
after changing an exam's status (e.g., closing/opening an exam), and in
ApplicationService.java after creating or refunding an application. Also ensure
any automatic expiry-driven exam closures call the cache invalidation method.
This will keep the cached quota data consistent with the current state.

@chominju02 chominju02 merged commit 3574e1d into develop Aug 6, 2025
3 checks passed
@chominju02 chominju02 deleted the feature/mosu-205 branch August 7, 2025 07:21
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