Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
0e66296
feat ( #10 ) : 레거시 코드 가져오기 & 루트의 src를 모듈로 따로 분리
qkrwndnjs1075 Jun 8, 2025
327b9f7
feat ( #11 ) : build logic, buildSrc 모듈로 마이그레이션
qkrwndnjs1075 Jun 8, 2025
261ff65
feat ( #12 ) : proto 파일 추가
qkrwndnjs1075 Jun 8, 2025
d04d42b
feat ( #12 ) : gRPC 의존성 설정 및 세팅
qkrwndnjs1075 Jun 8, 2025
04830be
feat ( #9 ) : application의 in/port 추가
qkrwndnjs1075 Jul 28, 2025
5f23664
feat ( #9 ) : application의 out/port 추가
qkrwndnjs1075 Jul 28, 2025
ad919ce
feat ( #9 ) : application의 service 추가
qkrwndnjs1075 Jul 28, 2025
a1cff73
feat ( #9 ) : 패키지 변경으로 삭제된 클래스들
qkrwndnjs1075 Jul 28, 2025
5422873
feat ( #9 ) : model 추가
qkrwndnjs1075 Jul 28, 2025
93ccf4b
feat ( #9 ) : exception 추가
qkrwndnjs1075 Jul 28, 2025
cf5583f
feat ( #9 ) : facacde 추가
qkrwndnjs1075 Jul 28, 2025
6c80d03
feat ( #9 ) : adapter/in 추가
qkrwndnjs1075 Jul 28, 2025
37f1826
feat ( #9 ) : adapter/in dto 추가
qkrwndnjs1075 Jul 28, 2025
6780a0e
feat ( #9 ) : adapter/out에 JpaEntity && domain 추가
qkrwndnjs1075 Jul 28, 2025
4188b09
feat ( #9 ) : mapper 추가
qkrwndnjs1075 Jul 28, 2025
b07bc0c
feat ( #9 ) : persistence 레이어 추가
qkrwndnjs1075 Jul 28, 2025
e6d6a1a
fix ( #18 ) : conflict 해결
qkrwndnjs1075 Jul 28, 2025
673c1b1
refactor ( #9 ) : mapstruct가 자동 구현할 수 있도록 componentModel = "spring" 추가
qkrwndnjs1075 Jul 29, 2025
4b9ba22
refactor ( #9 ) : passInfo도 암호화 되어야 하기 때문에 Hash 기준으로 find 하도록 수정
qkrwndnjs1075 Jul 29, 2025
9d1bcae
refactor ( #9 ) : 쉼표 추가
qkrwndnjs1075 Jul 30, 2025
3d4667f
chore ( #9 ) : class 네임 변경
qkrwndnjs1075 Jul 31, 2025
c3994f9
chore ( #9 ) : controller -> webAdapter로 크래스 이름 변경
qkrwndnjs1075 Jul 31, 2025
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
11 changes: 0 additions & 11 deletions build-logic/build.gradle.kts

This file was deleted.

17 changes: 0 additions & 17 deletions build-logic/settings.gradle.kts

This file was deleted.

15 changes: 0 additions & 15 deletions build-logic/src/main/kotlin/io/casper/build/TestClass.kt

This file was deleted.

7 changes: 7 additions & 0 deletions buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
plugins {
`kotlin-dsl`
}

repositories {
mavenCentral()
}
51 changes: 51 additions & 0 deletions buildSrc/src/main/kotlin/Dependencies.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
object Dependencies {
// Spring Boot
const val SPRING_BOOT_STARTER = "org.springframework.boot:spring-boot-starter"
const val SPRING_BOOT_STARTER_WEB = "org.springframework.boot:spring-boot-starter-web"
const val SPRING_BOOT_STARTER_DATA_JPA = "org.springframework.boot:spring-boot-starter-data-jpa"
const val SPRING_BOOT_STARTER_DATA_REDIS = "org.springframework.boot:spring-boot-starter-data-redis"
const val SPRING_BOOT_STARTER_SECURITY = "org.springframework.boot:spring-boot-starter-security"
const val SPRING_BOOT_STARTER_VALIDATION = "org.springframework.boot:spring-boot-starter-validation"
const val SPRING_BOOT_STARTER_TEST = "org.springframework.boot:spring-boot-starter-test"

// Kotlin
const val KOTLIN_REFLECT = "org.jetbrains.kotlin:kotlin-reflect"
const val KOTLIN_TEST_JUNIT5 = "org.jetbrains.kotlin:kotlin-test-junit5"

// Database
const val MYSQL_CONNECTOR = "com.mysql:mysql-connector-j"

// JSON
const val JACKSON_MODULE_KOTLIN = "com.fasterxml.jackson.module:jackson-module-kotlin"
const val ORG_JSON = "org.json:json:${DependencyVersion.ORG_JSON}"

// JWT
const val JWT_API = "io.jsonwebtoken:jjwt-api:${DependencyVersion.JWT}"
const val JWT_IMPL = "io.jsonwebtoken:jjwt-impl:${DependencyVersion.JWT}"
const val JWT_JACKSON = "io.jsonwebtoken:jjwt-jackson:${DependencyVersion.JWT}"

// MapStruct
const val MAPSTRUCT = "org.mapstruct:mapstruct:${DependencyVersion.MAPSTRUCT}"
const val MAPSTRUCT_PROCESSOR = "org.mapstruct:mapstruct-processor:${DependencyVersion.MAPSTRUCT}"

// Test
const val JUNIT_PLATFORM_LAUNCHER = "org.junit.platform:junit-platform-launcher"

// gRPC
const val GRPC_NETTY_SHADED = "io.grpc:grpc-netty-shaded:${DependencyVersion.GRPC}"
const val GRPC_PROTOBUF = "io.grpc:grpc-protobuf:${DependencyVersion.GRPC}"
const val GRPC_STUB = "io.grpc:grpc-stub:${DependencyVersion.GRPC}"
const val GRPC_KOTLIN_STUB = "io.grpc:grpc-kotlin-stub:${DependencyVersion.GRPC_KOTLIN}"
const val PROTOBUF_KOTLIN = "com.google.protobuf:protobuf-kotlin:${DependencyVersion.PROTOBUF}"
const val GRPC_TESTING = "io.grpc:grpc-testing:${DependencyVersion.GRPC}"
const val GRPC_SERVER_SPRING_BOOT_STARTER = "net.devh:grpc-server-spring-boot-starter:${DependencyVersion.GRPC_SPRING_BOOT_STARTER}"

//OkCert
const val OKCERT_PATH = "src/main/webapp/WEB-INF/lib/OkCert3-java1.5-2.3.1.jar"

//swagger
const val SWAGGER = "org.springdoc:springdoc-openapi-starter-webmvc-ui:${DependencyVersion.SWAGGER}"

// Sentry
const val SENTRY_SPRING_BOOT_STARTER = "io.sentry:sentry-spring-boot-starter-jakarta:${DependencyVersion.SENTRY}"
}
20 changes: 20 additions & 0 deletions buildSrc/src/main/kotlin/DependencyVersion.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
object DependencyVersion {
const val KOTLIN = "1.9.25"
const val SPRING_BOOT = "3.4.4"
const val SPRING_DEPENDENCY_MANAGEMENT = "1.1.7"
const val DETEKT = "1.23.6"
const val KTLINT = "12.1.1"

const val JWT = "0.11.5"
const val ORG_JSON = "20230227"
const val MAPSTRUCT = "1.6.0"

const val GRPC = "1.61.1"
const val GRPC_KOTLIN = "1.4.1"
const val PROTOBUF = "3.25.3"
const val GRPC_SPRING_BOOT_STARTER = "3.1.0.RELEASE"

const val SWAGGER = "2.7.0"

const val SENTRY = "7.14.0"
}
11 changes: 11 additions & 0 deletions buildSrc/src/main/kotlin/Plugin.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
object Plugin {
const val KOTLIN_JVM = "org.jetbrains.kotlin.jvm"
const val KOTLIN_SPRING = "org.jetbrains.kotlin.plugin.spring"
const val KOTLIN_KAPT = "org.jetbrains.kotlin.kapt"
const val SPRING_BOOT = "org.springframework.boot"
const val SPRING_DEPENDENCY_MANAGEMENT = "io.spring.dependency-management"
const val DETEKT = "io.gitlab.arturbosch.detekt"
const val KTLINT = "org.jlleitschuh.gradle.ktlint"
const val CASPER_DOCUMENTATION = "casper.documentation-convention"
const val PROTOBUF = "com.google.protobuf"
}
8 changes: 8 additions & 0 deletions buildSrc/src/main/kotlin/PluginVersion.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
object PluginVersion {
const val KOTLIN_VERSION = "1.9.25"
const val SPRING_BOOT_VERSION = "3.4.4"
const val SPRING_DEPENDENCY_MANAGEMENT_VERSION = "1.1.7"
const val DETEKT_VERSION = "1.23.6"
const val KTLINT_VERSION = "12.1.1"
const val PROTOBUF_VERSION = "0.9.4"
}
113 changes: 113 additions & 0 deletions casper-user/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import org.gradle.kotlin.dsl.withType
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
id(Plugin.KOTLIN_JVM) version PluginVersion.KOTLIN_VERSION
id(Plugin.KOTLIN_SPRING) version PluginVersion.KOTLIN_VERSION
id(Plugin.KOTLIN_KAPT)
id(Plugin.SPRING_BOOT) version PluginVersion.SPRING_BOOT_VERSION
id(Plugin.SPRING_DEPENDENCY_MANAGEMENT) version PluginVersion.SPRING_DEPENDENCY_MANAGEMENT_VERSION
id(Plugin.CASPER_DOCUMENTATION)
id(Plugin.PROTOBUF) version PluginVersion.PROTOBUF_VERSION
}

dependencies {
// 스프링 부트 기본 기능
implementation(Dependencies.SPRING_BOOT_STARTER)

// 코틀린 리플렉션
implementation(Dependencies.KOTLIN_REFLECT)

// 스프링 부트 테스트 도구
testImplementation(Dependencies.SPRING_BOOT_STARTER_TEST)

// 코틀린 + JUnit5 테스트
testImplementation(Dependencies.KOTLIN_TEST_JUNIT5)

// JUnit5 실행 런처
testRuntimeOnly(Dependencies.JUNIT_PLATFORM_LAUNCHER)

// 웹 관련
implementation(Dependencies.SPRING_BOOT_STARTER_WEB)

// 데이터베이스
implementation(Dependencies.SPRING_BOOT_STARTER_DATA_JPA)
implementation(Dependencies.SPRING_BOOT_STARTER_DATA_REDIS)
runtimeOnly(Dependencies.MYSQL_CONNECTOR)

// 보안
implementation(Dependencies.SPRING_BOOT_STARTER_SECURITY)

// 검증
implementation(Dependencies.SPRING_BOOT_STARTER_VALIDATION)

// JSON 처리
implementation(Dependencies.JACKSON_MODULE_KOTLIN)
implementation(Dependencies.ORG_JSON)

// JWT
implementation(Dependencies.JWT_API)
implementation(Dependencies.JWT_IMPL)
runtimeOnly(Dependencies.JWT_JACKSON)

implementation(Dependencies.MAPSTRUCT)
kapt(Dependencies.MAPSTRUCT_PROCESSOR)

// grpc
implementation(Dependencies.GRPC_NETTY_SHADED)
implementation(Dependencies.GRPC_PROTOBUF)
implementation(Dependencies.GRPC_STUB)
implementation(Dependencies.GRPC_KOTLIN_STUB)
implementation(Dependencies.PROTOBUF_KOTLIN)
implementation(Dependencies.GRPC_SERVER_SPRING_BOOT_STARTER)
testImplementation(Dependencies.GRPC_TESTING)

// OkCert
implementation(files("$projectDir/${Dependencies.OKCERT_PATH}"))

// swagger
implementation(Dependencies.SWAGGER)

// Sentry
implementation(Dependencies.SENTRY_SPRING_BOOT_STARTER)
}

protobuf {
protoc {
artifact = "com.google.protobuf:protoc:${DependencyVersion.PROTOBUF}"
}
plugins {
create("grpc") {
artifact = "io.grpc:protoc-gen-grpc-java:${DependencyVersion.GRPC}"
}
create("grpckt") {
artifact = "io.grpc:protoc-gen-grpc-kotlin:${DependencyVersion.GRPC_KOTLIN}:jdk8@jar"
}
}
generateProtoTasks {
all().forEach {
it.plugins {
create("grpc")
create("grpckt")
}
}
}
}

repositories {
mavenCentral()
}

kotlin {
jvmToolchain(17)
}

tasks.withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs += "-Xjsr305=strict"
}
}

tasks.withType<Test> {
useJUnitPlatform()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package hs.kr.entrydsm.user.domain.admin.adapter.`in`.web.dto.request

import jakarta.validation.constraints.NotBlank

/**
* 관리자 로그인 요청 데이터를 담는 DTO 클래스입니다.
*/
data class AdminLoginRequest(
@NotBlank
val adminId: String,
@NotBlank
val password: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package hs.kr.entrydsm.user.domain.admin.application.service

import hs.kr.entrydsm.user.domain.admin.adapter.`in`.web.dto.request.AdminLoginRequest
import hs.kr.entrydsm.user.domain.admin.application.port.`in`.AdminLoginUseCase
import hs.kr.entrydsm.user.domain.admin.application.port.out.QueryAdminPort
import hs.kr.entrydsm.user.domain.admin.application.port.out.SaveAdminPort
import hs.kr.entrydsm.user.domain.admin.exception.AdminNotFoundException
import hs.kr.entrydsm.user.domain.user.adapter.out.domain.UserInfo
import hs.kr.entrydsm.user.domain.user.adapter.out.domain.UserRole
import hs.kr.entrydsm.user.domain.user.adapter.out.persistence.repository.UserInfoRepository
import hs.kr.entrydsm.user.domain.user.exception.PasswordNotValidException
import hs.kr.entrydsm.user.global.security.jwt.JwtProperties
import hs.kr.entrydsm.user.global.security.jwt.JwtTokenProvider
import hs.kr.entrydsm.user.global.utils.token.dto.TokenResponse
import org.springframework.security.crypto.password.PasswordEncoder
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

/**
* 관리자 로그인 비즈니스 로직을 처리하는 서비스 클래스입니다.
*/
@Service
class AdminLoginService(
private val passwordEncoder: PasswordEncoder,
private val jwtTokenProvider: JwtTokenProvider,
private val userInfoRepository: UserInfoRepository,
private val jwtProperties: JwtProperties,
private val adminQueryAdminPort: QueryAdminPort,
private val adminSaveAdminPort: SaveAdminPort,
) : AdminLoginUseCase {
/**
* 관리자 로그인을 처리하고 JWT 토큰을 반환합니다.
*/
@Transactional
override fun login(adminLoginRequest: AdminLoginRequest): TokenResponse {
val admin = adminQueryAdminPort.findByAdminId(adminLoginRequest.adminId) ?: throw AdminNotFoundException

if (!passwordEncoder.matches(adminLoginRequest.password, admin.password)) {
throw PasswordNotValidException
}
val tokenResponse = jwtTokenProvider.generateToken(admin.id.toString(), UserRole.ADMIN.toString())
val userInfo =
UserInfo(
token = tokenResponse.accessToken,
userId = jwtTokenProvider.getSubjectWithExpiredCheck(tokenResponse.accessToken),
userRole = jwtTokenProvider.getRole(tokenResponse.accessToken),
ttl = jwtProperties.accessExp,
)
userInfoRepository.save(userInfo)
return tokenResponse
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package hs.kr.entrydsm.user.domain.admin.domain

import hs.kr.entrydsm.user.global.entity.BaseUUIDEntity
import java.util.UUID
import jakarta.persistence.Column
import jakarta.persistence.Entity

@Entity(name = "tbl_admin")
class Admin(
id: UUID?,
@Column(name = "admin_id", length = 15, nullable = false)
val adminId: String,
@Column(name = "password", length = 60, nullable = false)
val password: String,
) : BaseUUIDEntity(id)
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package hs.kr.entrydsm.user.domain.admin.domain.repository

import hs.kr.entrydsm.user.domain.admin.domain.Admin
import org.springframework.data.jpa.repository.JpaRepository
import java.util.UUID

interface AdminRepository : JpaRepository<Admin, UUID> {
fun findByAdminId(adminId: String): Admin?
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package hs.kr.entrydsm.user.domain.admin.exception

import hs.kr.entrydsm.user.global.error.exception.EquusException
import hs.kr.entrydsm.user.global.error.exception.ErrorCode

/**
* 관리자를 찾을 수 없을 때 발생하는 예외입니다.
*/
object AdminNotFoundException : EquusException(
ErrorCode.ADMIN_NOT_FOUND,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package hs.kr.entrydsm.user.domain.admin.exception

import hs.kr.entrydsm.user.global.error.exception.EquusException
import hs.kr.entrydsm.user.global.error.exception.ErrorCode

/**
* 관리자 권한이 없을 때 발생하는 예외입니다.
*/
object AdminUnauthorizedException : EquusException(
ErrorCode.ADMIN_UNAUTHORIZED,
)
Loading