Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package hs.kr.entrydsm.status.domain.status.adapter.`in`.web

import hs.kr.entrydsm.status.domain.status.application.port.`in`.AnnounceResultUseCase
import hs.kr.entrydsm.status.domain.status.application.port.`in`.CancelApplicationSubmitUseCase
import hs.kr.entrydsm.status.domain.status.application.port.`in`.StartScreeningUseCase
import hs.kr.entrydsm.status.domain.status.application.port.`in`.UpdateIsPrintsArrivedUseCase
import org.springframework.web.bind.annotation.PatchMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController

/**
* 관리자용 상태 관리 REST API 컨트롤러입니다.
* 관리자가 지원자의 상태를 직접 변경할 수 있는 기능을 제공합니다.
*
* @property updateIsPrintsArrivedUseCase 서류 도착 상태 변경 유스케이스
* @property cancelApplicationSubmitUseCase 지원서 제출 취소 유스케이스
* @property startScreeningUseCase 전형 시작 유스케이스
* @property announceResultUseCase 합격 발표 유스케이스
*/
@RestController
@RequestMapping("/admin/status")
class AdminWebController(
private val updateIsPrintsArrivedUseCase: UpdateIsPrintsArrivedUseCase,
private val cancelApplicationSubmitUseCase: CancelApplicationSubmitUseCase,
private val startScreeningUseCase: StartScreeningUseCase,
private val announceResultUseCase: AnnounceResultUseCase
) {

/**
* 지원서 제출을 취소합니다.
* 제출된 지원서를 작성 중 상태로 되돌립니다.
*
* @param receiptCode 접수번호
*/
@PatchMapping("/submitted/{receipt-code}")
fun cancelApplicationSubmit(@PathVariable("receipt-code") receiptCode: Long) {
cancelApplicationSubmitUseCase.execute(receiptCode)
}

/**
* 서류 도착을 확인합니다.
* 등기우편으로 제출된 서류의 도착을 관리자가 확인하여 상태를 변경합니다.
*
* @param receiptCode 접수번호
*/
@PatchMapping("/prints-arrived/{receipt-code}")
fun updateIsPrintsArrivedService(@PathVariable("receipt-code") receiptCode: Long) {
updateIsPrintsArrivedUseCase.execute(receiptCode)
}

/**
* 전형을 시작합니다.
* 서류 검토가 완료된 후 1차 또는 2차 전형을 시작합니다.
*
* @param receiptCode 접수번호
*/
@PatchMapping("/screening/{receipt-code}")
fun startScreening(@PathVariable("receipt-code") receiptCode: Long) {
startScreeningUseCase.execute(receiptCode)
}

/**
* 합격 결과를 발표합니다.
* 최종 전형 결과를 발표하고 상태를 변경합니다.
*
* @param receiptCode 접수번호
*/
@PatchMapping("/announce/{receipt-code}")
fun announceResult(@PathVariable("receipt-code") receiptCode: Long) {
announceResultUseCase.execute(receiptCode)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package hs.kr.entrydsm.status.domain.status.adapter.`in`.web

import hs.kr.entrydsm.status.domain.status.application.port.`in`.GetAllStatusUseCase
import hs.kr.entrydsm.status.domain.status.application.port.`in`.GetStatusByReceiptCodeUseCase
import hs.kr.entrydsm.status.infrastructure.grpc.server.dto.response.InternalStatusResponse
import hs.kr.entrydsm.status.domain.status.application.port.`in`.UpdateExamCodeUseCase
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PutMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController

/**
* 내부 시스템용 상태 조회 REST API 컨트롤러입니다.
* 다른 마이크로서비스에서 지원자의 상태 정보를 조회할 수 있는 기능을 제공합니다.
*
* @property getStatusByReceiptCodeUseCase 접수번호별 상태 조회 유스케이스
* @property getAllStatusUseCase 전체 상태 조회 유스케이스
* @property updateExamCodeUseCase 수험번호 업데이트 유스케이스
*/
@RestController
@RequestMapping("/internal/status")
class InternalStatusWebController(
private val getStatusByReceiptCodeUseCase: GetStatusByReceiptCodeUseCase,
private val getAllStatusUseCase: GetAllStatusUseCase,
private val updateExamCodeUseCase: UpdateExamCodeUseCase
) {

/**
* 접수번호로 상태를 조회합니다.
*
* @param receiptCode 접수번호
* @return 지원자의 상태 정보
*/
@GetMapping("/{receipt-code}")
fun getStatusByReceiptCode(@PathVariable("receipt-code") receiptCode: Long): InternalStatusResponse {
return getStatusByReceiptCodeUseCase.execute(receiptCode)
}

/**
* 모든 지원자의 상태 목록을 조회합니다.
*
* @return 전체 지원자 상태 정보 목록
*/
@GetMapping("/list")
fun getAllStatus(): List<InternalStatusResponse> {
return getAllStatusUseCase.execute()
}

/**
* 수험번호를 업데이트합니다.
*
* @param receiptCode 접수번호
* @param examCode 새로운 수험번호
*/
@PutMapping("/{receipt-code}")
fun updateExamCode(@PathVariable("receipt-code") receiptCode: Long, @RequestParam examCode: String) {
updateExamCodeUseCase.execute(receiptCode, examCode)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package hs.kr.entrydsm.status.domain.status.adapter.out.domain

import hs.kr.entrydsm.status.domain.status.model.ApplicationStatus
import hs.kr.entrydsm.status.domain.status.model.Status
import org.springframework.data.annotation.Id
import org.springframework.data.redis.core.RedisHash
import org.springframework.data.redis.core.TimeToLive

/**
* Redis 캐시용 상태 엔티티 클래스입니다.
* 상태 조회 성능 향상을 위한 캐시 데이터를 관리합니다.
*
* @property receiptCode 접수번호 (Redis 키로 사용)
* @property applicationStatus 지원 상태
* @property examCode 수험번호
* @property isFirstRoundPass 1차 전형 합격 여부
* @property isSecondRoundPass 2차 전형 합격 여부
* @property ttl Time To Live (캐시 만료 시간, 초 단위)
*/
@RedisHash(value = "status_cache")
class StatusCache(
@Id
val receiptCode: Long,

val applicationStatus: ApplicationStatus,

val examCode: String?,

val isFirstRoundPass: Boolean,

val isSecondRoundPass: Boolean,

@TimeToLive
var ttl: Long
){
companion object{
/**
* Status 도메인 모델로부터 StatusCache 인스턴스를 생성합니다.
*
* @param status 도메인 모델 Status 인스턴스
* @return StatusCache 인스턴스 (TTL 10분으로 설정)
*/
fun from(status: Status): StatusCache {
return StatusCache(
receiptCode = status.receiptCode,
applicationStatus = status.applicationStatus,
examCode = status.examCode,
isFirstRoundPass = status.isFirstRoundPass,
isSecondRoundPass = status.isSecondRoundPass,
ttl = 60 * 10
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package hs.kr.entrydsm.status.domain.status.adapter.out.domain

import hs.kr.entrydsm.status.domain.status.model.ApplicationStatus
import jakarta.persistence.Column
import jakarta.persistence.Entity
import jakarta.persistence.EnumType
import jakarta.persistence.Enumerated
import jakarta.persistence.GeneratedValue
import jakarta.persistence.GenerationType
import jakarta.persistence.Id

/**
* 지원 상태 정보를 저장하는 JPA 엔티티 클래스입니다.
* 데이터베이스의 status 테이블과 매핑되며, 지원자의 전형 진행 상태를 관리합니다.
*
* @property applicationStatus 현재 지원 상태
* @property examCode 수험번호 (고유값)
* @property isFirstRoundPass 1차 전형 합격 여부
* @property isSecondRoundPass 2차 전형 합격 여부
* @property receiptCode 접수번호
* @property id 데이터베이스 기본키 (자동 생성)
*/
@Entity(name = "status")
class StatusJpaEntity(
@Enumerated(EnumType.STRING)
@Column(name = "application_status")
var applicationStatus: ApplicationStatus = ApplicationStatus.NOT_APPLIED,
@Column(unique = true)
var examCode: String? = null,
var isFirstRoundPass: Boolean = false,
var isSecondRoundPass: Boolean = false,
val receiptCode: Long
) {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package hs.kr.entrydsm.status.domain.status.adapter.out.mapper

import hs.kr.entrydsm.status.domain.status.adapter.out.domain.StatusJpaEntity
import hs.kr.entrydsm.status.domain.status.model.Status
import hs.kr.entrydsm.status.global.mapper.GenericMapper
import org.mapstruct.Mapper

/**
* Status 도메인 모델과 StatusJpaEntity 간의 변환을 담당하는 매퍼 클래스입니다.
* MapStruct를 사용하여 도메인 계층과 인프라스트럭처 계층 간의 데이터 변환을 처리합니다.
*/
@Mapper(componentModel = "spring")
abstract class StatusMapper: GenericMapper<StatusJpaEntity, Status> {

/**
* Status 도메인 모델을 StatusJpaEntity로 변환합니다.
*
* @param model 변환할 Status 도메인 모델
* @return 변환된 StatusJpaEntity
*/
abstract override fun toEntity(model: Status): StatusJpaEntity

/**
* StatusJpaEntity를 Status 도메인 모델로 변환합니다.
*
* @param entity 변환할 StatusJpaEntity (null 가능)
* @return 변환된 Status 도메인 모델 (null 가능)
*/
abstract override fun toModel(entity: StatusJpaEntity?): Status?

/**
* StatusJpaEntity를 Status 도메인 모델로 변환합니다.
* null이 아닌 entity를 받아 null이 아닌 모델을 반환합니다.
*
* @param entity 변환할 StatusJpaEntity (null이 아님)
* @return 변환된 Status 도메인 모델 (null이 아님)
*/
abstract override fun toModelNotNull(entity: StatusJpaEntity): Status
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package hs.kr.entrydsm.status.domain.status.adapter.out.persistence

import hs.kr.entrydsm.status.domain.status.adapter.out.mapper.StatusMapper
import hs.kr.entrydsm.status.domain.status.adapter.out.persistence.repository.StatusRepository
import hs.kr.entrydsm.status.domain.status.application.port.out.StatusPort
import hs.kr.entrydsm.status.domain.status.model.Status
import org.springframework.stereotype.Component

/**
* 상태 데이터의 영속성 처리를 담당하는 어댑터 클래스입니다.
* 헥사고날 아키텍처의 Driven Adapter 역할을 하며, 도메인 계층의 StatusPort를 구현합니다.
*
* @property statusRepository JPA 기반 상태 데이터 저장소
* @property statusMapper 도메인 모델과 JPA 엔티티 간 변환 매퍼
*/
@Component
class StatusPersistenceAdapter(
private val statusRepository: StatusRepository,
private val statusMapper: StatusMapper,
): StatusPort {

/**
* 상태 정보를 저장합니다.
*
* @param status 저장할 상태 도메인 모델
*/
override fun save(status: Status) {
statusRepository.save(statusMapper.toEntity(status))
}

/**
* 접수번호로 상태 정보를 조회합니다.
*
* @param receiptCode 조회할 접수번호
* @return 조회된 상태 도메인 모델 (없으면 null)
*/
override fun findByReceiptCode(receiptCode: Long): Status? =
statusRepository.findByReceiptCode(receiptCode)?.let { statusMapper.toModel(it) }

/**
* 모든 상태 정보를 조회합니다.
*
* @return 모든 상태 도메인 모델 리스트
*/
override fun findAll(): List<Status> {
return statusRepository.findAll()
.map { statusMapper.toModelNotNull(it) }
}

/**
* 접수번호로 상태 정보를 삭제합니다.
*
* @param receiptCode 삭제할 접수번호
*/
override fun deleteByReceiptCode(receiptCode: Long) {
statusRepository.deleteByReceiptCode(receiptCode)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package hs.kr.entrydsm.status.domain.status.adapter.out.persistence.repository

import hs.kr.entrydsm.status.domain.status.adapter.out.domain.StatusCache
import org.springframework.data.repository.CrudRepository

/**
* 상태 캐시를 위한 Redis 저장소 인터페이스입니다.
* Spring Data Redis를 통해 상태 정보의 캐시 관리를 담당합니다.
*/
interface StatusCacheRepository : CrudRepository<StatusCache, Long>
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package hs.kr.entrydsm.status.domain.status.adapter.out.persistence.repository

import hs.kr.entrydsm.status.domain.status.adapter.out.domain.StatusJpaEntity
import org.springframework.data.repository.CrudRepository

/**
* 상태 JPA 엔티티를 위한 저장소 인터페이스입니다.
* Spring Data JPA를 통해 기본 CRUD 작업과 커스텀 쿼리를 제공합니다.
*/
interface StatusRepository : CrudRepository<StatusJpaEntity, Long> {

/**
* 접수번호로 상태 엔티티를 조회합니다.
*
* @param receiptCode 조회할 접수번호
* @return 조회된 상태 엔티티 (없으면 null)
*/
fun findByReceiptCode(receiptCode: Long): StatusJpaEntity?

/**
* 접수번호로 상태 엔티티를 삭제합니다.
*
* @param receiptCode 삭제할 접수번호
*/
fun deleteByReceiptCode(receiptCode: Long)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package hs.kr.entrydsm.status.domain.status.application.port.`in`

/**
* 합격 결과 발표 유스케이스 인터페이스입니다.
* 최종 전형 결과를 발표하고 상태를 변경하는 기능을 정의합니다.
*/
interface AnnounceResultUseCase {

/**
* 합격 결과를 발표합니다.
* 전형 진행 중 상태에서 합격 여부 확인 상태로 변경합니다.
*
* @param receiptCode 접수번호
*/
fun execute(receiptCode: Long)
}
Loading