diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/audition/AdminAuditionController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/audition/AdminAuditionController.kt
new file mode 100644
index 0000000..ab1e9ef
--- /dev/null
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/audition/AdminAuditionController.kt
@@ -0,0 +1,37 @@
+package kr.co.vividnext.sodalive.admin.audition
+
+import kr.co.vividnext.sodalive.common.ApiResponse
+import org.springframework.data.domain.Pageable
+import org.springframework.security.access.prepost.PreAuthorize
+import org.springframework.web.bind.annotation.GetMapping
+import org.springframework.web.bind.annotation.PostMapping
+import org.springframework.web.bind.annotation.PutMapping
+import org.springframework.web.bind.annotation.RequestMapping
+import org.springframework.web.bind.annotation.RequestPart
+import org.springframework.web.bind.annotation.RestController
+import org.springframework.web.multipart.MultipartFile
+
+@RestController
+@PreAuthorize("hasRole('ADMIN')")
+@RequestMapping("/admin/audition")
+class AdminAuditionController(private val service: AdminAuditionService) {
+    @PostMapping
+    fun createAudition(
+        @RequestPart("image") image: MultipartFile,
+        @RequestPart("request") requestString: String
+    ) = ApiResponse.ok(service.createAudition(image, requestString), "등록되었습니다.")
+
+    @PutMapping
+    fun updateAudition(
+        @RequestPart("image", required = false) image: MultipartFile? = null,
+        @RequestPart("request") requestString: String
+    ) = ApiResponse.ok(service.updateAudition(image, requestString), "수정되었습니다.")
+
+    @GetMapping
+    fun getAuditionList(pageable: Pageable) = ApiResponse.ok(
+        service.getAuditionList(
+            offset = pageable.offset,
+            limit = pageable.pageSize.toLong()
+        )
+    )
+}
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/audition/AdminAuditionRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/audition/AdminAuditionRepository.kt
new file mode 100644
index 0000000..f548802
--- /dev/null
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/audition/AdminAuditionRepository.kt
@@ -0,0 +1,70 @@
+package kr.co.vividnext.sodalive.admin.audition
+
+import com.querydsl.core.types.dsl.DateTimePath
+import com.querydsl.core.types.dsl.Expressions
+import com.querydsl.core.types.dsl.StringTemplate
+import com.querydsl.jpa.impl.JPAQueryFactory
+import kr.co.vividnext.sodalive.audition.Audition
+import kr.co.vividnext.sodalive.audition.QAudition.audition
+import org.springframework.beans.factory.annotation.Value
+import org.springframework.data.jpa.repository.JpaRepository
+import org.springframework.stereotype.Repository
+import java.time.LocalDateTime
+
+@Repository
+interface AdminAuditionRepository : JpaRepository<Audition, Long>, AdminAuditionQueryRepository
+
+interface AdminAuditionQueryRepository {
+    fun getAuditionList(offset: Long, limit: Long): List<GetAuditionListItem>
+    fun getAuditionListCount(): Int
+}
+
+class AdminAuditionQueryRepositoryImpl(
+    private val queryFactory: JPAQueryFactory,
+
+    @Value("\${cloud.aws.cloud-front.host}")
+    private val coverImageHost: String
+) : AdminAuditionQueryRepository {
+    override fun getAuditionList(offset: Long, limit: Long): List<GetAuditionListItem> {
+        return queryFactory
+            .select(
+                QGetAuditionListItem(
+                    audition.id,
+                    audition.title,
+                    getFormattedDate(audition.endDate),
+                    audition.imagePath.prepend("/").prepend(coverImageHost),
+                    audition.isAdult,
+                    audition.isActive,
+                    audition.information,
+                    audition.originalWorkUrl
+                )
+            )
+            .from(audition)
+            .offset(offset)
+            .limit(limit)
+            .orderBy(audition.isActive.desc(), audition.id.desc())
+            .fetch()
+    }
+
+    override fun getAuditionListCount(): Int {
+        return queryFactory
+            .select(audition.id)
+            .from(audition)
+            .fetch()
+            .size
+    }
+
+    private fun getFormattedDate(dateTimePath: DateTimePath<LocalDateTime>): StringTemplate {
+        return Expressions.stringTemplate(
+            "DATE_FORMAT({0}, {1})",
+            Expressions.dateTimeTemplate(
+                LocalDateTime::class.java,
+                "CONVERT_TZ({0},{1},{2})",
+                dateTimePath,
+                "UTC",
+                "Asia/Seoul"
+            ),
+            "%Y-%m-%d %H:%i:%s"
+        )
+    }
+}
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/audition/AdminAuditionService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/audition/AdminAuditionService.kt
new file mode 100644
index 0000000..bfec948
--- /dev/null
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/audition/AdminAuditionService.kt
@@ -0,0 +1,90 @@
+package kr.co.vividnext.sodalive.admin.audition
+
+import com.fasterxml.jackson.databind.ObjectMapper
+import kr.co.vividnext.sodalive.aws.s3.S3Uploader
+import kr.co.vividnext.sodalive.common.SodaException
+import kr.co.vividnext.sodalive.utils.generateFileName
+import org.springframework.beans.factory.annotation.Value
+import org.springframework.data.repository.findByIdOrNull
+import org.springframework.stereotype.Service
+import org.springframework.transaction.annotation.Transactional
+import org.springframework.web.multipart.MultipartFile
+import java.time.LocalDateTime
+import java.time.ZoneId
+import java.time.format.DateTimeFormatter
+
+@Service
+class AdminAuditionService(
+    private val s3Uploader: S3Uploader,
+    private val objectMapper: ObjectMapper,
+    private val repository: AdminAuditionRepository,
+
+    @Value("\${cloud.aws.s3.bucket}")
+    private val bucket: String
+) {
+    @Transactional
+    fun createAudition(image: MultipartFile, requestString: String) {
+        val request = objectMapper.readValue(requestString, CreateAuditionRequest::class.java)
+        val audition = repository.save(request.toAudition())
+
+        val fileName = generateFileName("audition")
+        val imagePath = s3Uploader.upload(
+            inputStream = image.inputStream,
+            bucket = bucket,
+            filePath = "audition/production/${audition.id}/$fileName"
+        )
+        audition.imagePath = imagePath
+    }
+
+    @Transactional
+    fun updateAudition(image: MultipartFile?, requestString: String) {
+        val request = objectMapper.readValue(requestString, UpdateAuditionRequest::class.java)
+        val audition = repository.findByIdOrNull(id = request.id)
+            ?: throw SodaException("잘못된 요청입니다.\n다시 시도해 주세요.")
+
+        if (request.title != null) {
+            audition.title = request.title
+        }
+
+        if (request.information != null) {
+            audition.information = request.information
+        }
+
+        if (request.isAdult != null) {
+            audition.isAdult = request.isAdult
+        }
+
+        if (request.endDateString != null) {
+            val dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
+            val endDate = LocalDateTime.parse(request.endDateString, dateTimeFormatter)
+                .atZone(ZoneId.of("Asia/Seoul"))
+                .withZoneSameInstant(ZoneId.of("UTC"))
+                .toLocalDateTime()
+            audition.endDate = endDate
+        }
+
+        if (request.originalWorkUrl != null) {
+            audition.originalWorkUrl = request.originalWorkUrl
+        }
+
+        if (image != null) {
+            val fileName = generateFileName("audition")
+            val imagePath = s3Uploader.upload(
+                inputStream = image.inputStream,
+                bucket = bucket,
+                filePath = "audition/production/${audition.id}/$fileName"
+            )
+            audition.imagePath = imagePath
+        }
+
+        if (request.isActive != null) {
+            audition.isActive = request.isActive
+        }
+    }
+
+    fun getAuditionList(offset: Long, limit: Long): GetAuditionListResponse {
+        val totalCount = repository.getAuditionListCount()
+        val items = repository.getAuditionList(offset = offset, limit = limit)
+        return GetAuditionListResponse(totalCount, items)
+    }
+}
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/audition/CreateAuditionRequest.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/audition/CreateAuditionRequest.kt
new file mode 100644
index 0000000..647fa34
--- /dev/null
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/audition/CreateAuditionRequest.kt
@@ -0,0 +1,45 @@
+package kr.co.vividnext.sodalive.admin.audition
+
+import kr.co.vividnext.sodalive.audition.Audition
+import kr.co.vividnext.sodalive.common.SodaException
+import java.time.LocalDateTime
+import java.time.ZoneId
+import java.time.format.DateTimeFormatter
+
+data class CreateAuditionRequest(
+    val title: String,
+    val information: String,
+    val isAdult: Boolean = false,
+    val endDateString: String? = null,
+    val originalWorkUrl: String? = null
+) {
+    init {
+        if (title.isBlank()) {
+            throw SodaException("오디션 제목을 입력하세요")
+        }
+
+        if (information.isBlank() || information.length < 10) {
+            throw SodaException("오디션 정보는 최소 10글자 입니다")
+        }
+    }
+
+    fun toAudition(): Audition {
+        val dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
+        val endDate = if (endDateString != null) {
+            LocalDateTime.parse(endDateString, dateTimeFormatter)
+                .atZone(ZoneId.of("Asia/Seoul"))
+                .withZoneSameInstant(ZoneId.of("UTC"))
+                .toLocalDateTime()
+        } else {
+            null
+        }
+
+        return Audition(
+            title = title,
+            information = information,
+            isAdult = isAdult,
+            endDate = endDate,
+            originalWorkUrl = originalWorkUrl
+        )
+    }
+}
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/audition/GetAuditionListResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/audition/GetAuditionListResponse.kt
new file mode 100644
index 0000000..10f2db4
--- /dev/null
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/audition/GetAuditionListResponse.kt
@@ -0,0 +1,19 @@
+package kr.co.vividnext.sodalive.admin.audition
+
+import com.querydsl.core.annotations.QueryProjection
+
+data class GetAuditionListResponse(
+    val totalCount: Int,
+    val items: List<GetAuditionListItem>
+)
+
+data class GetAuditionListItem @QueryProjection constructor(
+    val id: Long,
+    val title: String,
+    val endDate: String,
+    val imageUrl: String,
+    val isAdult: Boolean,
+    val isActive: Boolean,
+    val information: String,
+    val originalWorkUrl: String
+)
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/audition/UpdateAuditionRequest.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/audition/UpdateAuditionRequest.kt
new file mode 100644
index 0000000..5b1f16f
--- /dev/null
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/audition/UpdateAuditionRequest.kt
@@ -0,0 +1,11 @@
+package kr.co.vividnext.sodalive.admin.audition
+
+data class UpdateAuditionRequest(
+    val id: Long,
+    val title: String? = null,
+    val information: String? = null,
+    val isAdult: Boolean? = null,
+    val endDateString: String? = null,
+    val originalWorkUrl: String? = null,
+    val isActive: Boolean? = null
+)
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/audition/Audition.kt b/src/main/kotlin/kr/co/vividnext/sodalive/audition/Audition.kt
new file mode 100644
index 0000000..5970923
--- /dev/null
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/audition/Audition.kt
@@ -0,0 +1,18 @@
+package kr.co.vividnext.sodalive.audition
+
+import kr.co.vividnext.sodalive.common.BaseEntity
+import java.time.LocalDateTime
+import javax.persistence.Entity
+
+@Entity
+data class Audition(
+    var title: String,
+    var information: String,
+    var isAdult: Boolean = false,
+    var endDate: LocalDateTime? = null,
+    // 원작 URL
+    var originalWorkUrl: String? = null
+) : BaseEntity() {
+    var isActive: Boolean = true
+    var imagePath: String? = null
+}
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/audition/AuditionApplicant.kt b/src/main/kotlin/kr/co/vividnext/sodalive/audition/AuditionApplicant.kt
new file mode 100644
index 0000000..e485407
--- /dev/null
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/audition/AuditionApplicant.kt
@@ -0,0 +1,23 @@
+package kr.co.vividnext.sodalive.audition
+
+import kr.co.vividnext.sodalive.common.BaseEntity
+import kr.co.vividnext.sodalive.member.Member
+import javax.persistence.Entity
+import javax.persistence.FetchType
+import javax.persistence.JoinColumn
+import javax.persistence.ManyToOne
+
+@Entity
+data class AuditionApplicant(
+    val voicePath: String,
+    val phoneNumber: String,
+    val isActive: Boolean = true
+) : BaseEntity() {
+    @ManyToOne(fetch = FetchType.LAZY)
+    @JoinColumn(name = "role_id", nullable = false)
+    var role: AuditionRole? = null
+
+    @ManyToOne(fetch = FetchType.LAZY)
+    @JoinColumn(name = "member_id", nullable = false)
+    var member: Member? = null
+}
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/audition/AuditionRole.kt b/src/main/kotlin/kr/co/vividnext/sodalive/audition/AuditionRole.kt
new file mode 100644
index 0000000..4f7250e
--- /dev/null
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/audition/AuditionRole.kt
@@ -0,0 +1,20 @@
+package kr.co.vividnext.sodalive.audition
+
+import kr.co.vividnext.sodalive.common.BaseEntity
+import javax.persistence.Entity
+import javax.persistence.FetchType
+import javax.persistence.JoinColumn
+import javax.persistence.ManyToOne
+
+@Entity
+data class AuditionRole(
+    val name: String,
+    val imagePath: String,
+    // 오디션 대본 URL
+    val auditionScriptUrl: String,
+    val isActive: Boolean
+) : BaseEntity() {
+    @ManyToOne(fetch = FetchType.LAZY)
+    @JoinColumn(name = "audition_id", nullable = false)
+    var audition: Audition? = null
+}
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/audition/AuditionVote.kt b/src/main/kotlin/kr/co/vividnext/sodalive/audition/AuditionVote.kt
new file mode 100644
index 0000000..8e37808
--- /dev/null
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/audition/AuditionVote.kt
@@ -0,0 +1,18 @@
+package kr.co.vividnext.sodalive.audition
+
+import kr.co.vividnext.sodalive.common.BaseEntity
+import kr.co.vividnext.sodalive.member.Member
+import javax.persistence.Entity
+import javax.persistence.JoinColumn
+import javax.persistence.ManyToOne
+
+@Entity
+class AuditionVote : BaseEntity() {
+    @ManyToOne
+    @JoinColumn(name = "member_id", nullable = false)
+    var member: Member? = null
+
+    @ManyToOne
+    @JoinColumn(name = "applicant_id", nullable = false)
+    var applicant: AuditionApplicant? = null
+}