From cb2fbbb6b61d8bc8f23ffb83f539f5057dfa2e64 Mon Sep 17 00:00:00 2001 From: KNU-K Date: Sat, 26 Jul 2025 00:47:45 +0900 Subject: [PATCH 01/13] =?UTF-8?q?MOSU=20chore:=20ExamQuota=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EB=B0=8F=20=EC=83=81?= =?UTF-8?q?=ED=83=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exam/dto/event/ApplicationStatus.java | 5 ++++ .../exam/dto/event/ExamQuotaEvent.java | 23 +++++++++++++++++++ .../exam/dto/event/ExamQuotaEventType.java | 22 ++++++++++++++++++ .../exam/dto/event/ExamQuotaStatus.java | 5 ++++ .../exam/dto/event/MaxCapacityStatus.java | 5 ++++ 5 files changed, 60 insertions(+) create mode 100644 src/main/java/life/mosu/mosuserver/presentation/exam/dto/event/ApplicationStatus.java create mode 100644 src/main/java/life/mosu/mosuserver/presentation/exam/dto/event/ExamQuotaEvent.java create mode 100644 src/main/java/life/mosu/mosuserver/presentation/exam/dto/event/ExamQuotaEventType.java create mode 100644 src/main/java/life/mosu/mosuserver/presentation/exam/dto/event/ExamQuotaStatus.java create mode 100644 src/main/java/life/mosu/mosuserver/presentation/exam/dto/event/MaxCapacityStatus.java diff --git a/src/main/java/life/mosu/mosuserver/presentation/exam/dto/event/ApplicationStatus.java b/src/main/java/life/mosu/mosuserver/presentation/exam/dto/event/ApplicationStatus.java new file mode 100644 index 00000000..bbb2d161 --- /dev/null +++ b/src/main/java/life/mosu/mosuserver/presentation/exam/dto/event/ApplicationStatus.java @@ -0,0 +1,5 @@ +package life.mosu.mosuserver.presentation.exam.dto.event; + +public enum ApplicationStatus implements ExamQuotaStatus { + INCREASE, CREATE, DECREASE, DELETE +} diff --git a/src/main/java/life/mosu/mosuserver/presentation/exam/dto/event/ExamQuotaEvent.java b/src/main/java/life/mosu/mosuserver/presentation/exam/dto/event/ExamQuotaEvent.java new file mode 100644 index 00000000..eaf9f504 --- /dev/null +++ b/src/main/java/life/mosu/mosuserver/presentation/exam/dto/event/ExamQuotaEvent.java @@ -0,0 +1,23 @@ +package life.mosu.mosuserver.presentation.exam.dto.event; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor(staticName = "ofSingleCommand") +public class ExamQuotaEvent { + private final ExamQuotaEventType type; + private final String schoolName; + private final Long value; + private final Enum status; + + public ExamQuotaEvent(ExamQuotaEventType type, String schoolName, Long value) { + this.type = type; + this.schoolName = schoolName; + this.value = value; + this.status = null; + } + public static ExamQuotaEvent ofMultipleCommand(ExamQuotaEventType type, String schoolName, Long value) { + return new ExamQuotaEvent(type, schoolName, value); + } +} \ No newline at end of file diff --git a/src/main/java/life/mosu/mosuserver/presentation/exam/dto/event/ExamQuotaEventType.java b/src/main/java/life/mosu/mosuserver/presentation/exam/dto/event/ExamQuotaEventType.java new file mode 100644 index 00000000..53ac5544 --- /dev/null +++ b/src/main/java/life/mosu/mosuserver/presentation/exam/dto/event/ExamQuotaEventType.java @@ -0,0 +1,22 @@ +package life.mosu.mosuserver.presentation.exam.dto.event; + +import java.util.Set; + +public enum ExamQuotaEventType { + // Single Commands + CURRENT_APPLICATION(Set.of(ApplicationStatus.INCREASE, ApplicationStatus.CREATE)), + MAX_CAPACITY(Set.of(MaxCapacityStatus.CREATE, MaxCapacityStatus.UPDATE)), + + // Multiple Commands + LOAD(Set.of()), + DELETE_ALL(Set.of()); + private final Set validStatuses; + + ExamQuotaEventType(Set statuses) { + this.validStatuses = statuses; + } + + public boolean isValidStatus(ExamQuotaStatus status) { + return validStatuses.contains(status); + } +} \ No newline at end of file diff --git a/src/main/java/life/mosu/mosuserver/presentation/exam/dto/event/ExamQuotaStatus.java b/src/main/java/life/mosu/mosuserver/presentation/exam/dto/event/ExamQuotaStatus.java new file mode 100644 index 00000000..b73f8e58 --- /dev/null +++ b/src/main/java/life/mosu/mosuserver/presentation/exam/dto/event/ExamQuotaStatus.java @@ -0,0 +1,5 @@ +package life.mosu.mosuserver.presentation.exam.dto.event; + +public interface ExamQuotaStatus { + +} diff --git a/src/main/java/life/mosu/mosuserver/presentation/exam/dto/event/MaxCapacityStatus.java b/src/main/java/life/mosu/mosuserver/presentation/exam/dto/event/MaxCapacityStatus.java new file mode 100644 index 00000000..c006e65d --- /dev/null +++ b/src/main/java/life/mosu/mosuserver/presentation/exam/dto/event/MaxCapacityStatus.java @@ -0,0 +1,5 @@ +package life.mosu.mosuserver.presentation.exam.dto.event; + +public enum MaxCapacityStatus implements ExamQuotaStatus { + CREATE, UPDATE, DELETE +} From 3b2b5a6eac16a95f380bebc1834c1d921dbae5fc Mon Sep 17 00:00:00 2001 From: KNU-K Date: Sat, 26 Jul 2025 00:48:35 +0900 Subject: [PATCH 02/13] =?UTF-8?q?MOSU=20chore:=20ApplicationQueryRepositor?= =?UTF-8?q?y,=20RefundQueryRepository,=20StudentQueryRepository=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ApplicationSchoolPreWarmRunner.java | 19 ------------------- .../jpa}/ApplicationQueryRepositoryImpl.java | 3 ++- .../jpa}/RefundQueryRepositoryImpl.java | 3 ++- .../jpa}/StudentQueryRepositoryImpl.java | 3 ++- 4 files changed, 6 insertions(+), 22 deletions(-) delete mode 100644 src/main/java/life/mosu/mosuserver/global/runner/ApplicationSchoolPreWarmRunner.java rename src/main/java/life/mosu/mosuserver/{domain/admin => infra/persistence/jpa}/ApplicationQueryRepositoryImpl.java (98%) rename src/main/java/life/mosu/mosuserver/{domain/admin => infra/persistence/jpa}/RefundQueryRepositoryImpl.java (97%) rename src/main/java/life/mosu/mosuserver/{domain/admin => infra/persistence/jpa}/StudentQueryRepositoryImpl.java (98%) diff --git a/src/main/java/life/mosu/mosuserver/global/runner/ApplicationSchoolPreWarmRunner.java b/src/main/java/life/mosu/mosuserver/global/runner/ApplicationSchoolPreWarmRunner.java deleted file mode 100644 index a44035b9..00000000 --- a/src/main/java/life/mosu/mosuserver/global/runner/ApplicationSchoolPreWarmRunner.java +++ /dev/null @@ -1,19 +0,0 @@ -package life.mosu.mosuserver.global.runner; - -import life.mosu.mosuserver.application.exam.ExamQuotaCacheManager; -import lombok.RequiredArgsConstructor; -import org.springframework.boot.context.event.ApplicationReadyEvent; -import org.springframework.context.event.EventListener; -import org.springframework.stereotype.Component; - -@RequiredArgsConstructor -@Component -public class ApplicationSchoolPreWarmRunner { - - private final ExamQuotaCacheManager examQuotaCacheManager; - - @EventListener(ApplicationReadyEvent.class) - public void preloadSchoolData() { - examQuotaCacheManager.preloadSchoolData(); - } -} diff --git a/src/main/java/life/mosu/mosuserver/domain/admin/ApplicationQueryRepositoryImpl.java b/src/main/java/life/mosu/mosuserver/infra/persistence/jpa/ApplicationQueryRepositoryImpl.java similarity index 98% rename from src/main/java/life/mosu/mosuserver/domain/admin/ApplicationQueryRepositoryImpl.java rename to src/main/java/life/mosu/mosuserver/infra/persistence/jpa/ApplicationQueryRepositoryImpl.java index 2beba874..b1e8af7a 100644 --- a/src/main/java/life/mosu/mosuserver/domain/admin/ApplicationQueryRepositoryImpl.java +++ b/src/main/java/life/mosu/mosuserver/infra/persistence/jpa/ApplicationQueryRepositoryImpl.java @@ -1,4 +1,4 @@ -package life.mosu.mosuserver.domain.admin; +package life.mosu.mosuserver.infra.persistence.jpa; import com.querydsl.core.Tuple; import com.querydsl.core.types.Predicate; @@ -11,6 +11,7 @@ import java.util.List; import java.util.Set; import java.util.stream.Collectors; +import life.mosu.mosuserver.domain.admin.ApplicationQueryRepository; import life.mosu.mosuserver.domain.application.QApplicationJpaEntity; import life.mosu.mosuserver.domain.application.QExamTicketImageJpaEntity; import life.mosu.mosuserver.domain.application.Subject; diff --git a/src/main/java/life/mosu/mosuserver/domain/admin/RefundQueryRepositoryImpl.java b/src/main/java/life/mosu/mosuserver/infra/persistence/jpa/RefundQueryRepositoryImpl.java similarity index 97% rename from src/main/java/life/mosu/mosuserver/domain/admin/RefundQueryRepositoryImpl.java rename to src/main/java/life/mosu/mosuserver/infra/persistence/jpa/RefundQueryRepositoryImpl.java index 032596fc..90a20149 100644 --- a/src/main/java/life/mosu/mosuserver/domain/admin/RefundQueryRepositoryImpl.java +++ b/src/main/java/life/mosu/mosuserver/infra/persistence/jpa/RefundQueryRepositoryImpl.java @@ -1,4 +1,4 @@ -package life.mosu.mosuserver.domain.admin; +package life.mosu.mosuserver.infra.persistence.jpa; import static life.mosu.mosuserver.domain.base.BaseTimeEntity.formatDate; @@ -6,6 +6,7 @@ import com.querydsl.jpa.impl.JPAQuery; import com.querydsl.jpa.impl.JPAQueryFactory; import java.util.List; +import life.mosu.mosuserver.domain.admin.RefundQueryRepository; import life.mosu.mosuserver.domain.application.QApplicationJpaEntity; import life.mosu.mosuserver.domain.examapplication.QExamApplicationJpaEntity; import life.mosu.mosuserver.domain.payment.PaymentMethod; diff --git a/src/main/java/life/mosu/mosuserver/domain/admin/StudentQueryRepositoryImpl.java b/src/main/java/life/mosu/mosuserver/infra/persistence/jpa/StudentQueryRepositoryImpl.java similarity index 98% rename from src/main/java/life/mosu/mosuserver/domain/admin/StudentQueryRepositoryImpl.java rename to src/main/java/life/mosu/mosuserver/infra/persistence/jpa/StudentQueryRepositoryImpl.java index e77a1ed5..b81a5389 100644 --- a/src/main/java/life/mosu/mosuserver/domain/admin/StudentQueryRepositoryImpl.java +++ b/src/main/java/life/mosu/mosuserver/infra/persistence/jpa/StudentQueryRepositoryImpl.java @@ -1,4 +1,4 @@ -package life.mosu.mosuserver.domain.admin; +package life.mosu.mosuserver.infra.persistence.jpa; import com.querydsl.core.Tuple; import com.querydsl.core.types.Predicate; @@ -7,6 +7,7 @@ import com.querydsl.jpa.impl.JPAQueryFactory; import java.util.List; import java.util.Optional; +import life.mosu.mosuserver.domain.admin.StudentQueryRepository; import life.mosu.mosuserver.domain.application.QApplicationJpaEntity; import life.mosu.mosuserver.domain.profile.Education; import life.mosu.mosuserver.domain.profile.Gender; From 3587cd9287c1a6df39ac29a6a09ba5abc3e7ecb7 Mon Sep 17 00:00:00 2001 From: KNU-K Date: Sat, 26 Jul 2025 00:48:58 +0900 Subject: [PATCH 03/13] =?UTF-8?q?MOSU=20chore:=20Cache=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EC=9D=B8=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4(Cache?= =?UTF-8?q?Evictor,=20CacheLoader,=20CacheReader,=20CacheWriter)=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../infra/persistence/redis/CacheEvictor.java | 5 +++++ .../infra/persistence/redis/CacheLoader.java | 11 +++++++++++ .../infra/persistence/redis/CacheReader.java | 7 +++++++ .../infra/persistence/redis/CacheWriter.java | 8 ++++++++ 4 files changed, 31 insertions(+) create mode 100644 src/main/java/life/mosu/mosuserver/infra/persistence/redis/CacheEvictor.java create mode 100644 src/main/java/life/mosu/mosuserver/infra/persistence/redis/CacheLoader.java create mode 100644 src/main/java/life/mosu/mosuserver/infra/persistence/redis/CacheReader.java create mode 100644 src/main/java/life/mosu/mosuserver/infra/persistence/redis/CacheWriter.java diff --git a/src/main/java/life/mosu/mosuserver/infra/persistence/redis/CacheEvictor.java b/src/main/java/life/mosu/mosuserver/infra/persistence/redis/CacheEvictor.java new file mode 100644 index 00000000..284edd0b --- /dev/null +++ b/src/main/java/life/mosu/mosuserver/infra/persistence/redis/CacheEvictor.java @@ -0,0 +1,5 @@ +package life.mosu.mosuserver.infra.persistence.redis; + +public interface CacheEvictor { + void evict(K key); +} diff --git a/src/main/java/life/mosu/mosuserver/infra/persistence/redis/CacheLoader.java b/src/main/java/life/mosu/mosuserver/infra/persistence/redis/CacheLoader.java new file mode 100644 index 00000000..e6ba2855 --- /dev/null +++ b/src/main/java/life/mosu/mosuserver/infra/persistence/redis/CacheLoader.java @@ -0,0 +1,11 @@ +package life.mosu.mosuserver.infra.persistence.redis; + +import java.util.Map; + +public interface CacheLoader { + void loadAll(Map values); + + void load(K key, V value); + + boolean exists(K key); +} diff --git a/src/main/java/life/mosu/mosuserver/infra/persistence/redis/CacheReader.java b/src/main/java/life/mosu/mosuserver/infra/persistence/redis/CacheReader.java new file mode 100644 index 00000000..c01e982a --- /dev/null +++ b/src/main/java/life/mosu/mosuserver/infra/persistence/redis/CacheReader.java @@ -0,0 +1,7 @@ +package life.mosu.mosuserver.infra.persistence.redis; + +import java.util.Optional; + +public interface CacheReader { + Optional read(K key); +} diff --git a/src/main/java/life/mosu/mosuserver/infra/persistence/redis/CacheWriter.java b/src/main/java/life/mosu/mosuserver/infra/persistence/redis/CacheWriter.java new file mode 100644 index 00000000..02f8fdd9 --- /dev/null +++ b/src/main/java/life/mosu/mosuserver/infra/persistence/redis/CacheWriter.java @@ -0,0 +1,8 @@ +package life.mosu.mosuserver.infra.persistence.redis; + +public interface CacheWriter { + void writeOrUpdate(K key, V value); + void increase(K key); + void decrease(K key); + void delete(K key); +} From bdefa34852e2bf0bd3a6434ebf205ae3f698b352 Mon Sep 17 00:00:00 2001 From: KNU-K Date: Sat, 26 Jul 2025 00:49:11 +0900 Subject: [PATCH 04/13] =?UTF-8?q?MOSU=20chore:=20RedisCache=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=ED=81=B4=EB=9E=98=EC=8A=A4(DefaultRedisCacheEvicto?= =?UTF-8?q?r,=20DefaultRedisCacheLoader,=20DefaultRedisCacheReader,=20Defa?= =?UTF-8?q?ultRedisCacheWriter)=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../redis/DefaultRedisCacheEvictor.java | 13 ++++++++ .../redis/DefaultRedisCacheLoader.java | 29 +++++++++++++++++ .../redis/DefaultRedisCacheReader.java | 18 +++++++++++ .../redis/DefaultRedisCacheWriter.java | 31 +++++++++++++++++++ 4 files changed, 91 insertions(+) create mode 100644 src/main/java/life/mosu/mosuserver/infra/persistence/redis/DefaultRedisCacheEvictor.java create mode 100644 src/main/java/life/mosu/mosuserver/infra/persistence/redis/DefaultRedisCacheLoader.java create mode 100644 src/main/java/life/mosu/mosuserver/infra/persistence/redis/DefaultRedisCacheReader.java create mode 100644 src/main/java/life/mosu/mosuserver/infra/persistence/redis/DefaultRedisCacheWriter.java diff --git a/src/main/java/life/mosu/mosuserver/infra/persistence/redis/DefaultRedisCacheEvictor.java b/src/main/java/life/mosu/mosuserver/infra/persistence/redis/DefaultRedisCacheEvictor.java new file mode 100644 index 00000000..789c0337 --- /dev/null +++ b/src/main/java/life/mosu/mosuserver/infra/persistence/redis/DefaultRedisCacheEvictor.java @@ -0,0 +1,13 @@ +package life.mosu.mosuserver.infra.persistence.redis; + +import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.RedisTemplate; + +@RequiredArgsConstructor +public class DefaultRedisCacheEvictor implements CacheEvictor { + protected final RedisTemplate redisTemplate; + + @Override + public void evict(String key) { + } +} diff --git a/src/main/java/life/mosu/mosuserver/infra/persistence/redis/DefaultRedisCacheLoader.java b/src/main/java/life/mosu/mosuserver/infra/persistence/redis/DefaultRedisCacheLoader.java new file mode 100644 index 00000000..3c47e9a1 --- /dev/null +++ b/src/main/java/life/mosu/mosuserver/infra/persistence/redis/DefaultRedisCacheLoader.java @@ -0,0 +1,29 @@ + package life.mosu.mosuserver.infra.persistence.redis; + + import java.util.Map; + import lombok.RequiredArgsConstructor; + import org.springframework.data.redis.core.RedisTemplate; + import org.springframework.stereotype.Component; + + @Component + @RequiredArgsConstructor + public class DefaultRedisCacheLoader implements CacheLoader { + protected final RedisTemplate redisTemplate; + + @Override + public void loadAll(Map values) { + values.forEach(this::load); + } + + @Override + public void load(String key, T value) { + + redisTemplate.opsForValue().set(key, value); + } + + @Override + public boolean exists(String key) { + Boolean result = redisTemplate.hasKey(key); + return result != null && result; + } + } diff --git a/src/main/java/life/mosu/mosuserver/infra/persistence/redis/DefaultRedisCacheReader.java b/src/main/java/life/mosu/mosuserver/infra/persistence/redis/DefaultRedisCacheReader.java new file mode 100644 index 00000000..f82053cc --- /dev/null +++ b/src/main/java/life/mosu/mosuserver/infra/persistence/redis/DefaultRedisCacheReader.java @@ -0,0 +1,18 @@ +package life.mosu.mosuserver.infra.persistence.redis; + +import java.util.Optional; +import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class DefaultRedisCacheReader implements CacheReader { + protected final RedisTemplate redisTemplate; + + + @Override + public Optional read(String key) { + return Optional.of(redisTemplate.opsForValue().get(key)); + } +} diff --git a/src/main/java/life/mosu/mosuserver/infra/persistence/redis/DefaultRedisCacheWriter.java b/src/main/java/life/mosu/mosuserver/infra/persistence/redis/DefaultRedisCacheWriter.java new file mode 100644 index 00000000..3640678d --- /dev/null +++ b/src/main/java/life/mosu/mosuserver/infra/persistence/redis/DefaultRedisCacheWriter.java @@ -0,0 +1,31 @@ +package life.mosu.mosuserver.infra.persistence.redis; + +import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class DefaultRedisCacheWriter implements CacheWriter { + protected final RedisTemplate redisTemplate; + + @Override + public void writeOrUpdate(String key, T value) { + redisTemplate.opsForValue().set(key, value); + } + + @Override + public void increase(String key) { + redisTemplate.opsForValue().increment(key, 1); + } + + @Override + public void decrease(String key) { + redisTemplate.opsForValue().decrement(key, 1); + } + + @Override + public void delete(String key) { + redisTemplate.delete(key); + } +} From 3103fac34481cc5d8befb1e1e8725bbf11f4ae83 Mon Sep 17 00:00:00 2001 From: KNU-K Date: Sat, 26 Jul 2025 00:49:21 +0900 Subject: [PATCH 05/13] =?UTF-8?q?MOSU=20chore:=20KeyValueCacheManager=20?= =?UTF-8?q?=EC=B6=94=EC=83=81=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../persistence/redis/KeyValueCacheManager.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/main/java/life/mosu/mosuserver/infra/persistence/redis/KeyValueCacheManager.java diff --git a/src/main/java/life/mosu/mosuserver/infra/persistence/redis/KeyValueCacheManager.java b/src/main/java/life/mosu/mosuserver/infra/persistence/redis/KeyValueCacheManager.java new file mode 100644 index 00000000..c9616f2c --- /dev/null +++ b/src/main/java/life/mosu/mosuserver/infra/persistence/redis/KeyValueCacheManager.java @@ -0,0 +1,17 @@ +package life.mosu.mosuserver.infra.persistence.redis; + +import jakarta.annotation.PostConstruct; +import java.util.Optional; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public abstract class KeyValueCacheManager { + protected final CacheLoader cacheLoader; + protected final CacheWriter cacheWriter; + protected final CacheReader cacheReader; + @PostConstruct + private void init(){ + initCache(); + } + protected abstract void initCache(); +} From 15a0bf19ffd4e495376e786edee910f4e2d75f84 Mon Sep 17 00:00:00 2001 From: KNU-K Date: Sat, 26 Jul 2025 00:49:32 +0900 Subject: [PATCH 06/13] =?UTF-8?q?MOSU=20chore:=20ExamQuotaCacheManager=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20=EB=A6=AC=ED=8C=A9=ED=86=A0?= =?UTF-8?q?=EB=A7=81=20=EB=B0=8F=20=EC=BA=90=EC=8B=9C=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exam/ExamQuotaCacheManager.java | 121 ++++++++++-------- 1 file changed, 69 insertions(+), 52 deletions(-) diff --git a/src/main/java/life/mosu/mosuserver/application/exam/ExamQuotaCacheManager.java b/src/main/java/life/mosu/mosuserver/application/exam/ExamQuotaCacheManager.java index 0482a922..42959234 100644 --- a/src/main/java/life/mosu/mosuserver/application/exam/ExamQuotaCacheManager.java +++ b/src/main/java/life/mosu/mosuserver/application/exam/ExamQuotaCacheManager.java @@ -1,79 +1,96 @@ package life.mosu.mosuserver.application.exam; import java.time.LocalDate; -import java.util.List; -import life.mosu.mosuserver.domain.exam.ExamJpaEntity; +import java.util.Optional; import life.mosu.mosuserver.domain.exam.ExamJpaRepository; -import life.mosu.mosuserver.domain.exam.projection.SchoolExamCountProjection; +import life.mosu.mosuserver.infra.persistence.redis.CacheLoader; +import life.mosu.mosuserver.infra.persistence.redis.CacheReader; +import life.mosu.mosuserver.infra.persistence.redis.CacheWriter; +import life.mosu.mosuserver.infra.persistence.redis.KeyValueCacheManager; +import lombok.Getter; import lombok.RequiredArgsConstructor; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.stereotype.Service; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; -@Service -@RequiredArgsConstructor -public class ExamQuotaCacheManager { +@Component +@Slf4j +public class ExamQuotaCacheManager extends KeyValueCacheManager { + private final ExamJpaRepository examJpaRepository; - private static final String REDIS_KEY_SCHOOL_MAX_CAPACITY = "school:max_capacity:"; - private static final String REDIS_KEY_SCHOOL_CURRENT_APPLICATIONS = "school:current_applications:"; + public ExamQuotaCacheManager( + CacheLoader cacheLoader, + CacheWriter cacheWriter, + CacheReader cacheReader, + ExamJpaRepository examJpaRepository + ) { + super(cacheLoader, cacheWriter, cacheReader); + this.examJpaRepository = examJpaRepository; + } - private final RedisTemplate redisTemplate; - private final ExamJpaRepository examJpaRepository; + public Optional getMaxCapacity(String schoolName) { + String key = ExamQuotaPrefix.MAX_CAPACITY.with(schoolName); + return cacheReader.read(key); + } - public void cacheSchoolMaxCapacities() { - List exams = examJpaRepository.findUpcomingExamInfo(LocalDate.now()); - for (ExamJpaEntity exam : exams) { - addSchoolMaxCapacity( - exam.getSchoolName(), - exam.getCapacity() - ); - } + public Optional getCurrentApplications(String schoolName) { + String key = ExamQuotaPrefix.CURRENT_APPLICATIONS.with(schoolName); + return cacheReader.read(key); } - public void cacheSchoolCurrentApplicationCounts() { - List schoolExamCounts = examJpaRepository.countApplicationsGroupedBySchoolName(); - for (SchoolExamCountProjection projection : schoolExamCounts) { - addSchoolCurrentApplicationCount( - projection.schoolName(), - projection.applicationCount() - ); - } + public void setMaxCapacity(String schoolName, Long maxCapacity) { + String key = ExamQuotaPrefix.MAX_CAPACITY.with(schoolName); + cacheWriter.writeOrUpdate(key, maxCapacity); } - public void addSchoolMaxCapacity(String schoolName, Integer capacity) { - String key = REDIS_KEY_SCHOOL_MAX_CAPACITY + schoolName; - redisTemplate.opsForValue().set(key, Long.valueOf(capacity)); + public void setCurrentApplications(String schoolName, Long currentApplications) { + String key = ExamQuotaPrefix.CURRENT_APPLICATIONS.with(schoolName); + cacheWriter.writeOrUpdate(key, currentApplications); } - public void addSchoolCurrentApplicationCount(String schoolName, Long currentCount) { - String key = REDIS_KEY_SCHOOL_CURRENT_APPLICATIONS + schoolName; - redisTemplate.opsForValue().set(key, currentCount); + public void deleteMaxCapacity(String schoolName) { + String key = ExamQuotaPrefix.MAX_CAPACITY.with(schoolName); + cacheWriter.delete(key); } - public Long getSchoolApplicationCounts(String schoolName) { - return redisTemplate.opsForValue() - .get(REDIS_KEY_SCHOOL_CURRENT_APPLICATIONS + schoolName); + public void deleteCurrentApplications(String schoolName) { + String key = ExamQuotaPrefix.CURRENT_APPLICATIONS.with(schoolName); + cacheWriter.delete(key); } - public Long getSchoolCapacities(String schoolName) { - return redisTemplate.opsForValue() - .get(REDIS_KEY_SCHOOL_MAX_CAPACITY + schoolName); + public void increaseCurrentApplications(String schoolName) { + String key = ExamQuotaPrefix.CURRENT_APPLICATIONS.with(schoolName); + cacheWriter.increase(key); } - public void increaseApplicationCount(String schoolName) { - String key = REDIS_KEY_SCHOOL_CURRENT_APPLICATIONS + schoolName; - redisTemplate.opsForValue().increment(key); + public void decreaseCurrentApplications(String schoolName) { + String key = ExamQuotaPrefix.CURRENT_APPLICATIONS.with(schoolName); + cacheWriter.decrease(key); } - public void decreaseApplicationCount(String schoolName) { - String key = REDIS_KEY_SCHOOL_CURRENT_APPLICATIONS + schoolName; - Long currentValue = redisTemplate.opsForValue().get(key); - if (currentValue != null && currentValue > 0) { - redisTemplate.opsForValue().decrement(key); - } + @Override + protected void initCache() { + examJpaRepository.findUpcomingExamInfo(LocalDate.now()) + .forEach(exam -> setMaxCapacity( + exam.getSchoolName(), + exam.getCapacity().longValue() + )); + examJpaRepository.countApplicationsGroupedBySchoolName() + .forEach(projection -> setCurrentApplications( + projection.schoolName(), + projection.applicationCount() + )); } - public void preloadSchoolData() { - cacheSchoolMaxCapacities(); - cacheSchoolCurrentApplicationCounts(); + @RequiredArgsConstructor + @Getter + private enum ExamQuotaPrefix { + MAX_CAPACITY("school:max_capacity:"), + CURRENT_APPLICATIONS("school:current_applications:"); + + private final String prefix; + + public String with(String schoolName) { + return prefix + schoolName; + } } } \ No newline at end of file From 4cf633924d581a118a71e872ee930e660549016f Mon Sep 17 00:00:00 2001 From: KNU-K Date: Sat, 26 Jul 2025 00:49:41 +0900 Subject: [PATCH 07/13] =?UTF-8?q?MOSU=20chore:=20ExamQuotaEventListener=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20?= =?UTF-8?q?=EC=9D=B4=EB=B2=A4=ED=8A=B8=20=EC=B2=98=EB=A6=AC=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exam/ExamQuotaEventListener.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/main/java/life/mosu/mosuserver/presentation/exam/ExamQuotaEventListener.java diff --git a/src/main/java/life/mosu/mosuserver/presentation/exam/ExamQuotaEventListener.java b/src/main/java/life/mosu/mosuserver/presentation/exam/ExamQuotaEventListener.java new file mode 100644 index 00000000..d39b8f2b --- /dev/null +++ b/src/main/java/life/mosu/mosuserver/presentation/exam/ExamQuotaEventListener.java @@ -0,0 +1,18 @@ +package life.mosu.mosuserver.presentation.exam; + +import life.mosu.mosuserver.application.exam.ExamQuotaService; +import life.mosu.mosuserver.global.annotation.ReactiveEventListener; +import life.mosu.mosuserver.presentation.exam.dto.event.ExamQuotaEvent; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class ExamQuotaEventListener { + private final ExamQuotaService examQuotaService; + + @ReactiveEventListener + public void handleExamQuotaEvent(ExamQuotaEvent event) { + examQuotaService.handleExamQuotaEvent(event); + } +} From 6414d8b919ca515a410f900c8ca8bb525130709a Mon Sep 17 00:00:00 2001 From: KNU-K Date: Sat, 26 Jul 2025 00:49:48 +0900 Subject: [PATCH 08/13] =?UTF-8?q?MOSU=20chore:=20SwaggerConfig=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EC=84=9C=EB=B2=84=20=EB=AA=A9=EB=A1=9D=EC=9D=84=20?= =?UTF-8?q?List.of()=EB=A1=9C=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../infra/config/SwaggerConfig.java | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/main/java/life/mosu/mosuserver/infra/config/SwaggerConfig.java b/src/main/java/life/mosu/mosuserver/infra/config/SwaggerConfig.java index d2bdd88d..b3b82aac 100644 --- a/src/main/java/life/mosu/mosuserver/infra/config/SwaggerConfig.java +++ b/src/main/java/life/mosu/mosuserver/infra/config/SwaggerConfig.java @@ -9,21 +9,20 @@ @Configuration public class SwaggerConfig { - + private final List servers = List.of( + new Server().url("https://api.mosuedu.com/api/v1") + .description("MOSU SERVER"), + new Server().url("http://localhost:8080/api/v1") + .description("Local Development Server"), + new Server().url("http://192.168.35.174:8080/api/v1") + .description("Custom Development Server") + ); @Bean public OpenAPI customOpenAPI() { return new OpenAPI() .info(new Info() .title("MOSU API 문서") .version("1.0.0") - ).servers(List.of( - new Server().url("https://api.mosuedu.com/api/v1") - .description("MOSU SERVER"), - new Server().url("http://localhost:8080/api/v1") - .description("Local Development Server"), - - new Server().url("http://192.168.35.174:8080/api/v1") - .description("Custom Development Server") - )); + ).servers(servers); } } \ No newline at end of file From f5ff372d5fb8cbf4d0ab41e61e1833f9b37bb726 Mon Sep 17 00:00:00 2001 From: KNU-K Date: Sat, 26 Jul 2025 00:49:58 +0900 Subject: [PATCH 09/13] =?UTF-8?q?MOSU=20chore:=20ExamQuotaService=20?= =?UTF-8?q?=EB=B0=8F=20ExamQuotaEventResolver=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=EC=9D=B4=EB=B2=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=B2=98=EB=A6=AC=20=EB=A1=9C=EC=A7=81=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/exam/ExamQuotaService.java | 19 ++++++ .../application/exam/ExamService.java | 16 ++--- .../exam/resolver/ExamQuotaEventResolver.java | 60 +++++++++++++++++++ 3 files changed, 87 insertions(+), 8 deletions(-) create mode 100644 src/main/java/life/mosu/mosuserver/application/exam/ExamQuotaService.java create mode 100644 src/main/java/life/mosu/mosuserver/application/exam/resolver/ExamQuotaEventResolver.java diff --git a/src/main/java/life/mosu/mosuserver/application/exam/ExamQuotaService.java b/src/main/java/life/mosu/mosuserver/application/exam/ExamQuotaService.java new file mode 100644 index 00000000..d83ddbbf --- /dev/null +++ b/src/main/java/life/mosu/mosuserver/application/exam/ExamQuotaService.java @@ -0,0 +1,19 @@ +package life.mosu.mosuserver.application.exam; + +import java.util.function.Consumer; +import life.mosu.mosuserver.application.exam.resolver.ExamQuotaEventResolver; +import life.mosu.mosuserver.presentation.exam.dto.event.ExamQuotaEvent; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class ExamQuotaService { + + private final ExamQuotaEventResolver resolver; + + public void handleExamQuotaEvent(ExamQuotaEvent event) { + Consumer handler = resolver.resolve(event); + handler.accept(event); + } +} diff --git a/src/main/java/life/mosu/mosuserver/application/exam/ExamService.java b/src/main/java/life/mosu/mosuserver/application/exam/ExamService.java index 57ee203c..13926685 100644 --- a/src/main/java/life/mosu/mosuserver/application/exam/ExamService.java +++ b/src/main/java/life/mosu/mosuserver/application/exam/ExamService.java @@ -4,9 +4,12 @@ import life.mosu.mosuserver.domain.exam.Area; import life.mosu.mosuserver.domain.exam.ExamJpaEntity; import life.mosu.mosuserver.domain.exam.ExamJpaRepository; +import life.mosu.mosuserver.presentation.exam.dto.event.ExamQuotaEvent; import life.mosu.mosuserver.presentation.exam.dto.ExamRequest; import life.mosu.mosuserver.presentation.exam.dto.ExamResponse; +import life.mosu.mosuserver.presentation.exam.dto.event.ExamQuotaEventType; import lombok.RequiredArgsConstructor; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; @Service @@ -15,21 +18,18 @@ public class ExamService { private final ExamJpaRepository examJpaRepository; private final ExamQuotaCacheManager examQuotaCacheManager; + private final ApplicationEventPublisher publisher; public void register(ExamRequest request) { ExamJpaEntity exam = request.toEntity(); ExamJpaEntity savedExam = examJpaRepository.save(exam); - examQuotaCacheManager.addSchoolCurrentApplicationCount( + publisher.publishEvent(ExamQuotaEvent.ofMultipleCommand( + ExamQuotaEventType.LOAD, savedExam.getSchoolName(), - 0L - ); - examQuotaCacheManager.addSchoolMaxCapacity( - savedExam.getSchoolName(), - savedExam.getCapacity() - ); + savedExam.getCapacity().longValue() + )); } - public List getByArea(String areaName) { Area area = Area.from(areaName); List foundExams = examJpaRepository.findByArea(area); diff --git a/src/main/java/life/mosu/mosuserver/application/exam/resolver/ExamQuotaEventResolver.java b/src/main/java/life/mosu/mosuserver/application/exam/resolver/ExamQuotaEventResolver.java new file mode 100644 index 00000000..d00ff097 --- /dev/null +++ b/src/main/java/life/mosu/mosuserver/application/exam/resolver/ExamQuotaEventResolver.java @@ -0,0 +1,60 @@ +package life.mosu.mosuserver.application.exam.resolver; + +import java.util.function.Consumer; +import life.mosu.mosuserver.application.exam.ExamQuotaCacheManager; +import life.mosu.mosuserver.presentation.exam.dto.event.ApplicationStatus; +import life.mosu.mosuserver.presentation.exam.dto.event.ExamQuotaEvent; +import life.mosu.mosuserver.presentation.exam.dto.event.MaxCapacityStatus; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class ExamQuotaEventResolver { + + private final ExamQuotaCacheManager examQuotaCacheManager; + + public Consumer resolve(ExamQuotaEvent event) { + return switch (event.getType()) { + case LOAD -> resolveLoad(event); + case DELETE_ALL -> resolveDeleteAll(event); + case CURRENT_APPLICATION -> resolveCurrentApplication(event); + case MAX_CAPACITY -> resolveMaxCapacity(event); + }; + } + + private Consumer resolveLoad(ExamQuotaEvent event) { + return e -> { + examQuotaCacheManager.setMaxCapacity(e.getSchoolName(), e.getValue()); + examQuotaCacheManager.setCurrentApplications(e.getSchoolName(),0L); + }; + } + private Consumer resolveDeleteAll(ExamQuotaEvent event){ + return e -> { + examQuotaCacheManager.deleteMaxCapacity(e.getSchoolName()); + examQuotaCacheManager.deleteCurrentApplications(e.getSchoolName()); + }; + } + private Consumer resolveCurrentApplication(ExamQuotaEvent event) { + if (!(event.getStatus() instanceof ApplicationStatus status)) { + throw new IllegalArgumentException("Invalid status for CURRENT_APPLICATION event"); + } + + return switch (status) { + case CREATE -> e -> examQuotaCacheManager.setCurrentApplications(e.getSchoolName(), e.getValue()); + case INCREASE -> e -> examQuotaCacheManager.increaseCurrentApplications(e.getSchoolName()); + case DECREASE -> e -> examQuotaCacheManager.decreaseCurrentApplications(e.getSchoolName()); + case DELETE -> e -> examQuotaCacheManager.deleteCurrentApplications(e.getSchoolName()); + }; + } + + private Consumer resolveMaxCapacity(ExamQuotaEvent event) { + if (!(event.getStatus() instanceof MaxCapacityStatus status)) { + throw new IllegalArgumentException("Invalid status for MAX_CAPACITY event"); + } + return switch (status) { + case CREATE, UPDATE -> e -> examQuotaCacheManager.setMaxCapacity(e.getSchoolName(), e.getValue()); + case DELETE -> e -> examQuotaCacheManager.deleteMaxCapacity(e.getSchoolName()); + }; + } +} From 5330d2afe2ebd5fe1c5bd2ad8ff04addb59c3662 Mon Sep 17 00:00:00 2001 From: KNU-K Date: Sat, 26 Jul 2025 00:57:05 +0900 Subject: [PATCH 10/13] =?UTF-8?q?MOSU=20chore:=20ExamQuotaEventType?= =?UTF-8?q?=EC=97=90=EC=84=9C=20CURRENT=5FAPPLICATION=20=EB=B0=8F=20MAX=5F?= =?UTF-8?q?CAPACITY=EC=9D=98=20=EC=9C=A0=ED=9A=A8=20=EC=83=81=ED=83=9C=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/exam/dto/event/ExamQuotaEventType.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/life/mosu/mosuserver/presentation/exam/dto/event/ExamQuotaEventType.java b/src/main/java/life/mosu/mosuserver/presentation/exam/dto/event/ExamQuotaEventType.java index 53ac5544..504868bf 100644 --- a/src/main/java/life/mosu/mosuserver/presentation/exam/dto/event/ExamQuotaEventType.java +++ b/src/main/java/life/mosu/mosuserver/presentation/exam/dto/event/ExamQuotaEventType.java @@ -4,8 +4,8 @@ public enum ExamQuotaEventType { // Single Commands - CURRENT_APPLICATION(Set.of(ApplicationStatus.INCREASE, ApplicationStatus.CREATE)), - MAX_CAPACITY(Set.of(MaxCapacityStatus.CREATE, MaxCapacityStatus.UPDATE)), + CURRENT_APPLICATION(Set.of(ApplicationStatus.INCREASE, ApplicationStatus.CREATE, ApplicationStatus.DELETE)), + MAX_CAPACITY(Set.of(MaxCapacityStatus.CREATE, MaxCapacityStatus.UPDATE, ApplicationStatus.DELETE)), // Multiple Commands LOAD(Set.of()), From 6a26113ac698898f53a9d11b8c36fb434b7be32a Mon Sep 17 00:00:00 2001 From: KNU-K Date: Sat, 26 Jul 2025 00:57:57 +0900 Subject: [PATCH 11/13] =?UTF-8?q?MOSU=20chore:=20DefaultRedisCacheReader?= =?UTF-8?q?=EC=97=90=EC=84=9C=20read=20=EB=A9=94=EC=84=9C=EB=93=9C?= =?UTF-8?q?=EC=9D=98=20null=20=EC=B2=98=EB=A6=AC=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../infra/persistence/redis/DefaultRedisCacheReader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/life/mosu/mosuserver/infra/persistence/redis/DefaultRedisCacheReader.java b/src/main/java/life/mosu/mosuserver/infra/persistence/redis/DefaultRedisCacheReader.java index f82053cc..812f5ab7 100644 --- a/src/main/java/life/mosu/mosuserver/infra/persistence/redis/DefaultRedisCacheReader.java +++ b/src/main/java/life/mosu/mosuserver/infra/persistence/redis/DefaultRedisCacheReader.java @@ -13,6 +13,6 @@ public class DefaultRedisCacheReader implements CacheReader { @Override public Optional read(String key) { - return Optional.of(redisTemplate.opsForValue().get(key)); + return Optional.ofNullable(redisTemplate.opsForValue().get(key)); } } From 77e83d36d0c37d313a8137f56315c7d7c464a834 Mon Sep 17 00:00:00 2001 From: KNU-K Date: Sat, 26 Jul 2025 01:02:33 +0900 Subject: [PATCH 12/13] =?UTF-8?q?MOSU=20chore:=20ExamService=EC=97=90?= =?UTF-8?q?=EC=84=9C=20ExamQuotaEvent=20=EC=9E=84=ED=8F=AC=ED=8A=B8=20?= =?UTF-8?q?=EC=9C=84=EC=B9=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/life/mosu/mosuserver/application/exam/ExamService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/life/mosu/mosuserver/application/exam/ExamService.java b/src/main/java/life/mosu/mosuserver/application/exam/ExamService.java index 13926685..d04c9f6f 100644 --- a/src/main/java/life/mosu/mosuserver/application/exam/ExamService.java +++ b/src/main/java/life/mosu/mosuserver/application/exam/ExamService.java @@ -4,9 +4,9 @@ import life.mosu.mosuserver.domain.exam.Area; import life.mosu.mosuserver.domain.exam.ExamJpaEntity; import life.mosu.mosuserver.domain.exam.ExamJpaRepository; -import life.mosu.mosuserver.presentation.exam.dto.event.ExamQuotaEvent; import life.mosu.mosuserver.presentation.exam.dto.ExamRequest; import life.mosu.mosuserver.presentation.exam.dto.ExamResponse; +import life.mosu.mosuserver.presentation.exam.dto.event.ExamQuotaEvent; import life.mosu.mosuserver.presentation.exam.dto.event.ExamQuotaEventType; import lombok.RequiredArgsConstructor; import org.springframework.context.ApplicationEventPublisher; From f2f15b441f7409dc9c1c3fe041487d0a51304ee3 Mon Sep 17 00:00:00 2001 From: KNU-K Date: Sat, 26 Jul 2025 01:03:45 +0900 Subject: [PATCH 13/13] chore: Update MAX_CAPACITY event status to include MaxCapacityStatus.DELETE --- .../presentation/exam/dto/event/ExamQuotaEventType.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/life/mosu/mosuserver/presentation/exam/dto/event/ExamQuotaEventType.java b/src/main/java/life/mosu/mosuserver/presentation/exam/dto/event/ExamQuotaEventType.java index 504868bf..c4f9644d 100644 --- a/src/main/java/life/mosu/mosuserver/presentation/exam/dto/event/ExamQuotaEventType.java +++ b/src/main/java/life/mosu/mosuserver/presentation/exam/dto/event/ExamQuotaEventType.java @@ -5,7 +5,7 @@ public enum ExamQuotaEventType { // Single Commands CURRENT_APPLICATION(Set.of(ApplicationStatus.INCREASE, ApplicationStatus.CREATE, ApplicationStatus.DELETE)), - MAX_CAPACITY(Set.of(MaxCapacityStatus.CREATE, MaxCapacityStatus.UPDATE, ApplicationStatus.DELETE)), + MAX_CAPACITY(Set.of(MaxCapacityStatus.CREATE, MaxCapacityStatus.UPDATE, MaxCapacityStatus.DELETE)), // Multiple Commands LOAD(Set.of()),