66} from '../../schemas/mclass/index.js' ;
77import { MClassError } from '../../common/exception/mclass/MClassError.js' ;
88import logger from '../../config/logger.config.js' ;
9+ import { redis } from '../../config/redis.config.js' ;
910
1011export type MClassPhase = 'UPCOMING' | 'RECRUITING' | 'IN_PROGRESS' | 'ENDED' ;
1112
@@ -40,9 +41,9 @@ export class MClassService {
4041 constructor ( private repository : MClassRepository ) { }
4142
4243 /**
43- * Phase 계산 로직 (실시간 approvedCount 사용)
44+ * Phase 계산 로직 (이미 조회된 approvedCount 사용)
4445 */
45- private async calculatePhase ( mclass : any ) : Promise < MClassPhase > {
46+ private calculatePhase ( mclass : any ) : MClassPhase {
4647 const now = new Date ( ) ;
4748 const {
4849 recruitStartAt,
@@ -51,6 +52,7 @@ export class MClassService {
5152 endAt,
5253 visibility,
5354 capacity,
55+ approvedCount = 0 , // 기본값 0
5456 } = mclass ;
5557
5658 // 종료됨 (가장 우선 체크)
@@ -68,15 +70,14 @@ export class MClassService {
6870 return 'UPCOMING' ;
6971 }
7072
71- // RECRUITING: 모집 중 (실시간 approvedCount 계산 )
73+ // RECRUITING: 모집 중 (이미 조회된 approvedCount 사용 )
7274 if (
7375 recruitStartAt &&
7476 recruitEndAt &&
7577 now >= recruitStartAt &&
7678 now < recruitEndAt &&
7779 visibility === 'PUBLIC'
7880 ) {
79- const approvedCount = await this . repository . getApprovedCount ( mclass . id ) ;
8081 if ( capacity === null || approvedCount < capacity ) {
8182 return 'RECRUITING' ;
8283 }
@@ -95,7 +96,7 @@ export class MClassService {
9596 * MClass 데이터에 phase 추가 및 Date를 문자열로 변환
9697 */
9798 private async addPhaseToMClass ( mclass : any ) : Promise < MClassWithPhase > {
98- const phase = await this . calculatePhase ( mclass ) ;
99+ const phase = this . calculatePhase ( mclass ) ;
99100 return {
100101 ...mclass ,
101102 phase,
@@ -183,13 +184,34 @@ export class MClassService {
183184 logger . info ( `[MClassService] MClass 단일 조회 시작: ${ id } ` ) ;
184185
185186 try {
187+ const cachedMClass = await redis . get ( `mclass:${ id } ` ) ;
188+ if ( cachedMClass ) {
189+ const mclass = JSON . parse ( cachedMClass ) ;
190+ logger . info ( `[MClassService] MClass 캐시에서 조회: ${ id } ` ) ;
191+ return this . addPhaseToMClass ( mclass ) ;
192+ }
193+
186194 const mclass = await this . repository . findById ( id ) ;
187195 if ( ! mclass ) {
188196 logger . warn ( `[MClassService] MClass를 찾을 수 없음: ${ id } ` ) ;
189197 throw MClassError . notFound ( id ) ;
190198 }
191199
192200 const result = await this . addPhaseToMClass ( mclass ) ;
201+
202+ // 캐시에 저장 (5분간)
203+ try {
204+ await redis . setex ( `mclass:${ id } ` , 300 , JSON . stringify ( mclass ) ) ;
205+ logger . info ( `[MClassService] MClass 캐시에 저장: ${ id } ` ) ;
206+ } catch ( cacheError ) {
207+ logger . warn ( `[MClassService] MClass 캐시 저장 실패: ${ id } ` , {
208+ error :
209+ cacheError instanceof Error
210+ ? cacheError . message
211+ : String ( cacheError ) ,
212+ } ) ;
213+ }
214+
193215 logger . info (
194216 `[MClassService] MClass 단일 조회 성공: ${ id } , Phase: ${ result . phase } `
195217 ) ;
@@ -267,7 +289,7 @@ export class MClassService {
267289 }
268290
269291 // 모집 중인 클래스 수정 제한 체크
270- const currentPhase = await this . calculatePhase ( existingMClass ) ;
292+ const currentPhase = this . calculatePhase ( existingMClass ) ;
271293 if ( currentPhase === 'RECRUITING' ) {
272294 logger . warn (
273295 `[MClassService] 모집 중인 MClass 수정 시도: ${ id } , Phase: ${ currentPhase } `
@@ -304,7 +326,7 @@ export class MClassService {
304326 }
305327
306328 // 진행 중인 클래스 삭제 제한 체크
307- const currentPhase = await this . calculatePhase ( existingMClass ) ;
329+ const currentPhase = this . calculatePhase ( existingMClass ) ;
308330 if ( currentPhase === 'IN_PROGRESS' ) {
309331 logger . warn (
310332 `[MClassService] 진행 중인 MClass 삭제 시도: ${ id } , Phase: ${ currentPhase } `
0 commit comments