diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index 524f096..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,24 +0,0 @@
-# Compiled class file
-*.class
-
-# Log file
-*.log
-
-# BlueJ files
-*.ctxt
-
-# Mobile Tools for Java (J2ME)
-.mtj.tmp/
-
-# Package Files #
-*.jar
-*.war
-*.nar
-*.ear
-*.zip
-*.tar.gz
-*.rar
-
-# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
-hs_err_pid*
-replay_pid*
diff --git a/luke/.DS_Store b/luke/.DS_Store
new file mode 100644
index 0000000..7602093
Binary files /dev/null and b/luke/.DS_Store differ
diff --git a/luke/.idea/.gitignore b/luke/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/luke/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/luke/.idea/compiler.xml b/luke/.idea/compiler.xml
new file mode 100644
index 0000000..edc03cf
--- /dev/null
+++ b/luke/.idea/compiler.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/luke/.idea/gradle.xml b/luke/.idea/gradle.xml
new file mode 100644
index 0000000..8eb6c54
--- /dev/null
+++ b/luke/.idea/gradle.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/luke/.idea/jarRepositories.xml b/luke/.idea/jarRepositories.xml
new file mode 100644
index 0000000..fdc392f
--- /dev/null
+++ b/luke/.idea/jarRepositories.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/luke/.idea/luke.iml b/luke/.idea/luke.iml
new file mode 100644
index 0000000..d6ebd48
--- /dev/null
+++ b/luke/.idea/luke.iml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/luke/.idea/misc.xml b/luke/.idea/misc.xml
new file mode 100644
index 0000000..e0c6f33
--- /dev/null
+++ b/luke/.idea/misc.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/luke/.idea/modules.xml b/luke/.idea/modules.xml
new file mode 100644
index 0000000..3573f5b
--- /dev/null
+++ b/luke/.idea/modules.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/luke/.idea/modules/umc10th.main.iml b/luke/.idea/modules/umc10th.main.iml
new file mode 100644
index 0000000..a83d591
--- /dev/null
+++ b/luke/.idea/modules/umc10th.main.iml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/luke/.idea/vcs.xml b/luke/.idea/vcs.xml
new file mode 100644
index 0000000..6c0b863
--- /dev/null
+++ b/luke/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/luke/umc10th/.DS_Store b/luke/umc10th/.DS_Store
new file mode 100644
index 0000000..793f73d
Binary files /dev/null and b/luke/umc10th/.DS_Store differ
diff --git a/luke/umc10th/.gitattributes b/luke/umc10th/.gitattributes
new file mode 100644
index 0000000..8af972c
--- /dev/null
+++ b/luke/umc10th/.gitattributes
@@ -0,0 +1,3 @@
+/gradlew text eol=lf
+*.bat text eol=crlf
+*.jar binary
diff --git a/luke/umc10th/.github/ISSUE_TEMPLATE/mission_template.md b/luke/umc10th/.github/ISSUE_TEMPLATE/mission_template.md
new file mode 100644
index 0000000..9c5b6ef
--- /dev/null
+++ b/luke/umc10th/.github/ISSUE_TEMPLATE/mission_template.md
@@ -0,0 +1,18 @@
+---
+name: "๐ฉ ๋ฏธ์
"
+about: "๋ฏธ์
๋จ์๋ก ๊ด๋ฆฌํ๋ ์ด์ ํ
ํ๋ฆฟ"
+title: "[Mission]"
+labels: []
+assignees: []
+---
+
+## ๐ฉ ๋ฏธ์
์ค๋ช
+
+
+## โ
์ฒดํฌ๋ฆฌ์คํธ
+- [ ]
+- [ ]
+- [ ]
+
+## ๐ฌ ์ฐธ๊ณ ์๋ฃ
+
diff --git a/luke/umc10th/.github/PULL_REQUEST_TEMPLATE.md b/luke/umc10th/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 0000000..4915b04
--- /dev/null
+++ b/luke/umc10th/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,15 @@
+## ๐ฉ ๊ด๋ จ ์ด์
+
+- close #์ด์๋ฒํธ
+
+## ๐ ๊ตฌํ ๊ฒฐ๊ณผ
+
+
+## โ ๋ฆฌ๋ทฐ ์์ฒญ
+
+
+## ๐ค ์ง๋ฌธ
+
+
+## ๐ฌ ๊ธฐํ ๊ณต์ ์ฌํญ
+
diff --git a/luke/umc10th/.gitignore b/luke/umc10th/.gitignore
new file mode 100644
index 0000000..82f6973
--- /dev/null
+++ b/luke/umc10th/.gitignore
@@ -0,0 +1,49 @@
+HELP.md
+.gradle
+umc10th/build/
+!luke/gradle/wrapper/gradle-wrapper.jar
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### ๋ฏผ๊ฐํ ์ ๋ณด ###
+.env
+application.yml
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+bin/
+!**/src/main/**/bin/
+!**/src/test/**/bin/
+
+### IntelliJ IDEA ###
+umc10th/.idea
+*.iws
+*.iml
+.idea/
+*.ipr
+umc10th/out/
+!**/src/main/**/out/
+!**/src/test/**/out/
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+
+### VS Code ###
+.vscode/
+
+### macOS ###
+.DS_Store
+
+### Gradle ###
+build/
+.gradle/
\ No newline at end of file
diff --git a/luke/umc10th/README.md b/luke/umc10th/README.md
new file mode 100644
index 0000000..33c0edc
--- /dev/null
+++ b/luke/umc10th/README.md
@@ -0,0 +1,74 @@
+# 10th_SpringBoot_B
+
+### Git ์์
์์
+
+๋ณธ์ธ์ ๋ธ๋์น์์๋ง ์์
ํ๊ณ , `main` ๋ธ๋์น๋ ์ง์ ์์ ํ์ง ์์ต๋๋ค.
+
+#### 1. ํ์ฌ ๋ธ๋์น ํ์ธ
+```sh
+git branch
+```
+
+#### 2. ๋ณ๊ฒฝ ์ฌํญ ํ์ธ
+```sh
+git status
+```
+
+#### 3. ๋ณ๊ฒฝ๋ ํ์ผ ์ถ๊ฐ
+```sh
+git add .
+```
+
+#### 4. ์ปค๋ฐ ๋ฉ์์ง ์์ฑ
+```sh
+git commit-m "Commit Message"
+```
+
+#### 5. ์๊ฒฉ ์ ์ฅ์์ ๋ณธ์ธ ๋ธ๋์น๋ก ํธ์
+```sh
+git push origin <๋ธ๋์น๋ช
>
+```
+
+### Commit Convention
+
+์ปค๋ฐ ๋ฉ์์ง๋ `ํ์
: n์ฃผ์ฐจ ๋ฏธ์
์ค๋ช
#์ด์๋๋ฒ`์ ํ์์ ๊ฐ์ถ์ด ์์ฑํฉ๋๋ค.
+
+| ํ์
| ์ค๋ช
|
+|-----------|--------------------------------|
+| feat | ์๋ก์ด ๊ธฐ๋ฅ ์ถ๊ฐ |
+| fix | ๋ฒ๊ทธ ์์ |
+| refactor | ์ฝ๋ ๋ฆฌํฉํ ๋ง |
+| docs | ๋ฌธ์ ์์ (README ๋ฑ) |
+| style | ์ฝ๋ ์คํ์ผ ๋ณ๊ฒฝ (์ธ๋ฏธ์ฝ๋ก ์ถ๊ฐ ๋ฑ)|
+| chore | ๋น๋ ๋ฐ ํจํค์ง ์ค์ ๋ณ๊ฒฝ |
+| test | ํ
์คํธ ์ฝ๋ ์ถ๊ฐ |
+
+#### Commit Example
+```sh
+git commit -m "feat: 4์ฃผ์ฐจ ๋ฏธ์
์ํฐํฐ ์์ฑ #1"
+git commit -m "fix: 5์ฃผ์ฐจ ๋ฏธ์
์ฐ๊ด๊ด๊ณ ์์ #2"
+```
+
+### Branch Naming Convention
+
+๋ธ๋์น๋ `๋๋ค์/weekN` ํ์์ผ๋ก ์์ฑํฉ๋๋ค.
+
+| ๊ท์น | ์ค๋ช
| ์์ |
+| --- | --- | --- |
+| ๋๋ค์ | GitHub ๋๋ค์ ๋๋ ํ ๋ด ๋ณ์นญ ์ฌ์ฉ | `naru`, `leeseo` |
+| weekN | ๋ฏธ์
์ฃผ์ฐจ ๋ฒํธ (`N`์ ์ซ์) | `week1`, `week4` |
+| ๊ตฌ๋ถ์ | ์ฌ๋์(`/`)๋ก ๋๋ค์๊ณผ ์ฃผ์ฐจ ๊ตฌ๋ถ | `naru/week4` |
+
+#### Commit Example
+- `naru/week4` -> ๋๋ฃจ์ 4์ฃผ์ฐจ ๋ฏธ์
๋ธ๋์น
+- `leeseo/week5` -> ์ด์์ 5์ฃผ์ฐจ ๋ฏธ์
๋ธ๋์น
+
+### PR Convention
+
+- Pull Request(PR)์ ๋ฏธ์
๋ณ๋ก ์์ฑํฉ๋๋ค.
+- PR ์ ๋ชฉ์ `n์ฃผ์ฐจ ๋ฏธ์
[๋๋ค์]` ํ์์ผ๋ก ์์ฑํฉ๋๋ค.
+- ์คํฐ๋์๋ผ๋ฆฌ ์น์ธํ ํ, main ๋ธ๋์น๋ก Merge ํฉ๋๋ค.
+
+#### PR Example
+- 1์ฃผ์ฐจ ๋ฏธ์
[๋๋ฃจ]
+- 2์ฃผ์ฐจ ๋ฏธ์
[์ด์]
diff --git a/luke/umc10th/build.gradle b/luke/umc10th/build.gradle
new file mode 100644
index 0000000..94adc84
--- /dev/null
+++ b/luke/umc10th/build.gradle
@@ -0,0 +1,43 @@
+plugins {
+ id 'java'
+ id 'org.springframework.boot' version '4.0.5'
+ id 'io.spring.dependency-management' version '1.1.7'
+}
+
+group = 'com.example'
+version = '0.0.1-SNAPSHOT'
+description = 'umc10th'
+
+java {
+ toolchain {
+ languageVersion = JavaLanguageVersion.of(21)
+ }
+}
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
+ implementation 'org.springframework.boot:spring-boot-starter-webmvc'
+ compileOnly 'org.projectlombok:lombok'
+ runtimeOnly 'com.mysql:mysql-connector-j'
+ annotationProcessor 'org.projectlombok:lombok'
+ testImplementation 'org.springframework.boot:spring-boot-starter-data-jpa-test'
+ testImplementation 'org.springframework.boot:spring-boot-starter-webmvc-test'
+ testCompileOnly 'org.projectlombok:lombok'
+ testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
+ testAnnotationProcessor 'org.projectlombok:lombok'
+
+ // Swagger
+ implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:3.0.1'
+ implementation 'org.springdoc:springdoc-openapi-starter-webmvc-api:3.0.1'
+
+ // Validation
+ implementation 'org.springframework.boot:spring-boot-starter-validation'
+}
+
+tasks.named('test') {
+ useJUnitPlatform()
+}
diff --git a/luke/umc10th/gradle/wrapper/gradle-wrapper.jar b/luke/umc10th/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..d997cfc
Binary files /dev/null and b/luke/umc10th/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/luke/umc10th/gradle/wrapper/gradle-wrapper.properties b/luke/umc10th/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..c61a118
--- /dev/null
+++ b/luke/umc10th/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,7 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/luke/umc10th/gradlew b/luke/umc10th/gradlew
new file mode 100755
index 0000000..739907d
--- /dev/null
+++ b/luke/umc10th/gradlew
@@ -0,0 +1,248 @@
+#!/bin/sh
+
+#
+# Copyright ยฉ 2015 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions ยซ$varยป, ยซ${var}ยป, ยซ${var:-default}ยป, ยซ${var+SET}ยป,
+# ยซ${var#prefix}ยป, ยซ${var%suffix}ยป, and ยซ$( cmd )ยป;
+# * compound commands having a testable exit status, especially ยซcaseยป;
+# * various built-in commands including ยซcommandยป, ยซsetยป, and ยซulimitยป.
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/2d6327017519d23b96af35865dc997fcb544fb40/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+ echo "$*"
+} >&2
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
+esac
+
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD=$JAVA_HOME/jre/sh/java
+ else
+ JAVACMD=$JAVA_HOME/bin/java
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD=java
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
+fi
+
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# and any embedded shellness will be escaped.
+# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+# treated as '${Hostname}' itself on the command line.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/luke/umc10th/gradlew.bat b/luke/umc10th/gradlew.bat
new file mode 100644
index 0000000..c4bdd3a
--- /dev/null
+++ b/luke/umc10th/gradlew.bat
@@ -0,0 +1,93 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
+
+@if "%DEBUG%"=="" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if %ERRORLEVEL% equ 0 goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/luke/umc10th/settings.gradle b/luke/umc10th/settings.gradle
new file mode 100644
index 0000000..67a1b8e
--- /dev/null
+++ b/luke/umc10th/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = 'umc10th'
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/Umc10thApplication.java b/luke/umc10th/src/main/java/com/example/umc10th/Umc10thApplication.java
new file mode 100644
index 0000000..9202ae8
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/Umc10thApplication.java
@@ -0,0 +1,15 @@
+package com.example.umc10th;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
+
+@SpringBootApplication
+@EnableJpaAuditing
+public class Umc10thApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Umc10thApplication.class, args);
+ }
+
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/member/controller/MemberController.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/member/controller/MemberController.java
new file mode 100644
index 0000000..1b2e23f
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/member/controller/MemberController.java
@@ -0,0 +1,40 @@
+package com.example.umc10th.domain.member.controller;
+
+import com.example.umc10th.domain.member.dto.MemberReqDTO;
+import com.example.umc10th.domain.member.dto.MemberResDTO;
+import com.example.umc10th.domain.member.service.MemberService;
+import com.example.umc10th.global.apiPayload.ApiResponse;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+
+
+@RestController
+@RequestMapping("/members")
+@RequiredArgsConstructor
+public class MemberController {
+
+ private final MemberService memberService;
+
+ @PostMapping("/signup")
+ public ApiResponse signup(
+ @RequestBody MemberReqDTO.SignupDTO request
+ ) {
+
+ MemberResDTO.SignupDTO response = new MemberResDTO.SignupDTO();
+ response.userId = 1L;
+ response.message = "ํ์๊ฐ์
์ด ์๋ฃ๋์์ต๋๋ค.";
+
+ return ApiResponse.onSuccess(response);
+ }
+
+ @GetMapping("/home/my")
+ public ApiResponse getMyPage(
+ @RequestParam Long memberId
+ ) {
+
+ MemberResDTO.MyPageDTO response =
+ memberService.getMyPage(memberId);
+
+ return ApiResponse.onSuccess(response);
+ }
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/member/converter/MemberConverter.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/member/converter/MemberConverter.java
new file mode 100644
index 0000000..6c03f5d
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/member/converter/MemberConverter.java
@@ -0,0 +1,19 @@
+package com.example.umc10th.domain.member.converter;
+
+import com.example.umc10th.domain.member.dto.MemberResDTO;
+import com.example.umc10th.domain.member.entity.Member;
+
+public class MemberConverter {
+
+ public static MemberResDTO.MyPageDTO toMyPageDTO(Member member) {
+
+ return MemberResDTO.MyPageDTO.builder()
+ .nickname(member.getName())
+ .email(member.getEmail())
+ .phoneNumber(member.getPhoneNumber())
+ .phoneNumberStatus(member.getPhoneNumberStatus())
+ .userPoint(member.getUserPoint())
+ .build();
+ }
+
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/member/dto/MemberReqDTO.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/member/dto/MemberReqDTO.java
new file mode 100644
index 0000000..a279cb4
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/member/dto/MemberReqDTO.java
@@ -0,0 +1,61 @@
+package com.example.umc10th.domain.member.dto;
+
+import com.example.umc10th.domain.member.enums.Gender;
+import com.example.umc10th.domain.member.enums.UserType;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.*;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDate;
+
+public class MemberReqDTO {
+
+ public static class SignupDTO {
+ @Schema(description = "์ด๋ฆ", example = "ํ๊ธธ๋")
+ @NotBlank
+ public String name;
+
+ @Schema(description = "์ฑ๋ณ", example = "MALE")
+ @NotNull
+ public Gender gender;
+
+ @Schema(description = "์๋
์์ผ", example = "2003-01-01")
+ @NotNull
+ public LocalDate birth;
+
+ @Schema(description = "๊ธฐ๋ณธ ์ฃผ์")
+ @NotBlank
+ public String addressLine1;
+
+ @Schema(description = "์์ธ ์ฃผ์")
+ public String addressLine2;
+
+ @Schema(description = "์ด๋ฉ์ผ", example = "test@example.com")
+ @Email
+ @NotBlank
+ public String email;
+
+ @Schema(description = "์ ํ๋ฒํธ", example = "01012345678")
+ @NotBlank
+ public String phoneNumber;
+
+ @Schema(description = "์ ์ ํ์
")
+ @NotNull
+ public UserType type;
+
+ }
+
+ @Getter
+ @Builder
+ @AllArgsConstructor
+ @NoArgsConstructor
+ public static class MyPageDTO {
+
+ private String name;
+ private String email;
+ private Integer point;
+ }
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/member/dto/MemberResDTO.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/member/dto/MemberResDTO.java
new file mode 100644
index 0000000..b0b2edb
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/member/dto/MemberResDTO.java
@@ -0,0 +1,21 @@
+package com.example.umc10th.domain.member.dto;
+
+import lombok.Builder;
+
+public class MemberResDTO {
+
+ public static class SignupDTO {
+ public Long userId;
+ public String message;
+ }
+
+ @Builder
+ public static class MyPageDTO {
+ public String nickname;
+ public String email;
+ public String phoneNumber;
+ public Boolean phoneNumberStatus;
+ public Integer userPoint;
+ }
+
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/member/entity/FoodCategory.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/member/entity/FoodCategory.java
new file mode 100644
index 0000000..a1aceef
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/member/entity/FoodCategory.java
@@ -0,0 +1,25 @@
+package com.example.umc10th.domain.member.entity;
+
+import com.example.umc10th.domain.member.entity.mapping.Preference;
+import com.example.umc10th.global.entity.BaseEntity;
+import jakarta.persistence.*;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Entity
+@Getter
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+public class FoodCategory extends BaseEntity {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ @OneToMany(mappedBy = "foodCategory")
+ private List preferenceList = new ArrayList<>();
+
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/member/entity/Member.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/member/entity/Member.java
new file mode 100644
index 0000000..4eb233e
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/member/entity/Member.java
@@ -0,0 +1,69 @@
+package com.example.umc10th.domain.member.entity;
+
+import com.example.umc10th.domain.member.entity.mapping.Preference;
+import com.example.umc10th.domain.member.entity.mapping.UserTermAgreement;
+import com.example.umc10th.domain.member.enums.Gender;
+import com.example.umc10th.domain.member.enums.UserType;
+import com.example.umc10th.domain.mission.entity.mapping.Participate;
+import com.example.umc10th.domain.review.entity.Review;
+import com.example.umc10th.global.entity.BaseEntity;
+import jakarta.persistence.Entity;
+import jakarta.persistence.*;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.List;
+
+@Entity
+@Table(name = "user")
+@Getter
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+public class Member extends BaseEntity {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ @Enumerated(EnumType.STRING)
+ private UserType userType;
+
+ private String name;
+
+ @Enumerated(EnumType.STRING)
+ private Gender gender;
+
+ private LocalDate birth;
+
+ @Column(name = "address_line_1")
+ private String addressLine1;
+
+ @Column(name = "address_line_2")
+ private String addressLine2;
+
+ private String email;
+
+ @Column(name = "phone_number")
+ private String phoneNumber;
+
+ @Column(name = "phone_number_status")
+ private Boolean phoneNumberStatus;
+
+ @Column(name = "user_point")
+ private Integer userPoint;
+
+ @OneToMany(mappedBy = "member")
+ private List reviewList = new ArrayList<>();
+
+ @OneToMany(mappedBy = "member")
+ private List participateList = new ArrayList<>();
+
+ @OneToMany(mappedBy = "member")
+ private List preferenceList = new ArrayList<>();
+
+ @OneToMany(mappedBy = "member")
+ private List userTermAgreementList = new ArrayList<>();
+
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/member/entity/Notification.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/member/entity/Notification.java
new file mode 100644
index 0000000..d7b065e
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/member/entity/Notification.java
@@ -0,0 +1,31 @@
+package com.example.umc10th.domain.member.entity;
+
+import com.example.umc10th.domain.member.enums.Gender;
+import com.example.umc10th.domain.member.enums.NotifictationType;
+import com.example.umc10th.global.entity.BaseEntity;
+import jakarta.persistence.Entity;
+import jakarta.persistence.*;
+
+@Entity
+public class Notification extends BaseEntity {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ private String title;
+
+ private String detail;
+
+ @Column(name = "notification_type")
+ @Enumerated(EnumType.STRING)
+ private NotifictationType notifictationType;
+
+ @Column(name = "is_read")
+ private Boolean isRead;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "member_id")
+ private Member member;
+
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/member/entity/Term.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/member/entity/Term.java
new file mode 100644
index 0000000..57a0ecc
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/member/entity/Term.java
@@ -0,0 +1,37 @@
+package com.example.umc10th.domain.member.entity;
+
+import com.example.umc10th.domain.member.entity.mapping.UserTermAgreement;
+import com.example.umc10th.global.entity.BaseEntity;
+import jakarta.persistence.Entity;
+import jakarta.persistence.*;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Entity
+@Getter
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+public class Term extends BaseEntity {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ private String title;
+
+ private String content;
+
+ @Column(name = "is_required")
+ private Boolean isRequired;
+
+ private String version;
+
+ @Column(name = "is_active")
+ private Boolean isActive;
+
+ @OneToMany(mappedBy = "term")
+ private List userTermAgreementList = new ArrayList<>();
+
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/member/entity/mapping/Preference.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/member/entity/mapping/Preference.java
new file mode 100644
index 0000000..aa8fe03
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/member/entity/mapping/Preference.java
@@ -0,0 +1,29 @@
+package com.example.umc10th.domain.member.entity.mapping;
+
+import com.example.umc10th.domain.member.entity.FoodCategory;
+import com.example.umc10th.domain.member.entity.Member;
+import com.example.umc10th.domain.mission.entity.Market;
+import com.example.umc10th.global.entity.BaseEntity;
+import jakarta.persistence.*;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@Entity
+@Getter
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+public class Preference extends BaseEntity {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "foodCategory_id")
+ private FoodCategory foodCategory;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "member_id")
+ private Member member;
+
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/member/entity/mapping/UserTermAgreement.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/member/entity/mapping/UserTermAgreement.java
new file mode 100644
index 0000000..0a3d78a
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/member/entity/mapping/UserTermAgreement.java
@@ -0,0 +1,31 @@
+package com.example.umc10th.domain.member.entity.mapping;
+
+import com.example.umc10th.domain.member.entity.Member;
+import com.example.umc10th.domain.member.entity.Term;
+import com.example.umc10th.global.entity.BaseEntity;
+import jakarta.persistence.*;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@Entity
+@Getter
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+public class UserTermAgreement extends BaseEntity {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ @Column(name = "is_agreed")
+ private Boolean isAgreed;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "member_id")
+ private Member member;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "term_id")
+ private Term term;
+
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/member/enums/Gender.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/member/enums/Gender.java
new file mode 100644
index 0000000..072ea2b
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/member/enums/Gender.java
@@ -0,0 +1,5 @@
+package com.example.umc10th.domain.member.enums;
+
+public enum Gender {
+ MALE, FEMALE
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/member/enums/NotifictationType.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/member/enums/NotifictationType.java
new file mode 100644
index 0000000..802d42b
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/member/enums/NotifictationType.java
@@ -0,0 +1,10 @@
+package com.example.umc10th.domain.member.enums;
+
+public enum NotifictationType {
+
+ COMMENT,
+ MISSION,
+ REVIEW,
+ EVENT
+
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/member/enums/UserType.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/member/enums/UserType.java
new file mode 100644
index 0000000..0d1a9c6
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/member/enums/UserType.java
@@ -0,0 +1,11 @@
+package com.example.umc10th.domain.member.enums;
+
+public enum UserType {
+
+ DEFAULT,
+ KAKAO,
+ NAVER,
+ APPLE,
+ GOOGLE
+
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/member/exception/MemberException.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/member/exception/MemberException.java
new file mode 100644
index 0000000..f9ad7d4
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/member/exception/MemberException.java
@@ -0,0 +1,15 @@
+package com.example.umc10th.domain.member.exception;
+
+import com.example.umc10th.domain.review.exception.code.ReviewErrorCode;
+import lombok.Getter;
+
+@Getter
+public class MemberException extends RuntimeException {
+
+ private final ReviewErrorCode errorCode;
+
+ public MemberException(ReviewErrorCode errorCode) {
+ this.errorCode = errorCode;
+ }
+
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/member/exception/code/MemberErrorCode.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/member/exception/code/MemberErrorCode.java
new file mode 100644
index 0000000..088c4ca
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/member/exception/code/MemberErrorCode.java
@@ -0,0 +1,17 @@
+package com.example.umc10th.domain.member.exception.code;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.springframework.http.HttpStatus;
+
+@Getter
+@AllArgsConstructor
+public enum MemberErrorCode {
+
+ MEMBER_NOT_FOUND(HttpStatus.NOT_FOUND, "MEMBER4001", "๋ฉค๋ฒ๊ฐ ์กด์ฌํ์ง ์์ต๋๋ค.");
+
+ private final HttpStatus status;
+ private final String code;
+ private final String message;
+
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/member/exception/code/MemberSuccessCode.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/member/exception/code/MemberSuccessCode.java
new file mode 100644
index 0000000..f42e80f
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/member/exception/code/MemberSuccessCode.java
@@ -0,0 +1,4 @@
+package com.example.umc10th.domain.member.exception.code;
+
+public enum MemberSuccessCode {
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/member/repository/MemberRepository.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/member/repository/MemberRepository.java
new file mode 100644
index 0000000..e878bbb
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/member/repository/MemberRepository.java
@@ -0,0 +1,7 @@
+package com.example.umc10th.domain.member.repository;
+
+import com.example.umc10th.domain.member.entity.Member;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface MemberRepository extends JpaRepository {
+}
\ No newline at end of file
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/member/service/MemberService.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/member/service/MemberService.java
new file mode 100644
index 0000000..287356d
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/member/service/MemberService.java
@@ -0,0 +1,29 @@
+package com.example.umc10th.domain.member.service;
+
+import com.example.umc10th.domain.member.converter.MemberConverter;
+import com.example.umc10th.domain.member.dto.MemberResDTO;
+import com.example.umc10th.domain.member.entity.Member;
+import com.example.umc10th.domain.member.repository.MemberRepository;
+import com.example.umc10th.domain.review.exception.ReviewException;
+import com.example.umc10th.domain.review.exception.code.ReviewErrorCode;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@RequiredArgsConstructor
+@Transactional(readOnly = true)
+public class MemberService {
+
+ private final MemberRepository memberRepository;
+
+ public MemberResDTO.MyPageDTO getMyPage(Long memberId) {
+
+ Member member = memberRepository.findById(memberId)
+ .orElseThrow(() ->
+ new ReviewException(ReviewErrorCode.MEMBER_NOT_FOUND));
+
+ return MemberConverter.toMyPageDTO(member);
+
+ }
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/controller/MissionController.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/controller/MissionController.java
new file mode 100644
index 0000000..6895489
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/controller/MissionController.java
@@ -0,0 +1,118 @@
+package com.example.umc10th.domain.mission.controller;
+
+import com.example.umc10th.domain.mission.dto.MissionReqDTO;
+import com.example.umc10th.domain.mission.dto.MissionResDTO;
+import com.example.umc10th.domain.mission.dto.ParticipateReqDTO;
+import com.example.umc10th.domain.mission.dto.ParticipateResDTO;
+import com.example.umc10th.domain.mission.enums.ParticipatedStatus;
+import com.example.umc10th.domain.mission.exception.code.MissionSuccessCode;
+import com.example.umc10th.domain.mission.service.MissionService;
+import com.example.umc10th.global.apiPayload.ApiResponse;
+import com.example.umc10th.global.apiPayload.code.BaseSuccessCode;
+import com.example.umc10th.global.apiPayload.dto.PageResponseDTO;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.Min;
+import lombok.RequiredArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequestMapping("/mission")
+@RequiredArgsConstructor
+@Validated
+public class MissionController {
+
+ private final MissionService missionService;
+
+ @PostMapping("/store/{marketId}/missions")
+ public ApiResponse createMission(
+ @PathVariable Long marketId,
+ @RequestBody @Valid MissionReqDTO.CreateMission dto
+ ){
+ missionService.createMission(marketId, dto);
+
+ return ApiResponse.onSuccess(null);
+ }
+
+
+ @GetMapping
+ public ApiResponse> getMissionList(
+ @RequestParam(name = "memberId", required = false)
+ Long memberId,
+
+ @RequestParam(name = "status")
+ ParticipatedStatus status,
+
+ @Min(value = 0, message = "page๋ 0 ์ด์์ด์ด์ผ ํฉ๋๋ค.")
+ @RequestParam(name = "page")
+ Integer page,
+
+ @Min(value = 1, message = "size๋ 1 ์ด์์ด์ด์ผ ํฉ๋๋ค.")
+ @RequestParam(name = "size")
+ Integer size
+ ) {
+
+ return ApiResponse.onSuccess(
+ missionService.getMissionList(
+ memberId,
+ status,
+ page,
+ size
+ )
+ );
+ }
+
+ @PostMapping("/completed")
+ public ApiResponse completeMission(
+ @RequestBody MissionReqDTO.CompleteDTO request
+ ) {
+
+ MissionResDTO.CompleteDTO response = new MissionResDTO.CompleteDTO();
+ response.missionId = request.missionId;
+ response.message = "๋ฏธ์
์ด ์ ์์ ์ผ๋ก ์๋ฃ๋์์ต๋๋ค.";
+
+ return ApiResponse.onSuccess(response);
+ }
+
+ @GetMapping("/home")
+ public ApiResponse> getHomeMissionList(
+ @RequestParam String regionName,
+ @RequestParam Integer page,
+ @RequestParam Integer size
+ ) {
+
+ return ApiResponse.onSuccess(
+ missionService.getHomeMissionList(
+ regionName,
+ page,
+ size
+ )
+ );
+ }
+
+ @PostMapping("/my")
+ public ApiResponse>
+ getMyMissions(
+
+ @RequestBody ParticipateReqDTO.MyMissionRequest request,
+
+ @RequestParam(defaultValue = "0")
+ @Min(value = 0, message = "page๋ 0 ์ด์์ด์ด์ผ ํฉ๋๋ค.")
+ Integer page,
+
+ @RequestParam(defaultValue ="5")
+ @Min(value = 1, message = "size๋ 1 ์ด์์ด์ด์ผ ํฉ๋๋ค.")
+ Integer size
+ ){
+
+ return ApiResponse.onSuccess(
+ missionService.getMyMissions(
+ request.memberId(),
+ page,
+ size
+ )
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/converter/MissionConverter.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/converter/MissionConverter.java
new file mode 100644
index 0000000..1cae5dc
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/converter/MissionConverter.java
@@ -0,0 +1,53 @@
+package com.example.umc10th.domain.mission.converter;
+
+import com.example.umc10th.domain.mission.dto.MissionReqDTO;
+import com.example.umc10th.domain.mission.dto.MissionResDTO;
+import com.example.umc10th.domain.mission.entity.Market;
+import com.example.umc10th.domain.mission.entity.Mission;
+import com.example.umc10th.domain.mission.entity.mapping.Participate;
+import com.example.umc10th.domain.mission.enums.MissionStatus;
+
+public class MissionConverter {
+
+ public static Mission toMission(
+ Market market,
+ MissionReqDTO.CreateMission dto
+ ){
+ return Mission.builder()
+ .market(market)
+ .content(dto.content())
+ .point(dto.point())
+ .endDate(dto.deadline().atStartOfDay())
+ .missionStatus(MissionStatus.IN_PROGRESS)
+ .build();
+ }
+
+ public static MissionResDTO.MissionDTO toMissionDTO(
+ Participate participate
+ ) {
+
+ Mission mission = participate.getMission();
+
+ return MissionResDTO.MissionDTO.builder()
+ .missionId(mission.getId())
+ .marketName(mission.getMarket().getName())
+ .content(mission.getContent())
+ .point(mission.getPoint())
+ .status(participate.getStatus().name())
+ .build();
+ }
+
+ public static MissionResDTO.MissionDTO toHomeMissionDTO(
+ Mission mission
+ ) {
+
+ return MissionResDTO.MissionDTO.builder()
+ .missionId(mission.getId())
+ .marketName(mission.getMarket().getName())
+ .content(mission.getContent())
+ .point(mission.getPoint())
+ .status(mission.getMissionStatus().name())
+ .build();
+ }
+
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/converter/ParticipateConverter.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/converter/ParticipateConverter.java
new file mode 100644
index 0000000..7b131ac
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/converter/ParticipateConverter.java
@@ -0,0 +1,23 @@
+package com.example.umc10th.domain.mission.converter;
+
+import com.example.umc10th.domain.mission.dto.ParticipateResDTO;
+import com.example.umc10th.domain.mission.entity.Mission;
+import com.example.umc10th.domain.mission.entity.mapping.Participate;
+
+public class ParticipateConverter {
+
+ public static ParticipateResDTO.MyMissionPreviewDTO
+ toMyMissionPreviewDTO(
+ Participate participate
+ ){
+
+ Mission mission = participate.getMission();
+
+ return ParticipateResDTO.MyMissionPreviewDTO.builder()
+ .missionId(mission.getId())
+ .content(mission.getContent())
+ .point(mission.getPoint())
+ .endDate(mission.getEndDate())
+ .build();
+ }
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/dto/MissionReqDTO.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/dto/MissionReqDTO.java
new file mode 100644
index 0000000..3a89c6c
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/dto/MissionReqDTO.java
@@ -0,0 +1,26 @@
+package com.example.umc10th.domain.mission.dto;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+
+import java.time.LocalDate;
+
+public class MissionReqDTO {
+
+ public record CreateMission(
+
+ @NotBlank(message = "์กฐ๊ฑด์ ๋น์นธ์ผ ์ ์์ต๋๋ค.")
+ String content,
+
+ @NotNull(message = "๋ง๊ฐ๊ธฐํ์ ํ์์
๋๋ค.")
+ LocalDate deadline,
+
+ @NotNull(message = "๋ฏธ์
์ฑ๊ณต ํฌ์ธํธ๋ ํ์์
๋๋ค.")
+ Integer point
+ ){}
+
+ public static class CompleteDTO {
+ public Long missionId;
+ }
+
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/dto/MissionResDTO.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/dto/MissionResDTO.java
new file mode 100644
index 0000000..ead74a5
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/dto/MissionResDTO.java
@@ -0,0 +1,29 @@
+package com.example.umc10th.domain.mission.dto;
+
+import lombok.*;
+
+public class MissionResDTO {
+
+ @Getter
+ @Builder
+ @AllArgsConstructor
+ @NoArgsConstructor
+ public static class MissionDTO {
+ public Long missionId;
+ public String marketName;
+ public String content;
+ public Integer point;
+ public String status;
+ }
+
+ public static class GetMissionDTO {
+ public Long missionId;
+ public Integer point;
+ public String status;
+ }
+
+ public static class CompleteDTO {
+ public Long missionId;
+ public String message;
+ }
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/dto/ParticipateReqDTO.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/dto/ParticipateReqDTO.java
new file mode 100644
index 0000000..a2d6edb
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/dto/ParticipateReqDTO.java
@@ -0,0 +1,9 @@
+package com.example.umc10th.domain.mission.dto;
+
+public class ParticipateReqDTO {
+
+ public record MyMissionRequest(
+ Long memberId
+ ) {
+ }
+}
\ No newline at end of file
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/dto/ParticipateResDTO.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/dto/ParticipateResDTO.java
new file mode 100644
index 0000000..fdc534d
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/dto/ParticipateResDTO.java
@@ -0,0 +1,19 @@
+package com.example.umc10th.domain.mission.dto;
+
+import lombok.Builder;
+
+import java.time.LocalDateTime;
+
+public class ParticipateResDTO {
+
+ @Builder
+ public record MyMissionPreviewDTO(
+
+ Long missionId,
+ String content,
+ Integer point,
+ LocalDateTime endDate
+
+ ) {
+ }
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/entity/Market.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/entity/Market.java
new file mode 100644
index 0000000..31dabb4
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/entity/Market.java
@@ -0,0 +1,34 @@
+package com.example.umc10th.domain.mission.entity;
+
+import com.example.umc10th.global.entity.BaseEntity;
+import jakarta.persistence.Entity;
+import jakarta.persistence.*;
+import lombok.*;
+
+import java.util.*;
+
+@Getter
+@Entity
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+public class Market extends BaseEntity {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ private String name;
+
+ @Column(name = "address_line_1")
+ private String addressLine1;
+
+ @Column(name = "address_line_2")
+ private String addressLine2;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "region_id")
+ private Region region;
+
+ @OneToMany(mappedBy = "market")
+ private List missionList = new ArrayList<>();
+
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/entity/Mission.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/entity/Mission.java
new file mode 100644
index 0000000..49e88d6
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/entity/Mission.java
@@ -0,0 +1,53 @@
+package com.example.umc10th.domain.mission.entity;
+
+import com.example.umc10th.domain.mission.entity.mapping.Participate;
+import com.example.umc10th.domain.mission.enums.MissionStatus;
+import com.example.umc10th.global.entity.BaseEntity;
+import jakarta.persistence.Entity;
+import jakarta.persistence.*;
+import lombok.*;
+
+import java.time.LocalDateTime;
+import java.util.*;
+
+@Getter
+@Entity
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+public class Mission extends BaseEntity {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ private String content;
+
+ private Integer point;
+
+ @Column(name = "end_date")
+ private LocalDateTime endDate;
+
+ @Enumerated(EnumType.STRING)
+ @Column(name = "mission_status")
+ private MissionStatus missionStatus;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "market_id")
+ private Market market;
+
+ @OneToMany(mappedBy = "mission")
+ private List participateList = new ArrayList<>();
+
+ @Builder
+ public Mission(
+ String content,
+ Integer point,
+ LocalDateTime endDate,
+ MissionStatus missionStatus,
+ Market market
+ ) {
+ this.content = content;
+ this.point = point;
+ this.endDate = endDate;
+ this.missionStatus = missionStatus;
+ this.market = market;
+ }
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/entity/Region.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/entity/Region.java
new file mode 100644
index 0000000..ed42b34
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/entity/Region.java
@@ -0,0 +1,15 @@
+package com.example.umc10th.domain.mission.entity;
+
+import com.example.umc10th.global.entity.BaseEntity;
+import jakarta.persistence.Entity;
+import jakarta.persistence.*;
+
+@Entity
+public class Region extends BaseEntity {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ private String name;
+
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/entity/mapping/Participate.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/entity/mapping/Participate.java
new file mode 100644
index 0000000..1da73f1
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/entity/mapping/Participate.java
@@ -0,0 +1,31 @@
+package com.example.umc10th.domain.mission.entity.mapping;
+
+import com.example.umc10th.domain.member.entity.Member;
+import com.example.umc10th.domain.mission.entity.Mission;
+import com.example.umc10th.domain.mission.enums.ParticipatedStatus;
+import com.example.umc10th.global.entity.BaseEntity;
+import jakarta.persistence.*;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@Entity
+@Getter
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+public class Participate extends BaseEntity {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ @Enumerated(EnumType.STRING)
+ private ParticipatedStatus status;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "member_id")
+ private Member member;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "mission_id")
+ private Mission mission;
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/enums/MissionStatus.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/enums/MissionStatus.java
new file mode 100644
index 0000000..6a17f20
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/enums/MissionStatus.java
@@ -0,0 +1,6 @@
+package com.example.umc10th.domain.mission.enums;
+
+public enum MissionStatus {
+ IN_PROGRESS,
+ EXPIRED
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/enums/ParticipatedStatus.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/enums/ParticipatedStatus.java
new file mode 100644
index 0000000..5bbe507
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/enums/ParticipatedStatus.java
@@ -0,0 +1,6 @@
+package com.example.umc10th.domain.mission.enums;
+
+public enum ParticipatedStatus {
+ CHALLERGING,
+ PARTICIPATED
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/exception/MarketException.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/exception/MarketException.java
new file mode 100644
index 0000000..d03a20e
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/exception/MarketException.java
@@ -0,0 +1,7 @@
+package com.example.umc10th.domain.mission.exception;
+
+import com.example.umc10th.global.apiPayload.code.BaseErrorCode;
+
+public class MarketException extends MissionException {
+ public MarketException(BaseErrorCode code) { super(code);}
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/exception/MissionException.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/exception/MissionException.java
new file mode 100644
index 0000000..26102e0
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/exception/MissionException.java
@@ -0,0 +1,13 @@
+package com.example.umc10th.domain.mission.exception;
+
+import com.example.umc10th.global.apiPayload.code.BaseErrorCode;
+
+public class MissionException extends RuntimeException {
+
+ private final BaseErrorCode code;
+
+ public MissionException(BaseErrorCode code) {
+ this.code = code;
+ }
+
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/exception/code/MarketErrorCode.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/exception/code/MarketErrorCode.java
new file mode 100644
index 0000000..2e7f3c5
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/exception/code/MarketErrorCode.java
@@ -0,0 +1,19 @@
+package com.example.umc10th.domain.mission.exception.code;
+
+import com.example.umc10th.global.apiPayload.code.BaseErrorCode;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.HttpStatus;
+
+@Getter
+@RequiredArgsConstructor
+public enum MarketErrorCode implements BaseErrorCode {
+
+ NOT_FOUND(HttpStatus.NOT_FOUND,
+ "MARKET404_1",
+ "ํด๋น ๊ฐ๊ฒ๊ฐ ์กด์ฌํ์ง ์์ต๋๋ค."),
+ ;
+ private final HttpStatus status;
+ private final String code;
+ private final String message;
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/exception/code/MissionErrorCode.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/exception/code/MissionErrorCode.java
new file mode 100644
index 0000000..ee79191
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/exception/code/MissionErrorCode.java
@@ -0,0 +1,4 @@
+package com.example.umc10th.domain.mission.exception.code;
+
+public enum MissionErrorCode {
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/exception/code/MissionSuccessCode.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/exception/code/MissionSuccessCode.java
new file mode 100644
index 0000000..1d998d7
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/exception/code/MissionSuccessCode.java
@@ -0,0 +1,23 @@
+package com.example.umc10th.domain.mission.exception.code;
+
+import com.example.umc10th.global.apiPayload.code.BaseSuccessCode;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.HttpStatus;
+
+@Getter
+@RequiredArgsConstructor
+public enum MissionSuccessCode implements BaseSuccessCode {
+
+ CREATED(HttpStatus.OK,
+ "MISSION200_1",
+ "์ฑ๊ณต์ ์ผ๋ก ๋ฏธ์
์ ์์ฑํ์ต๋๋ค."),
+ OK(HttpStatus.OK,
+ "MISSION200_2",
+ "์ฑ๊ณต์ ์ผ๋ก ๋ฏธ์
์ ์กฐํํ์ต๋๋ค."),
+ ;
+
+ private final HttpStatus status;
+ private final String code;
+ private final String message;
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/repository/MarketRepository.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/repository/MarketRepository.java
new file mode 100644
index 0000000..db23cbf
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/repository/MarketRepository.java
@@ -0,0 +1,7 @@
+package com.example.umc10th.domain.mission.repository;
+
+import com.example.umc10th.domain.mission.entity.Market;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface MarketRepository extends JpaRepository {
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/repository/MissionRepository.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/repository/MissionRepository.java
new file mode 100644
index 0000000..6b3738e
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/repository/MissionRepository.java
@@ -0,0 +1,27 @@
+package com.example.umc10th.domain.mission.repository;
+
+import com.example.umc10th.domain.mission.entity.Mission;
+import com.example.umc10th.domain.mission.enums.MissionStatus;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Slice;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+
+public interface MissionRepository extends JpaRepository {
+
+ @Query("""
+ SELECT m
+ FROM Mission m
+ JOIN FETCH m.market mk
+ JOIN FETCH mk.region r
+ WHERE r.name = :regionName
+ AND m.missionStatus = :status
+ """)
+ Slice findMissionByRegion(
+ @Param("regionName") String regionName,
+ @Param("status") MissionStatus status,
+ Pageable pageable
+ );
+
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/repository/ParticipateRepository.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/repository/ParticipateRepository.java
new file mode 100644
index 0000000..450701f
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/repository/ParticipateRepository.java
@@ -0,0 +1,35 @@
+package com.example.umc10th.domain.mission.repository;
+
+import com.example.umc10th.domain.mission.entity.mapping.Participate;
+import com.example.umc10th.domain.mission.enums.ParticipatedStatus;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Slice;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface ParticipateRepository extends JpaRepository {
+
+ @Query("""
+ SELECT p
+ FROM Participate p
+ JOIN FETCH p.mission m
+ WHERE p.member.id = :memberId
+ AND p.status = :status
+ """)
+ Slice findMissionListByMemberAndStatus(
+ @Param("memberId") Long memberId,
+ @Param("status") ParticipatedStatus status,
+ Pageable pageable
+ );
+
+ Page findAllByMemberIdAndStatus(
+ Long memberId,
+ ParticipatedStatus status,
+ Pageable pageable
+ );
+
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/service/MissionService.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/service/MissionService.java
new file mode 100644
index 0000000..111df8a
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/mission/service/MissionService.java
@@ -0,0 +1,133 @@
+package com.example.umc10th.domain.mission.service;
+
+import com.example.umc10th.domain.mission.converter.MissionConverter;
+import com.example.umc10th.domain.mission.converter.ParticipateConverter;
+import com.example.umc10th.domain.mission.dto.MissionReqDTO;
+import com.example.umc10th.domain.mission.dto.MissionResDTO;
+import com.example.umc10th.domain.mission.dto.ParticipateResDTO;
+import com.example.umc10th.domain.mission.entity.Market;
+import com.example.umc10th.domain.mission.entity.Mission;
+import com.example.umc10th.domain.mission.entity.mapping.Participate;
+import com.example.umc10th.domain.mission.enums.MissionStatus;
+import com.example.umc10th.domain.mission.enums.ParticipatedStatus;
+import com.example.umc10th.domain.mission.exception.MarketException;
+import com.example.umc10th.domain.mission.exception.code.MarketErrorCode;
+import com.example.umc10th.domain.mission.repository.MarketRepository;
+import com.example.umc10th.domain.mission.repository.MissionRepository;
+import com.example.umc10th.domain.mission.repository.ParticipateRepository;
+import com.example.umc10th.global.apiPayload.dto.PageResponseDTO;
+import lombok.RequiredArgsConstructor;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Slice;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+@Service
+@RequiredArgsConstructor
+@Transactional(readOnly = true)
+public class MissionService {
+
+ private final ParticipateRepository participateRepository;
+ private final MissionRepository missionRepository;
+ private final MarketRepository marketRepository;
+
+ @Transactional
+ public void createMission(
+ Long marketId,
+ MissionReqDTO.CreateMission dto
+ ){
+ Market market = marketRepository.findById(marketId)
+ .orElseThrow(() -> new MarketException(MarketErrorCode.NOT_FOUND));
+
+ Mission mission = MissionConverter.toMission(market, dto);
+
+ missionRepository.save(mission);
+
+ }
+
+ public PageResponseDTO getMissionList(
+ Long memberId,
+ ParticipatedStatus status,
+ Integer page,
+ Integer size
+ ) {
+
+ Pageable pageable = PageRequest.of(page, size);
+
+ Slice participatePage =
+ participateRepository.findMissionListByMemberAndStatus(
+ memberId,
+ status,
+ pageable
+ );
+
+ List missionList =
+ participatePage.stream()
+ .map(MissionConverter::toMissionDTO)
+ .toList();
+
+ return PageResponseDTO.builder()
+ .content(missionList)
+ .page(page)
+ .size(size)
+ .hasNext(participatePage.hasNext())
+ .build();
+ }
+
+ public PageResponseDTO getHomeMissionList(
+ String regionName,
+ Integer page,
+ Integer size
+ ) {
+
+ Pageable pageable = PageRequest.of(page, size);
+
+ Slice missionPage =
+ missionRepository.findMissionByRegion(
+ regionName,
+ MissionStatus.IN_PROGRESS,
+ pageable
+ );
+
+ List missionList =
+ missionPage.stream()
+ .map(MissionConverter::toHomeMissionDTO)
+ .toList();
+
+ return PageResponseDTO.builder()
+ .content(missionList)
+ .page(page)
+ .size(size)
+ .hasNext(missionPage.hasNext())
+ .build();
+ }
+
+ @Transactional(readOnly = true)
+ public Page
+ getMyMissions(
+ Long memberId,
+ Integer page,
+ Integer size
+ ){
+
+ PageRequest pageRequest =
+ PageRequest.of(page, size);
+
+ Page participatePage =
+ participateRepository
+ .findAllByMemberIdAndStatus(
+ memberId,
+ ParticipatedStatus.CHALLERGING,
+ pageRequest
+ );
+
+ return participatePage.map(
+ ParticipateConverter::toMyMissionPreviewDTO
+ );
+ }
+
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/review/controller/ReviewController.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/review/controller/ReviewController.java
new file mode 100644
index 0000000..8348869
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/review/controller/ReviewController.java
@@ -0,0 +1,63 @@
+package com.example.umc10th.domain.review.controller;
+
+import com.example.umc10th.domain.review.dto.ReviewReqDTO;
+import com.example.umc10th.domain.review.dto.ReviewResDTO;
+import com.example.umc10th.domain.review.enums.ReviewSortType;
+import com.example.umc10th.domain.review.service.ReviewService;
+import com.example.umc10th.global.apiPayload.ApiResponse;
+import lombok.RequiredArgsConstructor;
+import org.springframework.data.domain.Slice;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequestMapping("/review")
+@RequiredArgsConstructor
+public class ReviewController {
+
+ private final ReviewService reviewService;
+
+ @PostMapping("/markets/{marketId}")
+ public ApiResponse createReview(
+ @PathVariable Long marketId,
+ @RequestParam Long memberId,
+ @RequestBody ReviewReqDTO.CreateReviewDTO request
+ ) {
+
+ ReviewResDTO.CreateReviewDTO response =
+ reviewService.createReview(memberId, marketId, request);
+
+ return ApiResponse.onSuccess(response);
+ }
+
+ @GetMapping("/my")
+ public ApiResponse>
+ getMyReviews(
+
+ @RequestParam Long memberId,
+
+ @RequestParam(required = false)
+ Long cursorId,
+
+ @RequestParam(required = false)
+ Integer cursorStars,
+
+ @RequestParam(defaultValue = "5")
+ Integer size,
+
+ @RequestParam(defaultValue = "ID")
+ ReviewSortType sort
+
+ ){
+
+ return ApiResponse.onSuccess(
+ reviewService.getMyReviews(
+ memberId,
+ cursorId,
+ cursorStars,
+ size,
+ sort
+ )
+ );
+ }
+
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/review/converter/ReviewConverter.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/review/converter/ReviewConverter.java
new file mode 100644
index 0000000..ba0b095
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/review/converter/ReviewConverter.java
@@ -0,0 +1,48 @@
+package com.example.umc10th.domain.review.converter;
+
+import com.example.umc10th.domain.member.entity.Member;
+import com.example.umc10th.domain.mission.entity.Market;
+import com.example.umc10th.domain.review.dto.ReviewReqDTO;
+import com.example.umc10th.domain.review.dto.ReviewResDTO;
+import com.example.umc10th.domain.review.entity.Review;
+
+public class ReviewConverter {
+
+ public static Review toReview(
+ Member member,
+ Market market,
+ ReviewReqDTO.CreateReviewDTO request
+ ) {
+
+ return Review.builder()
+ .member(member)
+ .market(market)
+ .stars(request.getStars())
+ .content(request.getContent())
+ .build();
+ }
+
+ public static ReviewResDTO.CreateReviewDTO toCreateReviewDTO(
+ Review review
+ ) {
+
+ return ReviewResDTO.CreateReviewDTO.builder()
+ .reviewId(review.getId())
+ .message("๋ฆฌ๋ทฐ ์์ฑ ์๋ฃ!")
+ .build();
+ }
+
+ public static ReviewResDTO.MyReviewPreviewDTO
+ toMyReviewPreviewDTO(
+ Review review
+ ){
+
+ return ReviewResDTO.MyReviewPreviewDTO.builder()
+ .reviewId(review.getId())
+ .stars(review.getStars())
+ .content(review.getContent())
+ .marketName(review.getMarket().getName())
+ .build();
+ }
+
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/review/dto/ReviewReqDTO.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/review/dto/ReviewReqDTO.java
new file mode 100644
index 0000000..7eacf27
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/review/dto/ReviewReqDTO.java
@@ -0,0 +1,12 @@
+package com.example.umc10th.domain.review.dto;
+
+import lombok.*;
+
+public class ReviewReqDTO {
+
+ @Getter @Setter
+ public static class CreateReviewDTO {
+ private Integer stars;
+ private String content;
+ }
+}
\ No newline at end of file
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/review/dto/ReviewResDTO.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/review/dto/ReviewResDTO.java
new file mode 100644
index 0000000..31e49d4
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/review/dto/ReviewResDTO.java
@@ -0,0 +1,27 @@
+package com.example.umc10th.domain.review.dto;
+
+import lombok.*;
+
+public class ReviewResDTO {
+
+ @Getter
+ @Builder
+ @AllArgsConstructor
+ @NoArgsConstructor
+ public static class CreateReviewDTO {
+ private Long reviewId;
+ private String message;
+ }
+
+ @Builder
+ public record MyReviewPreviewDTO(
+
+ Long reviewId,
+ Integer stars,
+ String content,
+ String marketName
+
+ ) {
+ }
+
+}
\ No newline at end of file
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/review/entity/Review.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/review/entity/Review.java
new file mode 100644
index 0000000..511a043
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/review/entity/Review.java
@@ -0,0 +1,32 @@
+package com.example.umc10th.domain.review.entity;
+
+import com.example.umc10th.domain.member.entity.Member;
+import com.example.umc10th.domain.mission.entity.Market;
+import com.example.umc10th.global.entity.BaseEntity;
+import jakarta.persistence.*;
+import lombok.*;
+
+@Entity
+@Getter @Builder
+@Table(name = "review")
+@AllArgsConstructor
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+public class Review extends BaseEntity {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "member_id")
+ private Member member;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "market_id")
+ private Market market;
+
+ private Integer stars;
+
+ private String content;
+
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/review/enums/ReviewSortType.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/review/enums/ReviewSortType.java
new file mode 100644
index 0000000..7e34104
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/review/enums/ReviewSortType.java
@@ -0,0 +1,6 @@
+package com.example.umc10th.domain.review.enums;
+
+public enum ReviewSortType {
+ ID,
+ STARS
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/review/exception/ReviewException.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/review/exception/ReviewException.java
new file mode 100644
index 0000000..270f27a
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/review/exception/ReviewException.java
@@ -0,0 +1,14 @@
+package com.example.umc10th.domain.review.exception;
+
+import com.example.umc10th.domain.review.exception.code.ReviewErrorCode;
+import lombok.Getter;
+
+@Getter
+public class ReviewException extends RuntimeException {
+
+ private final ReviewErrorCode errorCode;
+
+ public ReviewException(ReviewErrorCode errorCode) {
+ this.errorCode = errorCode;
+ }
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/review/exception/code/ReviewErrorCode.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/review/exception/code/ReviewErrorCode.java
new file mode 100644
index 0000000..f30154a
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/review/exception/code/ReviewErrorCode.java
@@ -0,0 +1,18 @@
+package com.example.umc10th.domain.review.exception.code;
+
+import com.example.umc10th.global.apiPayload.code.BaseErrorCode;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.springframework.http.HttpStatus;
+
+@Getter
+@AllArgsConstructor
+public enum ReviewErrorCode implements BaseErrorCode {
+
+ MEMBER_NOT_FOUND(HttpStatus.NOT_FOUND, "REVIEW4001", "๋ฉค๋ฒ๊ฐ ์กด์ฌํ์ง ์์ต๋๋ค."),
+ MARKET_NOT_FOUND(HttpStatus.NOT_FOUND, "REVIEW4002", "๊ฐ๊ฒ๊ฐ ์กด์ฌํ์ง ์์ต๋๋ค.");
+
+ private final HttpStatus status;
+ private final String code;
+ private final String message;
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/review/exception/code/ReviewSuccessCode.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/review/exception/code/ReviewSuccessCode.java
new file mode 100644
index 0000000..fb2f221
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/review/exception/code/ReviewSuccessCode.java
@@ -0,0 +1,4 @@
+package com.example.umc10th.domain.review.exception.code;
+
+public enum ReviewSuccessCode {
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/review/repository/ReviewRepository.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/review/repository/ReviewRepository.java
new file mode 100644
index 0000000..3d649d2
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/review/repository/ReviewRepository.java
@@ -0,0 +1,47 @@
+package com.example.umc10th.domain.review.repository;
+
+import com.example.umc10th.domain.review.entity.Review;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Slice;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+
+public interface ReviewRepository extends JpaRepository {
+
+ Slice findByMemberIdOrderByIdDesc(
+ Long memberId,
+ Pageable pageable
+ );
+
+ Slice findByMemberIdAndIdLessThanOrderByIdDesc(
+ Long memberId,
+ Long cursor,
+ Pageable pageable
+ );
+
+ // STARS ์ ๋ ฌ ์ฒซ ํ์ด์ง
+ Slice findByMemberIdOrderByStarsDescIdDesc(
+ Long memberId,
+ Pageable pageable
+ );
+
+ // STARS ๋ณตํฉ cursor ์กฐํ
+ @Query("""
+ SELECT r
+ FROM Review r
+ WHERE r.member.id = :memberId
+ AND (
+ r.stars < :stars
+ OR (r.stars = :stars AND r.id < :id)
+ )
+ ORDER BY r.stars DESC, r.id DESC
+""")
+ Slice findByStarsCursor(
+ @Param("memberId") Long memberId,
+ @Param("stars") Integer stars,
+ @Param("id") Long id,
+ Pageable pageable
+ );
+
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/domain/review/service/ReviewService.java b/luke/umc10th/src/main/java/com/example/umc10th/domain/review/service/ReviewService.java
new file mode 100644
index 0000000..6a1a1f3
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/domain/review/service/ReviewService.java
@@ -0,0 +1,135 @@
+package com.example.umc10th.domain.review.service;
+
+import com.example.umc10th.domain.member.entity.Member;
+import com.example.umc10th.domain.member.repository.MemberRepository;
+import com.example.umc10th.domain.mission.entity.Market;
+import com.example.umc10th.domain.mission.repository.MarketRepository;
+import com.example.umc10th.domain.review.converter.ReviewConverter;
+import com.example.umc10th.domain.review.dto.ReviewReqDTO;
+import com.example.umc10th.domain.review.dto.ReviewResDTO;
+import com.example.umc10th.domain.review.entity.Review;
+import com.example.umc10th.domain.review.enums.ReviewSortType;
+import com.example.umc10th.domain.review.exception.ReviewException;
+import com.example.umc10th.domain.review.exception.code.ReviewErrorCode;
+import com.example.umc10th.domain.review.repository.ReviewRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Slice;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@RequiredArgsConstructor
+@Transactional(readOnly = true)
+public class ReviewService {
+
+ private final ReviewRepository reviewRepository;
+ private final MemberRepository memberRepository;
+ private final MarketRepository marketRepository;
+
+ @Transactional
+ public ReviewResDTO.CreateReviewDTO createReview(
+ Long memberId,
+ Long marketId,
+ ReviewReqDTO.CreateReviewDTO request
+ ) {
+
+ Member member = memberRepository.findById(memberId)
+ .orElseThrow(() ->
+ new ReviewException(ReviewErrorCode.MEMBER_NOT_FOUND));
+
+ Market market = marketRepository.findById(marketId)
+ .orElseThrow(() ->
+ new ReviewException(ReviewErrorCode.MARKET_NOT_FOUND));
+
+ Review review = ReviewConverter.toReview(
+ member,
+ market,
+ request
+ );
+
+ Review savedReview = reviewRepository.save(review);
+
+ return ReviewConverter.toCreateReviewDTO(savedReview);
+
+ }
+
+ @Transactional(readOnly = true)
+ public Slice
+ getMyReviews(
+ Long memberId,
+ Long cursorId,
+ Integer cursorStars,
+ Integer size,
+ ReviewSortType sort
+ ){
+
+ Pageable pageable = PageRequest.of(0, size);
+
+ Slice reviewSlice;
+
+ if(sort == ReviewSortType.STARS){
+
+ // ์ฒซ ํ์ด์ง
+ if(cursorStars == null || cursorId == null){
+
+ reviewSlice =
+ reviewRepository
+ .findByMemberIdOrderByStarsDescIdDesc(
+ memberId,
+ pageable
+ );
+
+ }
+
+ // ๋ค์ ํ์ด์ง
+ else {
+
+ reviewSlice =
+ reviewRepository
+ .findByStarsCursor(
+ memberId,
+ cursorStars,
+ cursorId,
+ pageable
+ );
+ }
+
+ }
+
+ else {
+
+ // ์ฒซ ํ์ด์ง
+ if(cursorId == null){
+
+ reviewSlice =
+ reviewRepository
+ .findByMemberIdOrderByIdDesc(
+ memberId,
+ pageable
+ );
+
+ }
+
+ // ๋ค์ ํ์ด์ง
+ else {
+
+ reviewSlice =
+ reviewRepository
+ .findByMemberIdAndIdLessThanOrderByIdDesc(
+ memberId,
+ cursorId,
+ pageable
+ );
+ }
+
+ }
+
+
+ return reviewSlice.map(
+ ReviewConverter::toMyReviewPreviewDTO
+ );
+ }
+
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/global/apiPayload/ApiResponse.java b/luke/umc10th/src/main/java/com/example/umc10th/global/apiPayload/ApiResponse.java
new file mode 100644
index 0000000..f34ca31
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/global/apiPayload/ApiResponse.java
@@ -0,0 +1,35 @@
+package com.example.umc10th.global.apiPayload;
+
+import com.example.umc10th.global.apiPayload.code.BaseErrorCode;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+@JsonPropertyOrder({"isSuccess", "code", "message", "result"})
+public class ApiResponse {
+
+ @JsonProperty("isSuccess")
+ private final Boolean isSuccess;
+
+ @JsonProperty("code")
+ private final String code;
+
+ @JsonProperty("message")
+ private final String message;
+
+ @JsonProperty("result")
+ private final T result;
+
+ // ์ฑ๊ณตํ ๊ฒฝ์ฐ (result ํฌํจ)
+ public static ApiResponse onSuccess(T result) {
+ return new ApiResponse<>(true, "COMMON200", "์ฑ๊ณต์
๋๋ค.", result);
+ }
+
+ // ์คํจํ ๊ฒฝ์ฐ (result ํฌํจ)
+ public static ApiResponse onFailure(BaseErrorCode code, T result ) {
+ return new ApiResponse<>(false, code.getCode(), code.getMessage(), result);
+ }
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/global/apiPayload/code/BaseErrorCode.java b/luke/umc10th/src/main/java/com/example/umc10th/global/apiPayload/code/BaseErrorCode.java
new file mode 100644
index 0000000..137c8ac
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/global/apiPayload/code/BaseErrorCode.java
@@ -0,0 +1,9 @@
+package com.example.umc10th.global.apiPayload.code;
+
+import org.springframework.http.HttpStatus;
+
+public interface BaseErrorCode {
+ HttpStatus getStatus();
+ String getCode();
+ String getMessage();
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/global/apiPayload/code/BaseSuccessCode.java b/luke/umc10th/src/main/java/com/example/umc10th/global/apiPayload/code/BaseSuccessCode.java
new file mode 100644
index 0000000..5ebb033
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/global/apiPayload/code/BaseSuccessCode.java
@@ -0,0 +1,10 @@
+package com.example.umc10th.global.apiPayload.code;
+
+import org.springframework.http.HttpStatus;
+
+public interface BaseSuccessCode {
+
+ HttpStatus getStatus();
+ String getCode();
+ String getMessage();
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/global/apiPayload/code/GeneralErrorCode.java b/luke/umc10th/src/main/java/com/example/umc10th/global/apiPayload/code/GeneralErrorCode.java
new file mode 100644
index 0000000..6f77729
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/global/apiPayload/code/GeneralErrorCode.java
@@ -0,0 +1,34 @@
+package com.example.umc10th.global.apiPayload.code;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.HttpStatus;
+
+@Getter
+@RequiredArgsConstructor
+public enum GeneralErrorCode implements BaseErrorCode {
+
+ BAD_REQUEST(HttpStatus.BAD_REQUEST,
+ "COMMON400_1",
+ "์๋ชป๋ ์์ฒญ์
๋๋ค."),
+ UNAUTHORIZED(HttpStatus.UNAUTHORIZED,
+ "COMMON401_1",
+ "์ธ์ฆ๋์ง ์์์ต๋๋ค."),
+ FORBIDDEN(HttpStatus.FORBIDDEN,
+ "COMMON403_1",
+ "์ ๊ทผ์ด ๊ธ์ง๋์์ต๋๋ค."),
+ NOT_FOUND(HttpStatus.NOT_FOUND,
+ "Common404_1",
+ "ํด๋น ๋ฆฌ์์ค๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค."
+ ),
+ ;
+
+ private final HttpStatus status;
+ private final String code;
+ private final String message;
+
+}
+
+
+
+
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/global/apiPayload/code/GeneralSuccessCode.java b/luke/umc10th/src/main/java/com/example/umc10th/global/apiPayload/code/GeneralSuccessCode.java
new file mode 100644
index 0000000..4e0d00f
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/global/apiPayload/code/GeneralSuccessCode.java
@@ -0,0 +1,19 @@
+package com.example.umc10th.global.apiPayload.code;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.HttpStatus;
+
+@Getter@RequiredArgsConstructor
+public enum GeneralSuccessCode implements BaseErrorCode{
+
+ OK(HttpStatus.OK,
+ "COMMON200_1",
+ "์ฑ๊ณต์ ์ผ๋ก ์์ฒญ์ ์ฒ๋ฆฌํ์ต๋๋ค."),
+
+ ;
+
+ private final HttpStatus status;
+ private final String code;
+ private final String message;
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/global/apiPayload/dto/PageResponseDTO.java b/luke/umc10th/src/main/java/com/example/umc10th/global/apiPayload/dto/PageResponseDTO.java
new file mode 100644
index 0000000..c4072b8
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/global/apiPayload/dto/PageResponseDTO.java
@@ -0,0 +1,16 @@
+package com.example.umc10th.global.apiPayload.dto;
+
+import lombok.*;
+
+import java.util.List;
+
+@Getter
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class PageResponseDTO {
+ private List content;
+ private Integer page;
+ private Integer size;
+ private Boolean hasNext;
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/global/config/SwaggerConfig.java b/luke/umc10th/src/main/java/com/example/umc10th/global/config/SwaggerConfig.java
new file mode 100644
index 0000000..f0152ae
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/global/config/SwaggerConfig.java
@@ -0,0 +1,36 @@
+package com.example.umc10th.global.config;
+
+import io.swagger.v3.oas.models.info.Info;
+import io.swagger.v3.oas.models.servers.Server;
+import io.swagger.v3.oas.models.Components;
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.security.SecurityRequirement;
+import io.swagger.v3.oas.models.security.SecurityScheme;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class SwaggerConfig {
+
+ @Bean
+ public OpenAPI swagger() {
+ Info info = new Info().title("UMC10th").description("10๊ธฐ Swagger").version("0.0.1");
+
+ // JWT ํ ํฐ ํค๋ ๋ฐฉ์
+ String securityScheme = "JWT TOKEN";
+ SecurityRequirement securityRequirement = new SecurityRequirement().addList(securityScheme);
+
+ Components components = new Components()
+ .addSecuritySchemes(securityScheme, new SecurityScheme()
+ .name(securityScheme)
+ .type(SecurityScheme.Type.HTTP)
+ .scheme("Bearer")
+ .bearerFormat("JWT"));
+
+ return new OpenAPI()
+ .info(info)
+ .addServersItem(new Server().url("/api/v1"))
+ .addSecurityItem(securityRequirement)
+ .components(components);
+ }
+}
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/global/entity/BaseEntity.java b/luke/umc10th/src/main/java/com/example/umc10th/global/entity/BaseEntity.java
new file mode 100644
index 0000000..bab9c45
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/global/entity/BaseEntity.java
@@ -0,0 +1,28 @@
+package com.example.umc10th.global.entity;
+
+import jakarta.persistence.Column;
+import jakarta.persistence.EntityListeners;
+import jakarta.persistence.MappedSuperclass;
+import lombok.Getter;
+import org.springframework.data.annotation.CreatedDate;
+import org.springframework.data.annotation.LastModifiedDate;
+import org.springframework.data.jpa.domain.support.AuditingEntityListener;
+
+import java.time.LocalDateTime;
+
+@Getter
+@MappedSuperclass
+@EntityListeners(AuditingEntityListener.class)
+public abstract class BaseEntity {
+
+ @CreatedDate
+ @Column(name = "created_at", nullable = false, updatable = false)
+ private LocalDateTime createdAt;
+
+ @LastModifiedDate
+ @Column(name = "updated_at", nullable = false)
+ private LocalDateTime updatedAt;
+
+ @Column(name = "deleted_at")
+ private LocalDateTime deletedAt;
+}
\ No newline at end of file
diff --git a/luke/umc10th/src/main/java/com/example/umc10th/global/execption/GeneralExceptionAdvice.java b/luke/umc10th/src/main/java/com/example/umc10th/global/execption/GeneralExceptionAdvice.java
new file mode 100644
index 0000000..b596bb0
--- /dev/null
+++ b/luke/umc10th/src/main/java/com/example/umc10th/global/execption/GeneralExceptionAdvice.java
@@ -0,0 +1,34 @@
+package com.example.umc10th.global.execption;
+
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@RestControllerAdvice
+public class GeneralExceptionAdvice {
+
+ @ExceptionHandler(MethodArgumentNotValidException.class)
+ public ResponseEntity