diff --git a/.github/pull-request-template.md b/.github/pull-request-template.md
index 8b17f79e91..aa4599b4fb 100644
--- a/.github/pull-request-template.md
+++ b/.github/pull-request-template.md
@@ -1,20 +1,67 @@
## 요구사항
### 기본
-- [x] 기본 항목 1
-- [ ] 기본 항목 2
-### 심화
-- [ ] 심화 항목 1
-- [ ] 심화 항목 2
+프로젝트 초기화
-## 주요 변경사항
--
--
+- [x] IntelliJ를 통해 다음의 조건으로 Java 프로젝트를 생성합니다.
+- [x] IntelliJ에서 제공하는 프로젝트 템플릿 중 Java를 선택합니다.
+- [x] 프로젝트의 경로는 스프린트 미션 리포지토리의 경로와 같게 설정합니다.
+- [x] Create Git Repository 옵션은 체크하지 않습니다.
+- [x] Build system은 Gradle을 사용합니다. Gradle DSL은 Groovy를 사용합니다.
+- [x] JDK 17을 선택합니다.
+- [x] GroupId는 com.sprint.mission로 설정합니다.
+- [x] ArtifactId는 수정하지 않습니다.
+- [x] .gitignore에 IntelliJ와 관련된 파일이 형상관리 되지 않도록 .idea디렉토리를 추가합니다.
-## 스크린샷
-
+도메인 모델링
+
+- [x] 디스코드 서비스를 활용해보면서 각 도메인 모델에 필요한 정보를 도출하고, Java Class로 구현하세요.
+ - [x] 패키지명: com.sprint.mission.discodeit.entity
+ - [x] 도메인 모델 정의
+ - [x] 공통
+ - [x] id: 객체를 식별하기 위한 id로 UUID 타입으로 선언합니다.
+ - [x] createdAt, updatedAt: 각각 객체의 생성, 수정 시간을 유닉스 타임스탬프로 나타내기 위한 필드로 Long 타입으로 선언합니다.
+ - [x] User
+ - [x] Channel
+ - [x] Message
+ - [x] 생성자
+ - [x] id는 생성자에서 초기화하세요.
+ - [x] createdAt는 생성자에서 초기화하세요.
+ - [x] id, createdAt, updatedAt을 제외한 필드는 생성자의 파라미터를 통해 초기화하세요.
+ - [x] 메소드
+ - [x] 각 필드를 반환하는 Getter 함수를 정의하세요.
+ - [x] 필드를 수정하는 update 함수를 정의하세요.
+
+서비스 설계 및 구현
+
+- [x] 도메인 모델 별 CRUD(생성, 읽기, 모두 읽기, 수정, 삭제) 기능을 인터페이스로 선언하세요.
+- [x] 인터페이스 패키지명: com.sprint.mission.discodeit.service
+- [x] 인터페이스 네이밍 규칙: [도메인 모델 이름]Service
+- [x] 다음의 조건을 만족하는 서비스 인터페이스의 구현체를 작성하세요.
+- [x] 클래스 패키지명: com.sprint.mission.discodeit.service.jcf
+- [x] 클래스 네이밍 규칙: JCF[인터페이스 이름]
+- [x] Java Collections Framework를 활용하여 데이터를 저장할 수 있는 필드(data)를 final로 선언하고 생성자에서 초기화하세요.
+- [x] data 필드를 활용해 생성, 조회, 수정, 삭제하는 메소드를 구현하세요.
+메인 클래스 구현
+
+- [x] 메인 메소드가 선언된 JavaApplication 클래스를 선언하고, 도메인 별 서비스 구현체를 테스트해보세요.
+- [x] 등록
+- [x] 조회(단건, 다건)
+- [x] 수정
+- [x] 수정된 데이터 조회
+- [x] 삭제
+- [x] 조회를 통해 삭제되었는지 확인
+
+
+## 스크린샷
+[User CRUD Results]
+
+[Channel CRUD Results]
+
+[Message CRUD Results]
+
## 멘토에게
-- 셀프 코드 리뷰를 통해 질문 이어가겠습니다.
--
\ No newline at end of file
+- Message 클래스에 update 메소드를 JCFMessageService클래스에서 content가 UUID 타입으로 받아져서 두번 써서 해결했는데 괜찮은건지 궁금합니다
+- 셀프 코드 리뷰를 통해 질문 이어가겠습니다.
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000..aa7f43b323
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,44 @@
+.idea
+
+.gradle
+build/
+!gradle/wrapper/gradle-wrapper.jar
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### IntelliJ IDEA ###
+.idea/modules.xml
+.idea/jarRepositories.xml
+.idea/compiler.xml
+.idea/libraries/
+*.iws
+*.iml
+*.ipr
+out/
+!**/src/main/**/out/
+!**/src/test/**/out/
+
+### Eclipse ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+bin/
+!**/src/main/**/bin/
+!**/src/test/**/bin/
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+
+### VS Code ###
+.vscode/
+
+### Mac OS ###
+.DS_Store
\ No newline at end of file
diff --git a/HELP.md b/HELP.md
new file mode 100644
index 0000000000..42c5f00231
--- /dev/null
+++ b/HELP.md
@@ -0,0 +1,22 @@
+# Getting Started
+
+### Reference Documentation
+For further reference, please consider the following sections:
+
+* [Official Gradle documentation](https://docs.gradle.org)
+* [Spring Boot Gradle Plugin Reference Guide](https://docs.spring.io/spring-boot/3.4.0/gradle-plugin)
+* [Create an OCI image](https://docs.spring.io/spring-boot/3.4.0/gradle-plugin/packaging-oci-image.html)
+* [Spring Web](https://docs.spring.io/spring-boot/3.4.0/reference/web/servlet.html)
+
+### Guides
+The following guides illustrate how to use some features concretely:
+
+* [Building a RESTful Web Service](https://spring.io/guides/gs/rest-service/)
+* [Serving Web Content with Spring MVC](https://spring.io/guides/gs/serving-web-content/)
+* [Building REST services with Spring](https://spring.io/guides/tutorials/rest/)
+
+### Additional Links
+These additional references should also help you:
+
+* [Gradle Build Scans – insights for your project's build](https://scans.gradle.com#gradle)
+
diff --git a/README.md b/README.md
index 81a8535d90..815bede54f 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,2 @@
-# Spring 백엔드 트랙 1기 스프린트 미션 제출 리포지토리
\ No newline at end of file
+# 0-spring-mission
+스프린트 미션 모범 답안 리포지토리입니다.
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000000..2adfcfcaa8
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,36 @@
+plugins {
+ id 'java'
+ id 'org.springframework.boot' version '3.4.0'
+ id 'io.spring.dependency-management' version '1.1.6'
+}
+
+group = 'com.sprint.mission'
+version = '0.0.1-SNAPSHOT'
+
+java {
+ toolchain {
+ languageVersion = JavaLanguageVersion.of(17)
+ }
+}
+
+configurations {
+ compileOnly {
+ extendsFrom annotationProcessor
+ }
+}
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ implementation 'org.springframework.boot:spring-boot-starter-web'
+ compileOnly 'org.projectlombok:lombok'
+ annotationProcessor 'org.projectlombok:lombok'
+ testImplementation 'org.springframework.boot:spring-boot-starter-test'
+ testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
+}
+
+tasks.named('test') {
+ useJUnitPlatform()
+}
diff --git a/checkstyle.xml b/checkstyle.xml
new file mode 100644
index 0000000000..98e3c8f0ce
--- /dev/null
+++ b/checkstyle.xml
@@ -0,0 +1,442 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000000..a4b76b9530
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000000..e2847c8200
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,7 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000000..f5feea6d6b
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,252 @@
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 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/HEAD/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
+' "$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
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# 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" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ 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, 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" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# 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/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000000..9d21a21834
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,94 @@
+@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
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+: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/settings.gradle b/settings.gradle
new file mode 100644
index 0000000000..2437dfb29c
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = 'discodeit'
diff --git a/src/main/java/com/sprint/mission/discodeit/DiscodeitApplication.java b/src/main/java/com/sprint/mission/discodeit/DiscodeitApplication.java
new file mode 100644
index 0000000000..039e1d9009
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/DiscodeitApplication.java
@@ -0,0 +1,12 @@
+package com.sprint.mission.discodeit;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class DiscodeitApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(DiscodeitApplication.class, args);
+ }
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/Main.java b/src/main/java/com/sprint/mission/discodeit/Main.java
new file mode 100644
index 0000000000..302807c1e4
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/Main.java
@@ -0,0 +1,78 @@
+package com.sprint.mission.discodeit;
+
+import com.sprint.mission.discodeit.entity.Channel;
+import com.sprint.mission.discodeit.entity.Message;
+import com.sprint.mission.discodeit.entity.User;
+import com.sprint.mission.discodeit.service.jcf.JCFChannelService;
+import com.sprint.mission.discodeit.service.jcf.JCFMessageService;
+import com.sprint.mission.discodeit.service.jcf.JCFUserService;
+
+import java.util.List;
+
+public class Main {
+ public static void main(String[] args) {
+ JCFUserService userService = new JCFUserService();
+ JCFChannelService channelService = new JCFChannelService();
+ JCFMessageService messageService = new JCFMessageService(userService, channelService);
+
+ User userA = userService.createUser("Jun", "junhan5231@naver.com");
+ System.out.println("유저 생성: " + userA.getUsername());
+
+ User retrievedUser = userService.getUser(userA.getId());
+ System.out.println("조회된 유저: " + retrievedUser.getUsername());
+
+ List allUsers = userService.getAllUsers();
+ System.out.println("전체 유저 수: " + allUsers.size());
+
+ User updatedUser = userService.updateUser(userA.getId(), "Junhan", "jun5231@naver.com");
+ System.out.println("수정된 유저: " + updatedUser.getUsername());
+
+ User retrievedUpdatedUser = userService.getUser(userA.getId());
+ System.out.println("수정 후 조회된 유저: " + retrievedUpdatedUser.getUsername());
+
+ Channel channelA = channelService.createChannel("일반", "일반채널");
+ System.out.println("채널 생성: " + channelA.getName());
+
+ Channel retrievedChannel = channelService.getChannel(channelA.getId());
+ System.out.println("조회된 채널: " + retrievedChannel.getName());
+
+ List allChannels = channelService.getAllChannels();
+ System.out.println("전체 채널 수: " + allChannels.size());
+
+ Channel updatedChannel = channelService.updateChannel(channelA.getId(), "수정된 일반", "수정된 일반채널");
+ System.out.println("수정된 채널: " + updatedChannel.getName());
+
+ Channel retrievedUpdatedChannel = channelService.getChannel(channelA.getId());
+ System.out.println("수정 후 조회된 채널: " + retrievedUpdatedChannel.getName());
+
+ Message messageA = messageService.createMessage(userA.getId(), channelA.getId(), "안녕하세요");
+ System.out.println("메시지 생성: " + messageA.getContent());
+
+ Message retrievedMessage = messageService.getMessage(messageA.getId());
+ System.out.println("조회된 메시지: " + retrievedMessage.getContent());
+
+ List allMessages = messageService.getAllMessages();
+ System.out.println("전체 메시지 수: " + allMessages.size());
+
+ Message updatedMessage = messageService.updateMessage(messageA.getId(), "수정된 메시지입니다");
+ System.out.println("수정된 메시지: " + updatedMessage.getContent());
+
+ Message retrievedUpdatedMessage = messageService.getMessage(messageA.getId());
+ System.out.println("수정 후 조회된 메시지: " + retrievedUpdatedMessage.getContent());
+
+ messageService.deleteMessage(messageA.getId());
+ if (messageService.getMessage(messageA.getId()) == null) {
+ System.out.println("메시지가 성공적으로 삭제되었습니다.");
+ }
+
+ channelService.deleteChannel(channelA.getId());
+ if (channelService.getChannel(channelA.getId()) == null) {
+ System.out.println("채널이 성공적으로 삭제되었습니다.");
+ }
+
+ userService.deleteUser(userA.getId());
+ if (userService.getUser(userA.getId()) == null) {
+ System.out.println("유저가 성공적으로 삭제되었습니다.");
+ }
+ }
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/api/AuthController.java b/src/main/java/com/sprint/mission/discodeit/api/AuthController.java
new file mode 100644
index 0000000000..367604f70a
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/api/AuthController.java
@@ -0,0 +1,23 @@
+package com.sprint.mission.discodeit.api;
+
+import com.sprint.mission.discodeit.dto.request.LoginRequest;
+import com.sprint.mission.discodeit.entity.User;
+import com.sprint.mission.discodeit.service.AuthService;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequestMapping("/api/auth")
+public class AuthController {
+ private final AuthService authService;
+
+ public AuthController(AuthService authService) {
+ this.authService = authService;
+ }
+
+ @RequestMapping(value = "/login", method = RequestMethod.POST)
+ public ResponseEntity login(@RequestBody LoginRequest request) {
+ User user = authService.login(request);
+ return ResponseEntity.ok(user);
+ }
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/api/BinaryContentController.java b/src/main/java/com/sprint/mission/discodeit/api/BinaryContentController.java
new file mode 100644
index 0000000000..7cde90b3ce
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/api/BinaryContentController.java
@@ -0,0 +1,41 @@
+package com.sprint.mission.discodeit.api;
+
+import com.sprint.mission.discodeit.dto.request.BinaryContentCreateRequest;
+import com.sprint.mission.discodeit.entity.BinaryContent;
+import com.sprint.mission.discodeit.service.BinaryContentService;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.UUID;
+
+@RestController
+@RequestMapping("/api/binary-contents")
+public class BinaryContentController {
+ private final BinaryContentService binaryContentService;
+
+ public BinaryContentController(BinaryContentService binaryContentService) {
+ this.binaryContentService = binaryContentService;
+ }
+
+ // POST: 바이너리 파일 업로드
+ @RequestMapping(method = RequestMethod.POST)
+ public ResponseEntity createBinaryContent( BinaryContentCreateRequest request) {
+ BinaryContent binaryContent = binaryContentService.create(request);
+ return ResponseEntity.status(201).body(binaryContent);
+ }
+
+ // GET: 단일 바이너리 파일 조회
+ @RequestMapping(value = "/{binaryContentId}", method = RequestMethod.GET)
+ public ResponseEntity getBinaryContent(@PathVariable UUID binaryContentId) {
+ BinaryContent binaryContent = binaryContentService.find(binaryContentId);
+ return ResponseEntity.ok(binaryContent);
+ }
+
+ // GET: 여러 바이너리 파일 조회
+ @RequestMapping(method = RequestMethod.GET)
+ public ResponseEntity> getBinaryContents(@RequestParam List ids) {
+ List binaryContents = binaryContentService.findAllByIdIn(ids);
+ return ResponseEntity.ok(binaryContents);
+ }
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/api/ChannelController.java b/src/main/java/com/sprint/mission/discodeit/api/ChannelController.java
new file mode 100644
index 0000000000..031d878483
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/api/ChannelController.java
@@ -0,0 +1,54 @@
+package com.sprint.mission.discodeit.api;
+
+import com.sprint.mission.discodeit.dto.data.ChannelDto;
+import com.sprint.mission.discodeit.dto.request.PrivateChannelCreateRequest;
+import com.sprint.mission.discodeit.dto.request.PublicChannelCreateRequest;
+import com.sprint.mission.discodeit.dto.request.PublicChannelUpdateRequest;
+import com.sprint.mission.discodeit.entity.Channel;
+import com.sprint.mission.discodeit.service.ChannelService;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.UUID;
+
+@RestController
+@RequestMapping("/api/channels")
+public class ChannelController {
+ private final ChannelService channelService;
+
+ public ChannelController(ChannelService channelService) {
+ this.channelService = channelService;
+ }
+
+ @RequestMapping(value = "/public", method = RequestMethod.POST)
+ public ResponseEntity createPublicChannel(@RequestBody PublicChannelCreateRequest request) {
+ Channel channel = channelService.create(request);
+ return ResponseEntity.status(HttpStatus.CREATED).body(channel);
+ }
+
+ @RequestMapping(value = "/private", method = RequestMethod.POST)
+ public ResponseEntity createPrivateChannel(@RequestBody PrivateChannelCreateRequest request) {
+ Channel channel = channelService.create(request);
+ return ResponseEntity.status(HttpStatus.CREATED).body(channel);
+ }
+
+ @RequestMapping(value = "/{channelId}", method = RequestMethod.PUT)
+ public ResponseEntity updatePublicChannel(@PathVariable UUID channelId, @RequestBody PublicChannelUpdateRequest request) {
+ Channel updatedChannel = channelService.update(channelId, request);
+ return ResponseEntity.ok(updatedChannel);
+ }
+
+ @RequestMapping(value = "/{channelId}", method = RequestMethod.DELETE)
+ public ResponseEntity deleteChannel(@PathVariable UUID channelId) {
+ channelService.delete(channelId);
+ return ResponseEntity.noContent().build();
+ }
+
+ @RequestMapping(value = "/user/{userId}", method = RequestMethod.GET)
+ public ResponseEntity> getChannelsForUser(@PathVariable UUID userId) {
+ List channels = channelService.findAllByUserId(userId);
+ return ResponseEntity.ok(channels);
+ }
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/api/GlobalExceptionHandler.java b/src/main/java/com/sprint/mission/discodeit/api/GlobalExceptionHandler.java
new file mode 100644
index 0000000000..5f139d9c00
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/api/GlobalExceptionHandler.java
@@ -0,0 +1,27 @@
+package com.sprint.mission.discodeit.api;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+import java.util.NoSuchElementException;
+
+@RestControllerAdvice
+public class GlobalExceptionHandler {
+
+ @ExceptionHandler(NoSuchElementException.class)
+ public ResponseEntity handleNoSuchElementException(NoSuchElementException e) {
+ return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Resource not found: " + e.getMessage());
+ }
+
+ @ExceptionHandler(IllegalArgumentException.class)
+ public ResponseEntity handleIllegalArgumentException(IllegalArgumentException e) {
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Invalid argument: " + e.getMessage());
+ }
+
+ @ExceptionHandler(Exception.class)
+ public ResponseEntity handleGeneralException(Exception e) {
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("An error occurred: " + e.getMessage());
+ }
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/api/MessageController.java b/src/main/java/com/sprint/mission/discodeit/api/MessageController.java
new file mode 100644
index 0000000000..eba3230f5d
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/api/MessageController.java
@@ -0,0 +1,46 @@
+package com.sprint.mission.discodeit.api;
+
+import com.sprint.mission.discodeit.dto.request.MessageCreateRequest;
+import com.sprint.mission.discodeit.dto.request.MessageUpdateRequest;
+import com.sprint.mission.discodeit.entity.Message;
+import com.sprint.mission.discodeit.service.MessageService;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.UUID;
+
+@RestController
+@RequestMapping("/api/messages")
+public class MessageController {
+ private final MessageService messageService;
+
+ public MessageController(MessageService messageService) {
+ this.messageService = messageService;
+ }
+
+ @RequestMapping(method = RequestMethod.POST)
+ public ResponseEntity createMessage(@RequestBody MessageCreateRequest request) {
+ Message message = messageService.create(request, List.of());
+ return ResponseEntity.status(HttpStatus.CREATED).body(message);
+ }
+
+ @RequestMapping(value = "/{messageId}", method = RequestMethod.PUT)
+ public ResponseEntity updateMessage(@PathVariable UUID messageId, @RequestBody MessageUpdateRequest request) {
+ Message updatedMessage = messageService.update(messageId, request);
+ return ResponseEntity.ok(updatedMessage);
+ }
+
+ @RequestMapping(value = "/{messageId}", method = RequestMethod.DELETE)
+ public ResponseEntity deleteMessage(@PathVariable UUID messageId) {
+ messageService.delete(messageId);
+ return ResponseEntity.noContent().build();
+ }
+
+ @RequestMapping(value = "/channel/{channelId}", method = RequestMethod.GET)
+ public ResponseEntity> getMessagesForChannel(@PathVariable UUID channelId) {
+ List messages = messageService.findAllByChannelId(channelId);
+ return ResponseEntity.ok(messages);
+ }
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/api/ReadStatusController.java b/src/main/java/com/sprint/mission/discodeit/api/ReadStatusController.java
new file mode 100644
index 0000000000..2976af8127
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/api/ReadStatusController.java
@@ -0,0 +1,40 @@
+package com.sprint.mission.discodeit.api;
+
+import com.sprint.mission.discodeit.dto.request.ReadStatusCreateRequest;
+import com.sprint.mission.discodeit.dto.request.ReadStatusUpdateRequest;
+import com.sprint.mission.discodeit.entity.ReadStatus;
+import com.sprint.mission.discodeit.service.ReadStatusService;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.UUID;
+
+@RestController
+@RequestMapping("/api/read-status")
+public class ReadStatusController {
+ private final ReadStatusService readStatusService;
+
+ public ReadStatusController(ReadStatusService readStatusService) {
+ this.readStatusService = readStatusService;
+ }
+
+ @RequestMapping(method = RequestMethod.POST)
+ public ResponseEntity createReadStatus(@RequestBody ReadStatusCreateRequest request) {
+ ReadStatus readStatus = readStatusService.create(request);
+ return ResponseEntity.status(HttpStatus.CREATED).body(readStatus);
+ }
+
+ @RequestMapping(value = "/{readStatusId}", method = RequestMethod.PUT)
+ public ResponseEntity updateReadStatus(@PathVariable UUID readStatusId, @RequestBody ReadStatusUpdateRequest request) {
+ ReadStatus updatedReadStatus = readStatusService.update(readStatusId, request);
+ return ResponseEntity.ok(updatedReadStatus);
+ }
+
+ @RequestMapping(value = "/user/{userId}", method = RequestMethod.GET)
+ public ResponseEntity> getReadStatusForUser(@PathVariable UUID userId) {
+ List readStatuses = readStatusService.findAllByUserId(userId);
+ return ResponseEntity.ok(readStatuses);
+ }
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/api/UserController.java b/src/main/java/com/sprint/mission/discodeit/api/UserController.java
new file mode 100644
index 0000000000..01c152717a
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/api/UserController.java
@@ -0,0 +1,59 @@
+package com.sprint.mission.discodeit.api;
+
+import com.sprint.mission.discodeit.dto.data.UserDto;
+import com.sprint.mission.discodeit.dto.request.UserCreateRequest;
+import com.sprint.mission.discodeit.dto.request.UserUpdateRequest;
+import com.sprint.mission.discodeit.dto.request.UserStatusUpdateRequest;
+import com.sprint.mission.discodeit.entity.User;
+import com.sprint.mission.discodeit.entity.UserStatus;
+import com.sprint.mission.discodeit.service.UserService;
+import com.sprint.mission.discodeit.service.UserStatusService;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+
+@RestController
+@RequestMapping("/api/users")
+public class UserController {
+ private final UserService userService;
+ private final UserStatusService userStatusService;
+
+ public UserController(UserService userService, UserStatusService userStatusService) {
+ this.userService = userService;
+ this.userStatusService = userStatusService;
+ }
+
+ @RequestMapping(method = RequestMethod.POST)
+ public ResponseEntity createUser(@RequestBody UserCreateRequest request) {
+ User user = userService.create(request, Optional.empty());
+ return ResponseEntity.status(HttpStatus.CREATED).body(user);
+ }
+
+ @RequestMapping(value = "/{userId}", method = RequestMethod.PUT)
+ public ResponseEntity updateUser(@PathVariable UUID userId, @RequestBody UserUpdateRequest request) {
+ User updatedUser = userService.update(userId, request, Optional.empty());
+ return ResponseEntity.ok(updatedUser);
+ }
+
+ @RequestMapping(value = "/{userId}", method = RequestMethod.DELETE)
+ public ResponseEntity deleteUser(@PathVariable UUID userId) {
+ userService.delete(userId);
+ return ResponseEntity.noContent().build();
+ }
+
+ @RequestMapping(method = RequestMethod.GET)
+ public ResponseEntity> getAllUsers() {
+ List users = userService.findAll();
+ return ResponseEntity.ok(users);
+ }
+
+ @RequestMapping(value = "/{userId}/status", method = RequestMethod.PUT)
+ public ResponseEntity updateUserStatus(@PathVariable UUID userId, @RequestBody UserStatusUpdateRequest request) {
+ UserStatus updatedStatus = userStatusService.updateByUserId(userId, request);
+ return ResponseEntity.ok(updatedStatus);
+ }
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/dto/data/ChannelDto.java b/src/main/java/com/sprint/mission/discodeit/dto/data/ChannelDto.java
new file mode 100644
index 0000000000..2005105e10
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/dto/data/ChannelDto.java
@@ -0,0 +1,17 @@
+package com.sprint.mission.discodeit.dto.data;
+
+import com.sprint.mission.discodeit.entity.ChannelType;
+
+import java.time.Instant;
+import java.util.List;
+import java.util.UUID;
+
+public record ChannelDto(
+ UUID id,
+ ChannelType type,
+ String name,
+ String description,
+ List participantIds,
+ Instant lastMessageAt
+) {
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/dto/data/UserDto.java b/src/main/java/com/sprint/mission/discodeit/dto/data/UserDto.java
new file mode 100644
index 0000000000..46881b9d4d
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/dto/data/UserDto.java
@@ -0,0 +1,15 @@
+package com.sprint.mission.discodeit.dto.data;
+
+import java.time.Instant;
+import java.util.UUID;
+
+public record UserDto(
+ UUID id,
+ Instant createdAt,
+ Instant updatedAt,
+ String username,
+ String email,
+ UUID profileId,
+ Boolean online
+) {
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/dto/request/BinaryContentCreateRequest.java b/src/main/java/com/sprint/mission/discodeit/dto/request/BinaryContentCreateRequest.java
new file mode 100644
index 0000000000..b787a127dd
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/dto/request/BinaryContentCreateRequest.java
@@ -0,0 +1,8 @@
+package com.sprint.mission.discodeit.dto.request;
+
+public record BinaryContentCreateRequest(
+ String fileName,
+ String contentType,
+ byte[] bytes
+) {
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/dto/request/LoginRequest.java b/src/main/java/com/sprint/mission/discodeit/dto/request/LoginRequest.java
new file mode 100644
index 0000000000..2ab978e2af
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/dto/request/LoginRequest.java
@@ -0,0 +1,7 @@
+package com.sprint.mission.discodeit.dto.request;
+
+public record LoginRequest(
+ String username,
+ String password
+) {
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/dto/request/MessageCreateRequest.java b/src/main/java/com/sprint/mission/discodeit/dto/request/MessageCreateRequest.java
new file mode 100644
index 0000000000..dd8c3d24cd
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/dto/request/MessageCreateRequest.java
@@ -0,0 +1,10 @@
+package com.sprint.mission.discodeit.dto.request;
+
+import java.util.UUID;
+
+public record MessageCreateRequest(
+ String content,
+ UUID channelId,
+ UUID authorId
+) {
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/dto/request/MessageUpdateRequest.java b/src/main/java/com/sprint/mission/discodeit/dto/request/MessageUpdateRequest.java
new file mode 100644
index 0000000000..d1830fbb94
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/dto/request/MessageUpdateRequest.java
@@ -0,0 +1,6 @@
+package com.sprint.mission.discodeit.dto.request;
+
+public record MessageUpdateRequest(
+ String newContent
+) {
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/dto/request/PrivateChannelCreateRequest.java b/src/main/java/com/sprint/mission/discodeit/dto/request/PrivateChannelCreateRequest.java
new file mode 100644
index 0000000000..6b203baa7f
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/dto/request/PrivateChannelCreateRequest.java
@@ -0,0 +1,9 @@
+package com.sprint.mission.discodeit.dto.request;
+
+import java.util.List;
+import java.util.UUID;
+
+public record PrivateChannelCreateRequest(
+ List participantIds
+) {
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/dto/request/PublicChannelCreateRequest.java b/src/main/java/com/sprint/mission/discodeit/dto/request/PublicChannelCreateRequest.java
new file mode 100644
index 0000000000..c5b15cc330
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/dto/request/PublicChannelCreateRequest.java
@@ -0,0 +1,7 @@
+package com.sprint.mission.discodeit.dto.request;
+
+public record PublicChannelCreateRequest(
+ String name,
+ String description
+) {
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/dto/request/PublicChannelUpdateRequest.java b/src/main/java/com/sprint/mission/discodeit/dto/request/PublicChannelUpdateRequest.java
new file mode 100644
index 0000000000..6c02341628
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/dto/request/PublicChannelUpdateRequest.java
@@ -0,0 +1,7 @@
+package com.sprint.mission.discodeit.dto.request;
+
+public record PublicChannelUpdateRequest(
+ String newName,
+ String newDescription
+) {
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/dto/request/ReadStatusCreateRequest.java b/src/main/java/com/sprint/mission/discodeit/dto/request/ReadStatusCreateRequest.java
new file mode 100644
index 0000000000..f2d520af97
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/dto/request/ReadStatusCreateRequest.java
@@ -0,0 +1,11 @@
+package com.sprint.mission.discodeit.dto.request;
+
+import java.time.Instant;
+import java.util.UUID;
+
+public record ReadStatusCreateRequest(
+ UUID userId,
+ UUID channelId,
+ Instant lastReadAt
+) {
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/dto/request/ReadStatusUpdateRequest.java b/src/main/java/com/sprint/mission/discodeit/dto/request/ReadStatusUpdateRequest.java
new file mode 100644
index 0000000000..3921ffc754
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/dto/request/ReadStatusUpdateRequest.java
@@ -0,0 +1,8 @@
+package com.sprint.mission.discodeit.dto.request;
+
+import java.time.Instant;
+
+public record ReadStatusUpdateRequest(
+ Instant newLastReadAt
+) {
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/dto/request/UserCreateRequest.java b/src/main/java/com/sprint/mission/discodeit/dto/request/UserCreateRequest.java
new file mode 100644
index 0000000000..e1daa625b0
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/dto/request/UserCreateRequest.java
@@ -0,0 +1,8 @@
+package com.sprint.mission.discodeit.dto.request;
+
+public record UserCreateRequest(
+ String username,
+ String email,
+ String password
+) {
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/dto/request/UserStatusCreateRequest.java b/src/main/java/com/sprint/mission/discodeit/dto/request/UserStatusCreateRequest.java
new file mode 100644
index 0000000000..272a0d4c7b
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/dto/request/UserStatusCreateRequest.java
@@ -0,0 +1,10 @@
+package com.sprint.mission.discodeit.dto.request;
+
+import java.time.Instant;
+import java.util.UUID;
+
+public record UserStatusCreateRequest(
+ UUID userId,
+ Instant lastActiveAt
+) {
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/dto/request/UserStatusUpdateRequest.java b/src/main/java/com/sprint/mission/discodeit/dto/request/UserStatusUpdateRequest.java
new file mode 100644
index 0000000000..9a001937a6
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/dto/request/UserStatusUpdateRequest.java
@@ -0,0 +1,8 @@
+package com.sprint.mission.discodeit.dto.request;
+
+import java.time.Instant;
+
+public record UserStatusUpdateRequest(
+ Instant newLastActiveAt
+) {
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/dto/request/UserUpdateRequest.java b/src/main/java/com/sprint/mission/discodeit/dto/request/UserUpdateRequest.java
new file mode 100644
index 0000000000..d1da4c7a3b
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/dto/request/UserUpdateRequest.java
@@ -0,0 +1,8 @@
+package com.sprint.mission.discodeit.dto.request;
+
+public record UserUpdateRequest(
+ String newUsername,
+ String newEmail,
+ String newPassword
+) {
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/dto/response/ResponseBinaryContentDto.java b/src/main/java/com/sprint/mission/discodeit/dto/response/ResponseBinaryContentDto.java
new file mode 100644
index 0000000000..314d811b66
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/dto/response/ResponseBinaryContentDto.java
@@ -0,0 +1,11 @@
+package com.sprint.mission.discodeit.dto.response;
+
+import java.util.UUID;
+
+public record ResponseBinaryContentDto(
+ UUID id,
+ String fileName,
+ String contentType,
+ long size
+) {
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/entity/AbstractEntity.java b/src/main/java/com/sprint/mission/discodeit/entity/AbstractEntity.java
new file mode 100644
index 0000000000..5d12e4aef2
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/entity/AbstractEntity.java
@@ -0,0 +1,27 @@
+package com.sprint.mission.discodeit.entity;
+import java.util.UUID;
+
+public abstract class AbstractEntity {
+ protected final UUID id;
+ protected final Long createAt;
+ protected Long updateAt;
+
+ public AbstractEntity() {
+ this.id = UUID.randomUUID();
+ this.createAt = System.currentTimeMillis();
+ this.updateAt = this.createAt;
+ }
+ public UUID getId() {
+ return id;
+ }
+ public Long getCreateAt() {
+ return createAt;
+ }
+ public Long getUpdateAt() {
+ return updateAt;
+ }
+ protected void updateTimestamp(){
+ this.updateAt = System.currentTimeMillis();
+ }
+
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/entity/BinaryContent.java b/src/main/java/com/sprint/mission/discodeit/entity/BinaryContent.java
new file mode 100644
index 0000000000..3af46c7d17
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/entity/BinaryContent.java
@@ -0,0 +1,29 @@
+package com.sprint.mission.discodeit.entity;
+
+import lombok.Getter;
+
+import java.io.Serializable;
+import java.time.Instant;
+import java.util.UUID;
+
+@Getter
+public class BinaryContent implements Serializable {
+ private static final long serialVersionUID = 1L;
+ private UUID id;
+ private Instant createdAt;
+ //
+ private String fileName;
+ private Long size;
+ private String contentType;
+ private byte[] bytes;
+
+ public BinaryContent(String fileName, Long size, String contentType, byte[] bytes) {
+ this.id = UUID.randomUUID();
+ this.createdAt = Instant.now();
+ //
+ this.fileName = fileName;
+ this.size = size;
+ this.contentType = contentType;
+ this.bytes = bytes;
+ }
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/entity/Channel.java b/src/main/java/com/sprint/mission/discodeit/entity/Channel.java
new file mode 100644
index 0000000000..fd7096d5b7
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/entity/Channel.java
@@ -0,0 +1,27 @@
+package com.sprint.mission.discodeit.entity;
+
+import lombok.Getter;
+
+public class Channel extends AbstractEntity {
+ private String name;
+ private String description;
+
+ public Channel(String name, String description) {
+ super();
+ this.name = name;
+ this.description = description;
+ }
+ public String getName() {
+ return name;
+ }
+ public String getDescription() {
+ return description;
+ }
+
+ public void update(String name, String description){
+ this.name = name;
+ this.description = description;
+ updateTimestamp();
+ }
+}
+
diff --git a/src/main/java/com/sprint/mission/discodeit/entity/ChannelType.java b/src/main/java/com/sprint/mission/discodeit/entity/ChannelType.java
new file mode 100644
index 0000000000..9a2ff3f0fd
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/entity/ChannelType.java
@@ -0,0 +1,6 @@
+package com.sprint.mission.discodeit.entity;
+
+public enum ChannelType {
+ PUBLIC,
+ PRIVATE,
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/entity/Message.java b/src/main/java/com/sprint/mission/discodeit/entity/Message.java
new file mode 100644
index 0000000000..870f90b5f9
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/entity/Message.java
@@ -0,0 +1,45 @@
+package com.sprint.mission.discodeit.entity;
+
+import lombok.Getter;
+
+import java.io.Serializable;
+import java.time.Instant;
+import java.util.List;
+import java.util.UUID;
+
+@Getter
+public class Message implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private UUID id;
+ private Instant createdAt;
+ private Instant updatedAt;
+ //
+ private String content;
+ //
+ private UUID channelId;
+ private UUID authorId;
+ private List attachmentIds;
+
+ public Message(String content, UUID channelId, UUID authorId, List attachmentIds) {
+ this.id = UUID.randomUUID();
+ this.createdAt = Instant.now();
+ //
+ this.content = content;
+ this.channelId = channelId;
+ this.authorId = authorId;
+ this.attachmentIds = attachmentIds;
+ }
+
+ public void update(String newContent) {
+ boolean anyValueUpdated = false;
+ if (newContent != null && !newContent.equals(this.content)) {
+ this.content = newContent;
+ anyValueUpdated = true;
+ }
+
+ if (anyValueUpdated) {
+ this.updatedAt = Instant.now();
+ }
+ }
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/entity/ReadStatus.java b/src/main/java/com/sprint/mission/discodeit/entity/ReadStatus.java
new file mode 100644
index 0000000000..79db72e4e2
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/entity/ReadStatus.java
@@ -0,0 +1,40 @@
+package com.sprint.mission.discodeit.entity;
+
+import lombok.Getter;
+
+import java.io.Serializable;
+import java.time.Instant;
+import java.util.UUID;
+
+@Getter
+public class ReadStatus implements Serializable {
+ private static final long serialVersionUID = 1L;
+ private UUID id;
+ private Instant createdAt;
+ private Instant updatedAt;
+ //
+ private UUID userId;
+ private UUID channelId;
+ private Instant lastReadAt;
+
+ public ReadStatus(UUID userId, UUID channelId, Instant lastReadAt) {
+ this.id = UUID.randomUUID();
+ this.createdAt = Instant.now();
+ //
+ this.userId = userId;
+ this.channelId = channelId;
+ this.lastReadAt = lastReadAt;
+ }
+
+ public void update(Instant newLastReadAt) {
+ boolean anyValueUpdated = false;
+ if (newLastReadAt != null && !newLastReadAt.equals(this.lastReadAt)) {
+ this.lastReadAt = newLastReadAt;
+ anyValueUpdated = true;
+ }
+
+ if (anyValueUpdated) {
+ this.updatedAt = Instant.now();
+ }
+ }
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/entity/User.java b/src/main/java/com/sprint/mission/discodeit/entity/User.java
new file mode 100644
index 0000000000..089ac73025
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/entity/User.java
@@ -0,0 +1,55 @@
+package com.sprint.mission.discodeit.entity;
+
+import lombok.Getter;
+
+import java.io.Serializable;
+import java.time.Instant;
+import java.util.UUID;
+
+@Getter
+public class User implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private UUID id;
+ private Instant createdAt;
+ private Instant updatedAt;
+ //
+ private String username;
+ private String email;
+ private String password;
+ private UUID profileId; // BinaryContent
+
+ public User(String username, String email, String password, UUID profileId) {
+ this.id = UUID.randomUUID();
+ this.createdAt = Instant.now();
+ //
+ this.username = username;
+ this.email = email;
+ this.password = password;
+ this.profileId = profileId;
+ }
+
+ public void update(String newUsername, String newEmail, String newPassword, UUID newProfileId) {
+ boolean anyValueUpdated = false;
+ if (newUsername != null && !newUsername.equals(this.username)) {
+ this.username = newUsername;
+ anyValueUpdated = true;
+ }
+ if (newEmail != null && !newEmail.equals(this.email)) {
+ this.email = newEmail;
+ anyValueUpdated = true;
+ }
+ if (newPassword != null && !newPassword.equals(this.password)) {
+ this.password = newPassword;
+ anyValueUpdated = true;
+ }
+ if (newProfileId != null && !newProfileId.equals(this.profileId)) {
+ this.profileId = newProfileId;
+ anyValueUpdated = true;
+ }
+
+ if (anyValueUpdated) {
+ this.updatedAt = Instant.now();
+ }
+ }
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/entity/UserStatus.java b/src/main/java/com/sprint/mission/discodeit/entity/UserStatus.java
new file mode 100644
index 0000000000..53c7865a2e
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/entity/UserStatus.java
@@ -0,0 +1,45 @@
+package com.sprint.mission.discodeit.entity;
+
+import lombok.Getter;
+
+import java.io.Serializable;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.UUID;
+
+@Getter
+public class UserStatus implements Serializable {
+ private static final long serialVersionUID = 1L;
+ private UUID id;
+ private Instant createdAt;
+ private Instant updatedAt;
+ //
+ private UUID userId;
+ private Instant lastActiveAt;
+
+ public UserStatus(UUID userId, Instant lastActiveAt) {
+ this.id = UUID.randomUUID();
+ this.createdAt = Instant.now();
+ //
+ this.userId = userId;
+ this.lastActiveAt = lastActiveAt;
+ }
+
+ public void update(Instant lastActiveAt) {
+ boolean anyValueUpdated = false;
+ if (lastActiveAt != null && !lastActiveAt.equals(this.lastActiveAt)) {
+ this.lastActiveAt = lastActiveAt;
+ anyValueUpdated = true;
+ }
+
+ if (anyValueUpdated) {
+ this.updatedAt = Instant.now();
+ }
+ }
+
+ public Boolean isOnline() {
+ Instant instantFiveMinutesAgo = Instant.now().minus(Duration.ofMinutes(5));
+
+ return lastActiveAt.isAfter(instantFiveMinutesAgo);
+ }
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/repository/BinaryContentRepository.java b/src/main/java/com/sprint/mission/discodeit/repository/BinaryContentRepository.java
new file mode 100644
index 0000000000..15e0098747
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/repository/BinaryContentRepository.java
@@ -0,0 +1,15 @@
+package com.sprint.mission.discodeit.repository;
+
+import com.sprint.mission.discodeit.entity.BinaryContent;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+
+public interface BinaryContentRepository {
+ BinaryContent save(BinaryContent binaryContent);
+ Optional findById(UUID id);
+ List findAllByIdIn(List ids);
+ boolean existsById(UUID id);
+ void deleteById(UUID id);
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/repository/ChannelRepository.java b/src/main/java/com/sprint/mission/discodeit/repository/ChannelRepository.java
new file mode 100644
index 0000000000..326a84f4ba
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/repository/ChannelRepository.java
@@ -0,0 +1,15 @@
+package com.sprint.mission.discodeit.repository;
+
+import com.sprint.mission.discodeit.entity.Channel;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+
+public interface ChannelRepository {
+ Channel save(Channel channel);
+ Optional findById(UUID id);
+ List findAll();
+ boolean existsById(UUID id);
+ void deleteById(UUID id);
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/repository/MessageRepository.java b/src/main/java/com/sprint/mission/discodeit/repository/MessageRepository.java
new file mode 100644
index 0000000000..69547b2226
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/repository/MessageRepository.java
@@ -0,0 +1,16 @@
+package com.sprint.mission.discodeit.repository;
+
+import com.sprint.mission.discodeit.entity.Message;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+
+public interface MessageRepository {
+ Message save(Message message);
+ Optional findById(UUID id);
+ List findAllByChannelId(UUID channelId);
+ boolean existsById(UUID id);
+ void deleteById(UUID id);
+ void deleteAllByChannelId(UUID channelId);
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/repository/ReadStatusRepository.java b/src/main/java/com/sprint/mission/discodeit/repository/ReadStatusRepository.java
new file mode 100644
index 0000000000..e0ef9c69b7
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/repository/ReadStatusRepository.java
@@ -0,0 +1,17 @@
+package com.sprint.mission.discodeit.repository;
+
+import com.sprint.mission.discodeit.entity.ReadStatus;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+
+public interface ReadStatusRepository {
+ ReadStatus save(ReadStatus readStatus);
+ Optional findById(UUID id);
+ List findAllByUserId(UUID userId);
+ List findAllByChannelId(UUID channelId);
+ boolean existsById(UUID id);
+ void deleteById(UUID id);
+ void deleteAllByChannelId(UUID channelId);
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/repository/UserRepository.java b/src/main/java/com/sprint/mission/discodeit/repository/UserRepository.java
new file mode 100644
index 0000000000..75c52fa8af
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/repository/UserRepository.java
@@ -0,0 +1,18 @@
+package com.sprint.mission.discodeit.repository;
+
+import com.sprint.mission.discodeit.entity.User;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+
+public interface UserRepository {
+ User save(User user);
+ Optional findById(UUID id);
+ Optional findByUsername(String username);
+ List findAll();
+ boolean existsById(UUID id);
+ void deleteById(UUID id);
+ boolean existsByEmail(String email);
+ boolean existsByUsername(String username);
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/repository/UserStatusRepository.java b/src/main/java/com/sprint/mission/discodeit/repository/UserStatusRepository.java
new file mode 100644
index 0000000000..6651bd2011
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/repository/UserStatusRepository.java
@@ -0,0 +1,17 @@
+package com.sprint.mission.discodeit.repository;
+
+import com.sprint.mission.discodeit.entity.UserStatus;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+
+public interface UserStatusRepository {
+ UserStatus save(UserStatus userStatus);
+ Optional findById(UUID id);
+ Optional findByUserId(UUID userId);
+ List findAll();
+ boolean existsById(UUID id);
+ void deleteById(UUID id);
+ void deleteByUserId(UUID userId);
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/repository/file/FileBinaryContentRepository.java b/src/main/java/com/sprint/mission/discodeit/repository/file/FileBinaryContentRepository.java
new file mode 100644
index 0000000000..42a5861f34
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/repository/file/FileBinaryContentRepository.java
@@ -0,0 +1,109 @@
+package com.sprint.mission.discodeit.repository.file;
+
+import com.sprint.mission.discodeit.entity.BinaryContent;
+import com.sprint.mission.discodeit.repository.BinaryContentRepository;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.stereotype.Repository;
+
+import java.io.*;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+import java.util.stream.Stream;
+
+@ConditionalOnProperty(name = "discodeit.repository.type", havingValue = "file")
+@Repository
+public class FileBinaryContentRepository implements BinaryContentRepository {
+ private final Path DIRECTORY;
+ private final String EXTENSION = ".ser";
+
+ public FileBinaryContentRepository(
+ @Value("${discodeit.repository.file-directory:data}") String fileDirectory
+ ) {
+ this.DIRECTORY = Paths.get(System.getProperty("user.dir"), fileDirectory, BinaryContent.class.getSimpleName());
+ if (Files.notExists(DIRECTORY)) {
+ try {
+ Files.createDirectories(DIRECTORY);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ private Path resolvePath(UUID id) {
+ return DIRECTORY.resolve(id + EXTENSION);
+ }
+
+ @Override
+ public BinaryContent save(BinaryContent binaryContent) {
+ Path path = resolvePath(binaryContent.getId());
+ try (
+ FileOutputStream fos = new FileOutputStream(path.toFile());
+ ObjectOutputStream oos = new ObjectOutputStream(fos)
+ ) {
+ oos.writeObject(binaryContent);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ return binaryContent;
+ }
+
+ @Override
+ public Optional findById(UUID id) {
+ BinaryContent binaryContentNullable = null;
+ Path path = resolvePath(id);
+ if (Files.exists(path)) {
+ try (
+ FileInputStream fis = new FileInputStream(path.toFile());
+ ObjectInputStream ois = new ObjectInputStream(fis)
+ ) {
+ binaryContentNullable = (BinaryContent) ois.readObject();
+ } catch (IOException | ClassNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return Optional.ofNullable(binaryContentNullable);
+ }
+
+ @Override
+ public List findAllByIdIn(List ids) {
+ try (Stream paths = Files.list(DIRECTORY)) {
+ return paths
+ .filter(path -> path.toString().endsWith(EXTENSION))
+ .map(path -> {
+ try (
+ FileInputStream fis = new FileInputStream(path.toFile());
+ ObjectInputStream ois = new ObjectInputStream(fis)
+ ) {
+ return (BinaryContent) ois.readObject();
+ } catch (IOException | ClassNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ })
+ .filter(content -> ids.contains(content.getId()))
+ .toList();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public boolean existsById(UUID id) {
+ Path path = resolvePath(id);
+ return Files.exists(path);
+ }
+
+ @Override
+ public void deleteById(UUID id) {
+ Path path = resolvePath(id);
+ try {
+ Files.delete(path);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/repository/file/FileChannelRepository.java b/src/main/java/com/sprint/mission/discodeit/repository/file/FileChannelRepository.java
new file mode 100644
index 0000000000..80ea52c62a
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/repository/file/FileChannelRepository.java
@@ -0,0 +1,60 @@
+package com.sprint.mission.discodeit.repository.file;
+
+import com.sprint.mission.discodeit.entity.Channel;
+import com.sprint.mission.discodeit.repository.ChannelRepository;
+import org.springframework.stereotype.Repository;
+
+import java.io.*;
+import java.util.*;
+
+@Repository
+public class FileChannelRepository implements ChannelRepository {
+ private final String filePath = "channels.ser";
+ private Map data;
+
+
+ public FileChannelRepository() {
+ this.data = loadFromFile();
+ }
+
+ @Override
+ public void save(Channel channel) {
+ data.put(channel.getId(), channel);
+ saveToFile();
+ }
+
+ @Override
+ public Channel findById(UUID id) {
+ return data.get(id);
+ }
+
+ @Override
+ public List findAll() {
+ return new ArrayList<>(data.values());
+ }
+
+ @Override
+ public void delete(UUID id) {
+ data.remove(id);
+ saveToFile();
+ }
+
+ private void saveToFile() {
+ try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath))) {
+ oos.writeObject(data);
+ } catch (IOException e) {
+ throw new RuntimeException("채널을 저장하는데 실패하였습니다.", e);
+ }
+ }
+
+ private Map loadFromFile() {
+ try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filePath))) {
+ return (Map) ois.readObject();
+ } catch (FileNotFoundException e) {
+ return new HashMap<>();
+ } catch (IOException | ClassNotFoundException e) {
+ throw new RuntimeException("채널을 불러오는데 실패하였습니다", e);
+ }
+ }
+}
+
diff --git a/src/main/java/com/sprint/mission/discodeit/repository/file/FileMessageRepository.java b/src/main/java/com/sprint/mission/discodeit/repository/file/FileMessageRepository.java
new file mode 100644
index 0000000000..b96af20b26
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/repository/file/FileMessageRepository.java
@@ -0,0 +1,59 @@
+package com.sprint.mission.discodeit.repository.file;
+
+import com.sprint.mission.discodeit.entity.Message;
+import com.sprint.mission.discodeit.repository.MessageRepository;
+import org.springframework.stereotype.Repository;
+
+import java.io.*;
+import java.util.*;
+
+@Repository
+public class FileMessageRepository implements MessageRepository {
+ private final String filePath = "messages.ser";
+ private Map data;
+
+
+ public FileMessageRepository() {
+ this.data = loadFromFile();
+ }
+
+ @Override
+ public void save(Message message) {
+ data.put(message.getId(), message);
+ saveToFile();
+ }
+
+ @Override
+ public Message findById(UUID id) {
+ return data.get(id);
+ }
+
+ @Override
+ public List findAll() {
+ return new ArrayList<>(data.values());
+ }
+
+ @Override
+ public void delete(UUID id) {
+ data.remove(id);
+ saveToFile();
+ }
+
+ private void saveToFile() {
+ try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath))) {
+ oos.writeObject(data);
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to save messages", e);
+ }
+ }
+
+ private Map loadFromFile() {
+ try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filePath))) {
+ return (Map) ois.readObject();
+ } catch (FileNotFoundException e) {
+ return new HashMap<>();
+ } catch (IOException | ClassNotFoundException e) {
+ throw new RuntimeException("채널을 불러오는데 실패하였습니다", e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/sprint/mission/discodeit/repository/file/FileReadStatusRepository.java b/src/main/java/com/sprint/mission/discodeit/repository/file/FileReadStatusRepository.java
new file mode 100644
index 0000000000..6a0e8fba9c
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/repository/file/FileReadStatusRepository.java
@@ -0,0 +1,137 @@
+package com.sprint.mission.discodeit.repository.file;
+
+import com.sprint.mission.discodeit.entity.ReadStatus;
+import com.sprint.mission.discodeit.repository.ReadStatusRepository;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.stereotype.Repository;
+
+import java.io.*;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+import java.util.stream.Stream;
+
+@ConditionalOnProperty(name = "discodeit.repository.type", havingValue = "file")
+@Repository
+public class FileReadStatusRepository implements ReadStatusRepository {
+ private final Path DIRECTORY;
+ private final String EXTENSION = ".ser";
+
+ public FileReadStatusRepository(
+ @Value("${discodeit.repository.file-directory:data}") String fileDirectory
+ ) {
+ this.DIRECTORY = Paths.get(System.getProperty("user.dir"), fileDirectory, ReadStatus.class.getSimpleName());
+ if (Files.notExists(DIRECTORY)) {
+ try {
+ Files.createDirectories(DIRECTORY);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ private Path resolvePath(UUID id) {
+ return DIRECTORY.resolve(id + EXTENSION);
+ }
+
+ @Override
+ public ReadStatus save(ReadStatus readStatus) {
+ Path path = resolvePath(readStatus.getId());
+ try (
+ FileOutputStream fos = new FileOutputStream(path.toFile());
+ ObjectOutputStream oos = new ObjectOutputStream(fos)
+ ) {
+ oos.writeObject(readStatus);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ return readStatus;
+ }
+
+ @Override
+ public Optional findById(UUID id) {
+ ReadStatus readStatusNullable = null;
+ Path path = resolvePath(id);
+ if (Files.exists(path)) {
+ try (
+ FileInputStream fis = new FileInputStream(path.toFile());
+ ObjectInputStream ois = new ObjectInputStream(fis)
+ ) {
+ readStatusNullable = (ReadStatus) ois.readObject();
+ } catch (IOException | ClassNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return Optional.ofNullable(readStatusNullable);
+ }
+
+ @Override
+ public List findAllByUserId(UUID userId) {
+ try (Stream paths = Files.list(DIRECTORY)) {
+ return paths
+ .filter(path -> path.toString().endsWith(EXTENSION))
+ .map(path -> {
+ try (
+ FileInputStream fis = new FileInputStream(path.toFile());
+ ObjectInputStream ois = new ObjectInputStream(fis)
+ ) {
+ return (ReadStatus) ois.readObject();
+ } catch (IOException | ClassNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ })
+ .filter(readStatus -> readStatus.getUserId().equals(userId))
+ .toList();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public List findAllByChannelId(UUID channelId) {
+ try (Stream paths = Files.list(DIRECTORY)) {
+ return paths
+ .filter(path -> path.toString().endsWith(EXTENSION))
+ .map(path -> {
+ try (
+ FileInputStream fis = new FileInputStream(path.toFile());
+ ObjectInputStream ois = new ObjectInputStream(fis)
+ ) {
+ return (ReadStatus) ois.readObject();
+ } catch (IOException | ClassNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ })
+ .filter(readStatus -> readStatus.getChannelId().equals(channelId))
+ .toList();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public boolean existsById(UUID id) {
+ Path path = resolvePath(id);
+ return Files.exists(path);
+ }
+
+ @Override
+ public void deleteById(UUID id) {
+ Path path = resolvePath(id);
+ try {
+ Files.delete(path);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void deleteAllByChannelId(UUID channelId) {
+ this.findAllByChannelId(channelId)
+ .forEach(readStatus -> this.deleteById(readStatus.getId()));
+ }
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/repository/file/FileUserRepository.java b/src/main/java/com/sprint/mission/discodeit/repository/file/FileUserRepository.java
new file mode 100644
index 0000000000..08d2a417b1
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/repository/file/FileUserRepository.java
@@ -0,0 +1,59 @@
+package com.sprint.mission.discodeit.repository.file;
+
+import com.sprint.mission.discodeit.entity.User;
+import com.sprint.mission.discodeit.repository.UserRepository;
+import org.springframework.stereotype.Repository;
+
+import java.io.*;
+import java.util.*;
+@Repository
+public class FileUserRepository implements UserRepository {
+ private final String filePath = "users.ser";
+ private Map data;
+
+
+ public FileUserRepository() {
+ this.data = loadFromFile();
+ }
+
+ @Override
+ public void save(User user) {
+ data.put(user.getId(), user);
+ saveToFile();
+ }
+
+ @Override
+ public User findById(UUID id) {
+ return data.get(id);
+ }
+
+ @Override
+ public List findAll() {
+ return new ArrayList<>(data.values());
+ }
+
+ @Override
+ public void delete(UUID id) {
+ data.remove(id);
+ saveToFile();
+ }
+
+ private void saveToFile() {
+ try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath))) {
+ oos.writeObject(data);
+ } catch (IOException e) {
+ throw new RuntimeException("유저를 저장하는데 실패하였습니다.", e);
+ }
+ }
+
+ private Map loadFromFile() {
+ try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filePath))) {
+ return (Map) ois.readObject();
+ } catch (FileNotFoundException e) {
+ return new HashMap<>();
+ } catch (IOException | ClassNotFoundException e) {
+ throw new RuntimeException("유저를 불러오는데 실패하였습니다", e);
+ }
+ }
+}
+
diff --git a/src/main/java/com/sprint/mission/discodeit/repository/file/FileUserStatusRepository.java b/src/main/java/com/sprint/mission/discodeit/repository/file/FileUserStatusRepository.java
new file mode 100644
index 0000000000..732538dbdb
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/repository/file/FileUserStatusRepository.java
@@ -0,0 +1,121 @@
+package com.sprint.mission.discodeit.repository.file;
+
+import com.sprint.mission.discodeit.entity.UserStatus;
+import com.sprint.mission.discodeit.repository.UserStatusRepository;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.stereotype.Repository;
+
+import java.io.*;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+import java.util.stream.Stream;
+
+@ConditionalOnProperty(name = "discodeit.repository.type", havingValue = "file")
+@Repository
+public class FileUserStatusRepository implements UserStatusRepository {
+ private final Path DIRECTORY;
+ private final String EXTENSION = ".ser";
+
+ public FileUserStatusRepository(
+ @Value("${discodeit.repository.file-directory:data}") String fileDirectory
+ ) {
+ this.DIRECTORY = Paths.get(System.getProperty("user.dir"), fileDirectory, UserStatus.class.getSimpleName());
+ if (Files.notExists(DIRECTORY)) {
+ try {
+ Files.createDirectories(DIRECTORY);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ private Path resolvePath(UUID id) {
+ return DIRECTORY.resolve(id + EXTENSION);
+ }
+
+ @Override
+ public UserStatus save(UserStatus userStatus) {
+ Path path = resolvePath(userStatus.getId());
+ try (
+ FileOutputStream fos = new FileOutputStream(path.toFile());
+ ObjectOutputStream oos = new ObjectOutputStream(fos)
+ ) {
+ oos.writeObject(userStatus);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ return userStatus;
+ }
+
+ @Override
+ public Optional findById(UUID id) {
+ UserStatus userStatusNullable = null;
+ Path path = resolvePath(id);
+ if (Files.exists(path)) {
+ try (
+ FileInputStream fis = new FileInputStream(path.toFile());
+ ObjectInputStream ois = new ObjectInputStream(fis)
+ ) {
+ userStatusNullable = (UserStatus) ois.readObject();
+ } catch (IOException | ClassNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return Optional.ofNullable(userStatusNullable);
+ }
+
+ @Override
+ public Optional findByUserId(UUID userId) {
+ return findAll().stream()
+ .filter(userStatus -> userStatus.getUserId().equals(userId))
+ .findFirst();
+ }
+
+ @Override
+ public List findAll() {
+ try (Stream paths = Files.list(DIRECTORY)) {
+ return paths
+ .filter(path -> path.toString().endsWith(EXTENSION))
+ .map(path -> {
+ try (
+ FileInputStream fis = new FileInputStream(path.toFile());
+ ObjectInputStream ois = new ObjectInputStream(fis)
+ ) {
+ return (UserStatus) ois.readObject();
+ } catch (IOException | ClassNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ })
+ .toList();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public boolean existsById(UUID id) {
+ Path path = resolvePath(id);
+ return Files.exists(path);
+ }
+
+ @Override
+ public void deleteById(UUID id) {
+ Path path = resolvePath(id);
+ try {
+ Files.delete(path);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void deleteByUserId(UUID userId) {
+ this.findByUserId(userId)
+ .ifPresent(userStatus -> this.deleteById(userStatus.getId()));
+ }
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/repository/jcf/JCFBinaryContentRepository.java b/src/main/java/com/sprint/mission/discodeit/repository/jcf/JCFBinaryContentRepository.java
new file mode 100644
index 0000000000..48f55a3ff5
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/repository/jcf/JCFBinaryContentRepository.java
@@ -0,0 +1,46 @@
+package com.sprint.mission.discodeit.repository.jcf;
+
+import com.sprint.mission.discodeit.entity.BinaryContent;
+import com.sprint.mission.discodeit.repository.BinaryContentRepository;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.stereotype.Repository;
+
+import java.util.*;
+
+@ConditionalOnProperty(name = "discodeit.repository.type", havingValue = "jcf", matchIfMissing = true)
+@Repository
+public class JCFBinaryContentRepository implements BinaryContentRepository {
+ private final Map data;
+
+ public JCFBinaryContentRepository() {
+ this.data = new HashMap<>();
+ }
+
+ @Override
+ public BinaryContent save(BinaryContent binaryContent) {
+ this.data.put(binaryContent.getId(), binaryContent);
+ return binaryContent;
+ }
+
+ @Override
+ public Optional findById(UUID id) {
+ return Optional.ofNullable(this.data.get(id));
+ }
+
+ @Override
+ public List findAllByIdIn(List ids) {
+ return this.data.values().stream()
+ .filter(content -> ids.contains(content.getId()))
+ .toList();
+ }
+
+ @Override
+ public boolean existsById(UUID id) {
+ return this.data.containsKey(id);
+ }
+
+ @Override
+ public void deleteById(UUID id) {
+ this.data.remove(id);
+ }
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/repository/jcf/JCFChannelRepository.java b/src/main/java/com/sprint/mission/discodeit/repository/jcf/JCFChannelRepository.java
new file mode 100644
index 0000000000..5e4ec92829
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/repository/jcf/JCFChannelRepository.java
@@ -0,0 +1,44 @@
+package com.sprint.mission.discodeit.repository.jcf;
+
+import com.sprint.mission.discodeit.entity.Channel;
+import com.sprint.mission.discodeit.repository.ChannelRepository;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.stereotype.Repository;
+
+import java.util.*;
+
+@ConditionalOnProperty(name = "discodeit.repository.type", havingValue = "jcf", matchIfMissing = true)
+@Repository
+public class JCFChannelRepository implements ChannelRepository {
+ private final Map data;
+
+ public JCFChannelRepository() {
+ this.data = new HashMap<>();
+ }
+
+ @Override
+ public Channel save(Channel channel) {
+ this.data.put(channel.getId(), channel);
+ return channel;
+ }
+
+ @Override
+ public Optional findById(UUID id) {
+ return Optional.ofNullable(this.data.get(id));
+ }
+
+ @Override
+ public List findAll() {
+ return this.data.values().stream().toList();
+ }
+
+ @Override
+ public boolean existsById(UUID id) {
+ return this.data.containsKey(id);
+ }
+
+ @Override
+ public void deleteById(UUID id) {
+ this.data.remove(id);
+ }
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/repository/jcf/JCFMessageRepository.java b/src/main/java/com/sprint/mission/discodeit/repository/jcf/JCFMessageRepository.java
new file mode 100644
index 0000000000..c0039f9624
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/repository/jcf/JCFMessageRepository.java
@@ -0,0 +1,50 @@
+package com.sprint.mission.discodeit.repository.jcf;
+
+import com.sprint.mission.discodeit.entity.Message;
+import com.sprint.mission.discodeit.repository.MessageRepository;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.stereotype.Repository;
+
+import java.util.*;
+
+@ConditionalOnProperty(name = "discodeit.repository.type", havingValue = "jcf", matchIfMissing = true)
+@Repository
+public class JCFMessageRepository implements MessageRepository {
+ private final Map data;
+
+ public JCFMessageRepository() {
+ this.data = new HashMap<>();
+ }
+
+ @Override
+ public Message save(Message message) {
+ this.data.put(message.getId(), message);
+ return message;
+ }
+
+ @Override
+ public Optional findById(UUID id) {
+ return Optional.ofNullable(this.data.get(id));
+ }
+
+ @Override
+ public List findAllByChannelId(UUID channelId) {
+ return this.data.values().stream().filter(message -> message.getChannelId().equals(channelId)).toList();
+ }
+
+ @Override
+ public boolean existsById(UUID id) {
+ return this.data.containsKey(id);
+ }
+
+ @Override
+ public void deleteById(UUID id) {
+ this.data.remove(id);
+ }
+
+ @Override
+ public void deleteAllByChannelId(UUID channelId) {
+ this.findAllByChannelId(channelId)
+ .forEach(message -> this.deleteById(message.getId()));
+ }
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/repository/jcf/JCFReadStatusRepository.java b/src/main/java/com/sprint/mission/discodeit/repository/jcf/JCFReadStatusRepository.java
new file mode 100644
index 0000000000..9c483eeb95
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/repository/jcf/JCFReadStatusRepository.java
@@ -0,0 +1,59 @@
+package com.sprint.mission.discodeit.repository.jcf;
+
+import com.sprint.mission.discodeit.entity.ReadStatus;
+import com.sprint.mission.discodeit.repository.ReadStatusRepository;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.stereotype.Repository;
+
+import java.util.*;
+
+@ConditionalOnProperty(name = "discodeit.repository.type", havingValue = "jcf", matchIfMissing = true)
+@Repository
+public class JCFReadStatusRepository implements ReadStatusRepository {
+ private final Map data;
+
+ public JCFReadStatusRepository() {
+ this.data = new HashMap<>();
+ }
+
+ @Override
+ public ReadStatus save(ReadStatus readStatus) {
+ this.data.put(readStatus.getId(), readStatus);
+ return readStatus;
+ }
+
+ @Override
+ public Optional findById(UUID id) {
+ return Optional.ofNullable(this.data.get(id));
+ }
+
+ @Override
+ public List findAllByUserId(UUID userId) {
+ return this.data.values().stream()
+ .filter(readStatus -> readStatus.getUserId().equals(userId))
+ .toList();
+ }
+
+ @Override
+ public List findAllByChannelId(UUID channelId) {
+ return this.data.values().stream()
+ .filter(readStatus -> readStatus.getChannelId().equals(channelId))
+ .toList();
+ }
+
+ @Override
+ public boolean existsById(UUID id) {
+ return this.data.containsKey(id);
+ }
+
+ @Override
+ public void deleteById(UUID id) {
+ this.data.remove(id);
+ }
+
+ @Override
+ public void deleteAllByChannelId(UUID channelId) {
+ this.findAllByChannelId(channelId)
+ .forEach(readStatus -> this.deleteById(readStatus.getId()));
+ }
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/repository/jcf/JCFUserRepository.java b/src/main/java/com/sprint/mission/discodeit/repository/jcf/JCFUserRepository.java
new file mode 100644
index 0000000000..ec1bc555fb
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/repository/jcf/JCFUserRepository.java
@@ -0,0 +1,61 @@
+package com.sprint.mission.discodeit.repository.jcf;
+
+import com.sprint.mission.discodeit.entity.User;
+import com.sprint.mission.discodeit.repository.UserRepository;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.stereotype.Repository;
+
+import java.util.*;
+
+@ConditionalOnProperty(name = "discodeit.repository.type", havingValue = "jcf", matchIfMissing = true)
+@Repository
+public class JCFUserRepository implements UserRepository {
+ private final Map data;
+
+ public JCFUserRepository() {
+ this.data = new HashMap<>();
+ }
+
+ @Override
+ public User save(User user) {
+ this.data.put(user.getId(), user);
+ return user;
+ }
+
+ @Override
+ public Optional findById(UUID id) {
+ return Optional.ofNullable(this.data.get(id));
+ }
+
+ @Override
+ public Optional findByUsername(String username) {
+ return this.findAll().stream()
+ .filter(user -> user.getUsername().equals(username))
+ .findFirst();
+ }
+
+ @Override
+ public List findAll() {
+ return this.data.values().stream().toList();
+ }
+
+ @Override
+ public boolean existsById(UUID id) {
+ return this.data.containsKey(id);
+ }
+
+ @Override
+ public void deleteById(UUID id) {
+ this.data.remove(id);
+ }
+
+ @Override
+ public boolean existsByEmail(String email) {
+ return this.findAll().stream().anyMatch(user -> user.getEmail().equals(email));
+ }
+
+ @Override
+ public boolean existsByUsername(String username) {
+ return this.findAll().stream().anyMatch(user -> user.getUsername().equals(username));
+ }
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/repository/jcf/JCFUserStatusRepository.java b/src/main/java/com/sprint/mission/discodeit/repository/jcf/JCFUserStatusRepository.java
new file mode 100644
index 0000000000..334cfad758
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/repository/jcf/JCFUserStatusRepository.java
@@ -0,0 +1,57 @@
+package com.sprint.mission.discodeit.repository.jcf;
+
+import com.sprint.mission.discodeit.entity.UserStatus;
+import com.sprint.mission.discodeit.repository.UserStatusRepository;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.stereotype.Repository;
+
+import java.util.*;
+
+@ConditionalOnProperty(name = "discodeit.repository.type", havingValue = "jcf", matchIfMissing = true)
+@Repository
+public class JCFUserStatusRepository implements UserStatusRepository {
+ private final Map data;
+
+ public JCFUserStatusRepository() {
+ this.data = new HashMap<>();
+ }
+
+ @Override
+ public UserStatus save(UserStatus userStatus) {
+ this.data.put(userStatus.getId(), userStatus);
+ return userStatus;
+ }
+
+ @Override
+ public Optional findById(UUID id) {
+ return Optional.ofNullable(this.data.get(id));
+ }
+
+ @Override
+ public Optional findByUserId(UUID userId) {
+ return this.findAll().stream()
+ .filter(userStatus -> userStatus.getUserId().equals(userId))
+ .findFirst();
+ }
+
+ @Override
+ public List findAll() {
+ return this.data.values().stream().toList();
+ }
+
+ @Override
+ public boolean existsById(UUID id) {
+ return this.data.containsKey(id);
+ }
+
+ @Override
+ public void deleteById(UUID id) {
+ this.data.remove(id);
+ }
+
+ @Override
+ public void deleteByUserId(UUID userId) {
+ this.findByUserId(userId)
+ .ifPresent(userStatus -> this.deleteByUserId(userStatus.getId()));
+ }
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/service/AuthService.java b/src/main/java/com/sprint/mission/discodeit/service/AuthService.java
new file mode 100644
index 0000000000..fcc2b1af03
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/service/AuthService.java
@@ -0,0 +1,8 @@
+package com.sprint.mission.discodeit.service;
+
+import com.sprint.mission.discodeit.dto.request.LoginRequest;
+import com.sprint.mission.discodeit.entity.User;
+
+public interface AuthService {
+ User login(LoginRequest loginRequest);
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/service/BinaryContentService.java b/src/main/java/com/sprint/mission/discodeit/service/BinaryContentService.java
new file mode 100644
index 0000000000..77d8358b7b
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/service/BinaryContentService.java
@@ -0,0 +1,14 @@
+package com.sprint.mission.discodeit.service;
+
+import com.sprint.mission.discodeit.dto.request.BinaryContentCreateRequest;
+import com.sprint.mission.discodeit.entity.BinaryContent;
+
+import java.util.List;
+import java.util.UUID;
+
+public interface BinaryContentService {
+ BinaryContent create(BinaryContentCreateRequest request);
+ BinaryContent find(UUID binaryContentId);
+ List findAllByIdIn(List binaryContentIds);
+ void delete(UUID binaryContentId);
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/service/ChannelService.java b/src/main/java/com/sprint/mission/discodeit/service/ChannelService.java
new file mode 100644
index 0000000000..e64bda71fd
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/service/ChannelService.java
@@ -0,0 +1,20 @@
+package com.sprint.mission.discodeit.service;
+
+import com.sprint.mission.discodeit.dto.data.ChannelDto;
+import com.sprint.mission.discodeit.dto.request.PrivateChannelCreateRequest;
+import com.sprint.mission.discodeit.dto.request.PublicChannelCreateRequest;
+import com.sprint.mission.discodeit.dto.request.PublicChannelUpdateRequest;
+import com.sprint.mission.discodeit.entity.Channel;
+import com.sprint.mission.discodeit.entity.ChannelType;
+
+import java.util.List;
+import java.util.UUID;
+
+public interface ChannelService {
+ Channel create(PublicChannelCreateRequest request);
+ Channel create(PrivateChannelCreateRequest request);
+ ChannelDto find(UUID channelId);
+ List findAllByUserId(UUID userId);
+ Channel update(UUID channelId, PublicChannelUpdateRequest request);
+ void delete(UUID channelId);
+}
\ No newline at end of file
diff --git a/src/main/java/com/sprint/mission/discodeit/service/MessageService.java b/src/main/java/com/sprint/mission/discodeit/service/MessageService.java
new file mode 100644
index 0000000000..fa517ef918
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/service/MessageService.java
@@ -0,0 +1,17 @@
+package com.sprint.mission.discodeit.service;
+
+import com.sprint.mission.discodeit.dto.request.BinaryContentCreateRequest;
+import com.sprint.mission.discodeit.dto.request.MessageCreateRequest;
+import com.sprint.mission.discodeit.dto.request.MessageUpdateRequest;
+import com.sprint.mission.discodeit.entity.Message;
+
+import java.util.List;
+import java.util.UUID;
+
+public interface MessageService {
+ Message create(MessageCreateRequest messageCreateRequest, List binaryContentCreateRequests);
+ Message find(UUID messageId);
+ List findAllByChannelId(UUID channelId);
+ Message update(UUID messageId, MessageUpdateRequest request);
+ void delete(UUID messageId);
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/service/ReadStatusService.java b/src/main/java/com/sprint/mission/discodeit/service/ReadStatusService.java
new file mode 100644
index 0000000000..fcbc82f99b
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/service/ReadStatusService.java
@@ -0,0 +1,16 @@
+package com.sprint.mission.discodeit.service;
+
+import com.sprint.mission.discodeit.dto.request.ReadStatusCreateRequest;
+import com.sprint.mission.discodeit.dto.request.ReadStatusUpdateRequest;
+import com.sprint.mission.discodeit.entity.ReadStatus;
+
+import java.util.List;
+import java.util.UUID;
+
+public interface ReadStatusService {
+ ReadStatus create(ReadStatusCreateRequest request);
+ ReadStatus find(UUID readStatusId);
+ List findAllByUserId(UUID userId);
+ ReadStatus update(UUID readStatusId, ReadStatusUpdateRequest request);
+ void delete(UUID readStatusId);
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/service/UserService.java b/src/main/java/com/sprint/mission/discodeit/service/UserService.java
new file mode 100644
index 0000000000..d824a7806c
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/service/UserService.java
@@ -0,0 +1,19 @@
+package com.sprint.mission.discodeit.service;
+
+import com.sprint.mission.discodeit.dto.data.UserDto;
+import com.sprint.mission.discodeit.dto.request.BinaryContentCreateRequest;
+import com.sprint.mission.discodeit.dto.request.UserCreateRequest;
+import com.sprint.mission.discodeit.dto.request.UserUpdateRequest;
+import com.sprint.mission.discodeit.entity.User;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+
+public interface UserService {
+ User create(UserCreateRequest userCreateRequest, Optional profileCreateRequest);
+ UserDto find(UUID userId);
+ List findAll();
+ User update(UUID userId, UserUpdateRequest userUpdateRequest, Optional profileCreateRequest);
+ void delete(UUID userId);
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/service/UserStatusService.java b/src/main/java/com/sprint/mission/discodeit/service/UserStatusService.java
new file mode 100644
index 0000000000..47058277f5
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/service/UserStatusService.java
@@ -0,0 +1,17 @@
+package com.sprint.mission.discodeit.service;
+
+import com.sprint.mission.discodeit.dto.request.UserStatusCreateRequest;
+import com.sprint.mission.discodeit.dto.request.UserStatusUpdateRequest;
+import com.sprint.mission.discodeit.entity.UserStatus;
+
+import java.util.List;
+import java.util.UUID;
+
+public interface UserStatusService {
+ UserStatus create(UserStatusCreateRequest request);
+ UserStatus find(UUID userStatusId);
+ List findAll();
+ UserStatus update(UUID userStatusId, UserStatusUpdateRequest request);
+ UserStatus updateByUserId(UUID userId, UserStatusUpdateRequest request);
+ void delete(UUID userStatusId);
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/service/basic/BasicAuthService.java b/src/main/java/com/sprint/mission/discodeit/service/basic/BasicAuthService.java
new file mode 100644
index 0000000000..38f67f1c02
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/service/basic/BasicAuthService.java
@@ -0,0 +1,31 @@
+package com.sprint.mission.discodeit.service.basic;
+
+import com.sprint.mission.discodeit.dto.request.LoginRequest;
+import com.sprint.mission.discodeit.entity.User;
+import com.sprint.mission.discodeit.repository.UserRepository;
+import com.sprint.mission.discodeit.service.AuthService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.util.NoSuchElementException;
+
+@RequiredArgsConstructor
+@Service
+public class BasicAuthService implements AuthService {
+ private final UserRepository userRepository;
+
+ @Override
+ public User login(LoginRequest loginRequest) {
+ String username = loginRequest.username();
+ String password = loginRequest.password();
+
+ User user = userRepository.findByUsername(username)
+ .orElseThrow(() -> new NoSuchElementException("User with username " + username + " not found"));
+
+ if (!user.getPassword().equals(password)) {
+ throw new IllegalArgumentException("Wrong password");
+ }
+
+ return user;
+ }
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/service/basic/BasicBinaryContentService.java b/src/main/java/com/sprint/mission/discodeit/service/basic/BasicBinaryContentService.java
new file mode 100644
index 0000000000..74a6532eb2
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/service/basic/BasicBinaryContentService.java
@@ -0,0 +1,52 @@
+package com.sprint.mission.discodeit.service.basic;
+
+import com.sprint.mission.discodeit.dto.request.BinaryContentCreateRequest;
+import com.sprint.mission.discodeit.entity.BinaryContent;
+import com.sprint.mission.discodeit.repository.BinaryContentRepository;
+import com.sprint.mission.discodeit.service.BinaryContentService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.UUID;
+
+@RequiredArgsConstructor
+@Service
+public class BasicBinaryContentService implements BinaryContentService {
+ private final BinaryContentRepository binaryContentRepository;
+
+ @Override
+ public BinaryContent create(BinaryContentCreateRequest request) {
+ String fileName = request.fileName();
+ byte[] bytes = request.bytes();
+ String contentType = request.contentType();
+ BinaryContent binaryContent = new BinaryContent(
+ fileName,
+ (long) bytes.length,
+ contentType,
+ bytes
+ );
+ return binaryContentRepository.save(binaryContent);
+ }
+
+ @Override
+ public BinaryContent find(UUID binaryContentId) {
+ return binaryContentRepository.findById(binaryContentId)
+ .orElseThrow(() -> new NoSuchElementException("BinaryContent with id " + binaryContentId + " not found"));
+ }
+
+ @Override
+ public List findAllByIdIn(List binaryContentIds) {
+ return binaryContentRepository.findAllByIdIn(binaryContentIds).stream()
+ .toList();
+ }
+
+ @Override
+ public void delete(UUID binaryContentId) {
+ if (!binaryContentRepository.existsById(binaryContentId)) {
+ throw new NoSuchElementException("BinaryContent with id " + binaryContentId + " not found");
+ }
+ binaryContentRepository.deleteById(binaryContentId);
+ }
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/service/basic/BasicChannelService.java b/src/main/java/com/sprint/mission/discodeit/service/basic/BasicChannelService.java
new file mode 100644
index 0000000000..62391b100f
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/service/basic/BasicChannelService.java
@@ -0,0 +1,50 @@
+package com.sprint.mission.discodeit.service.basic;
+
+import com.sprint.mission.discodeit.entity.Channel;
+import com.sprint.mission.discodeit.repository.ChannelRepository;
+import com.sprint.mission.discodeit.service.ChannelService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.UUID;
+
+@Service
+@RequiredArgsConstructor
+public class BasicChannelService implements ChannelService {
+
+ private final ChannelRepository channelRepository;
+
+ @Override
+ public Channel createChannel(String name, String description) {
+ Channel channel = new Channel(name, description);
+ channelRepository.save(channel);
+ return channel;
+ }
+
+ @Override
+ public Channel getChannel(UUID id) {
+ return channelRepository.findById(id);
+ }
+
+ @Override
+ public List getAllChannels() {
+ return channelRepository.findAll();
+ }
+
+ @Override
+ public Channel updateChannel(UUID id, String name, String description) {
+ Channel channel = channelRepository.findById(id);
+ if (channel != null) {
+ channel.update(name, description);
+ channelRepository.save(channel);
+ return channel;
+ }
+ return null;
+ }
+
+ @Override
+ public void deleteChannel(UUID id) {
+ channelRepository.delete(id);
+ }
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/service/basic/BasicMessageService.java b/src/main/java/com/sprint/mission/discodeit/service/basic/BasicMessageService.java
new file mode 100644
index 0000000000..eb99323d3d
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/service/basic/BasicMessageService.java
@@ -0,0 +1,65 @@
+package com.sprint.mission.discodeit.service.basic;
+
+import com.sprint.mission.discodeit.entity.Message;
+import com.sprint.mission.discodeit.repository.MessageRepository;
+import com.sprint.mission.discodeit.service.ChannelService;
+import com.sprint.mission.discodeit.service.MessageService;
+import com.sprint.mission.discodeit.service.UserService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.UUID;
+
+@Service
+@RequiredArgsConstructor
+public class BasicMessageService implements MessageService {
+
+ @Autowired
+ private final MessageRepository messageRepository;
+ @Autowired
+ private final UserService userService;
+
+ private final ChannelService channelService;
+
+ @Override
+ public Message createMessage(UUID userId, UUID channelId, String content) {
+ if (userService.getUser(userId) == null) {
+ throw new IllegalArgumentException("유저를 찾을 수 없습니다. userId: " + userId);
+ }
+ if (channelService.getChannel(channelId) == null) {
+ throw new IllegalArgumentException("채널을 찾을 수 없습니다. channelId: " + channelId);
+ }
+
+ Message message = new Message(userId, channelId, content);
+ messageRepository.save(message);
+ return message;
+ }
+
+ @Override
+ public Message getMessage(UUID id) {
+ return messageRepository.findById(id);
+ }
+
+ @Override
+ public List getAllMessages() {
+ return messageRepository.findAll();
+ }
+
+ @Override
+ public Message updateMessage(UUID id, String content) {
+ Message message = messageRepository.findById(id);
+ if (message != null) {
+ message.update(content);
+ messageRepository.save(message);
+ return message;
+ }
+ return null;
+ }
+
+ @Override
+ public void deleteMessage(UUID id) {
+ messageRepository.delete(id);
+ }
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/service/basic/BasicReadStatusService.java b/src/main/java/com/sprint/mission/discodeit/service/basic/BasicReadStatusService.java
new file mode 100644
index 0000000000..18c00fb9ed
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/service/basic/BasicReadStatusService.java
@@ -0,0 +1,74 @@
+package com.sprint.mission.discodeit.service.basic;
+
+import com.sprint.mission.discodeit.dto.request.ReadStatusCreateRequest;
+import com.sprint.mission.discodeit.dto.request.ReadStatusUpdateRequest;
+import com.sprint.mission.discodeit.entity.ReadStatus;
+import com.sprint.mission.discodeit.repository.ChannelRepository;
+import com.sprint.mission.discodeit.repository.ReadStatusRepository;
+import com.sprint.mission.discodeit.repository.UserRepository;
+import com.sprint.mission.discodeit.service.ReadStatusService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.time.Instant;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.UUID;
+
+@RequiredArgsConstructor
+@Service
+public class BasicReadStatusService implements ReadStatusService {
+ private final ReadStatusRepository readStatusRepository;
+ private final UserRepository userRepository;
+ private final ChannelRepository channelRepository;
+
+ @Override
+ public ReadStatus create(ReadStatusCreateRequest request) {
+ UUID userId = request.userId();
+ UUID channelId = request.channelId();
+
+ if (!userRepository.existsById(userId)) {
+ throw new NoSuchElementException("User with id " + userId + " does not exist");
+ }
+ if (!channelRepository.existsById(channelId)) {
+ throw new NoSuchElementException("Channel with id " + channelId + " does not exist");
+ }
+ if (readStatusRepository.findAllByUserId(userId).stream()
+ .anyMatch(readStatus -> readStatus.getChannelId().equals(channelId))) {
+ throw new IllegalArgumentException("ReadStatus with userId " + userId + " and channelId " + channelId + " already exists");
+ }
+
+ Instant lastReadAt = request.lastReadAt();
+ ReadStatus readStatus = new ReadStatus(userId, channelId, lastReadAt);
+ return readStatusRepository.save(readStatus);
+ }
+
+ @Override
+ public ReadStatus find(UUID readStatusId) {
+ return readStatusRepository.findById(readStatusId)
+ .orElseThrow(() -> new NoSuchElementException("ReadStatus with id " + readStatusId + " not found"));
+ }
+
+ @Override
+ public List findAllByUserId(UUID userId) {
+ return readStatusRepository.findAllByUserId(userId).stream()
+ .toList();
+ }
+
+ @Override
+ public ReadStatus update(UUID readStatusId, ReadStatusUpdateRequest request) {
+ Instant newLastReadAt = request.newLastReadAt();
+ ReadStatus readStatus = readStatusRepository.findById(readStatusId)
+ .orElseThrow(() -> new NoSuchElementException("ReadStatus with id " + readStatusId + " not found"));
+ readStatus.update(newLastReadAt);
+ return readStatusRepository.save(readStatus);
+ }
+
+ @Override
+ public void delete(UUID readStatusId) {
+ if (!readStatusRepository.existsById(readStatusId)) {
+ throw new NoSuchElementException("ReadStatus with id " + readStatusId + " not found");
+ }
+ readStatusRepository.deleteById(readStatusId);
+ }
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/service/basic/BasicUserService.java b/src/main/java/com/sprint/mission/discodeit/service/basic/BasicUserService.java
new file mode 100644
index 0000000000..152d7ffd0d
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/service/basic/BasicUserService.java
@@ -0,0 +1,50 @@
+package com.sprint.mission.discodeit.service.basic;
+
+import com.sprint.mission.discodeit.entity.User;
+import com.sprint.mission.discodeit.repository.UserRepository;
+import com.sprint.mission.discodeit.service.UserService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.UUID;
+
+@Service
+@RequiredArgsConstructor
+public class BasicUserService implements UserService {
+
+ private final UserRepository userRepository;
+
+ @Override
+ public User createUser(String username, String email) {
+ User user = new User(username, email);
+ userRepository.save(user);
+ return user;
+ }
+
+ @Override
+ public User getUser(UUID id) {
+ return userRepository.findById(id);
+ }
+
+ @Override
+ public List getAllUsers() {
+ return userRepository.findAll();
+ }
+
+ @Override
+ public User updateUser(UUID id, String username, String email) {
+ User user = userRepository.findById(id);
+ if (user != null) {
+ user.update(username, email);
+ userRepository.save(user);
+ return user;
+ }
+ return null;
+ }
+
+ @Override
+ public void deleteUser(UUID id) {
+ userRepository.delete(id);
+ }
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/service/basic/BasicUserStatusService.java b/src/main/java/com/sprint/mission/discodeit/service/basic/BasicUserStatusService.java
new file mode 100644
index 0000000000..ee14451fd6
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/service/basic/BasicUserStatusService.java
@@ -0,0 +1,80 @@
+package com.sprint.mission.discodeit.service.basic;
+
+import com.sprint.mission.discodeit.dto.request.UserStatusCreateRequest;
+import com.sprint.mission.discodeit.dto.request.UserStatusUpdateRequest;
+import com.sprint.mission.discodeit.entity.UserStatus;
+import com.sprint.mission.discodeit.repository.UserRepository;
+import com.sprint.mission.discodeit.repository.UserStatusRepository;
+import com.sprint.mission.discodeit.service.UserStatusService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.time.Instant;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.UUID;
+
+@RequiredArgsConstructor
+@Service
+public class BasicUserStatusService implements UserStatusService {
+ private final UserStatusRepository userStatusRepository;
+ private final UserRepository userRepository;
+
+ @Override
+ public UserStatus create(UserStatusCreateRequest request) {
+ UUID userId = request.userId();
+
+ if (!userRepository.existsById(userId)) {
+ throw new NoSuchElementException("User with id " + userId + " does not exist");
+ }
+ if (userStatusRepository.findByUserId(userId).isPresent()) {
+ throw new IllegalArgumentException("UserStatus with id " + userId + " already exists");
+ }
+
+ Instant lastActiveAt = request.lastActiveAt();
+ UserStatus userStatus = new UserStatus(userId, lastActiveAt);
+ return userStatusRepository.save(userStatus);
+ }
+
+ @Override
+ public UserStatus find(UUID userStatusId) {
+ return userStatusRepository.findById(userStatusId)
+ .orElseThrow(() -> new NoSuchElementException("UserStatus with id " + userStatusId + " not found"));
+ }
+
+ @Override
+ public List findAll() {
+ return userStatusRepository.findAll().stream()
+ .toList();
+ }
+
+ @Override
+ public UserStatus update(UUID userStatusId, UserStatusUpdateRequest request) {
+ Instant newLastActiveAt = request.newLastActiveAt();
+
+ UserStatus userStatus = userStatusRepository.findById(userStatusId)
+ .orElseThrow(() -> new NoSuchElementException("UserStatus with id " + userStatusId + " not found"));
+ userStatus.update(newLastActiveAt);
+
+ return userStatusRepository.save(userStatus);
+ }
+
+ @Override
+ public UserStatus updateByUserId(UUID userId, UserStatusUpdateRequest request) {
+ Instant newLastActiveAt = request.newLastActiveAt();
+
+ UserStatus userStatus = userStatusRepository.findByUserId(userId)
+ .orElseThrow(() -> new NoSuchElementException("UserStatus with userId " + userId + " not found"));
+ userStatus.update(newLastActiveAt);
+
+ return userStatusRepository.save(userStatus);
+ }
+
+ @Override
+ public void delete(UUID userStatusId) {
+ if (!userStatusRepository.existsById(userStatusId)) {
+ throw new NoSuchElementException("UserStatus with id " + userStatusId + " not found");
+ }
+ userStatusRepository.deleteById(userStatusId);
+ }
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/service/file/FileChannelService.java b/src/main/java/com/sprint/mission/discodeit/service/file/FileChannelService.java
new file mode 100644
index 0000000000..c003b7e36e
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/service/file/FileChannelService.java
@@ -0,0 +1,52 @@
+package com.sprint.mission.discodeit.service.file;
+
+import com.sprint.mission.discodeit.entity.Channel;
+import com.sprint.mission.discodeit.repository.ChannelRepository;
+import com.sprint.mission.discodeit.repository.file.FileChannelRepository;
+import com.sprint.mission.discodeit.service.ChannelService;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.UUID;
+
+@Service
+public class FileChannelService implements ChannelService {
+ private final ChannelRepository repository;
+
+ public FileChannelService() {
+ this.repository = new FileChannelRepository();
+ }
+
+ @Override
+ public Channel createChannel(String name, String description) {
+ Channel channel = new Channel(name, description);
+ repository.save(channel);
+ return channel;
+ }
+
+ @Override
+ public Channel getChannel(UUID id) {
+ return repository.findById(id);
+ }
+
+ @Override
+ public List getAllChannels() {
+ return repository.findAll();
+ }
+
+ @Override
+ public Channel updateChannel(UUID id, String name, String description) {
+ Channel channel = repository.findById(id);
+ if(channel != null) {
+ channel.update(name, description);
+ repository.save(channel);
+ return channel;
+ }
+ return null;
+ }
+
+ @Override
+ public void deleteChannel(UUID id) {
+ repository.delete(id);
+ }
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/service/file/FileMessageService.java b/src/main/java/com/sprint/mission/discodeit/service/file/FileMessageService.java
new file mode 100644
index 0000000000..27858a7f64
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/service/file/FileMessageService.java
@@ -0,0 +1,68 @@
+package com.sprint.mission.discodeit.service.file;
+
+import com.sprint.mission.discodeit.entity.Channel;
+import com.sprint.mission.discodeit.entity.Message;
+import com.sprint.mission.discodeit.entity.User;
+import com.sprint.mission.discodeit.repository.MessageRepository;
+import com.sprint.mission.discodeit.repository.file.FileMessageRepository;
+import com.sprint.mission.discodeit.service.ChannelService;
+import com.sprint.mission.discodeit.service.MessageService;
+import com.sprint.mission.discodeit.service.UserService;
+
+import java.util.List;
+import java.util.UUID;
+
+public class FileMessageService implements MessageService {
+ private final MessageRepository repository;
+ private final UserService userService;
+ private final ChannelService channelService;
+
+ public FileMessageService(MessageRepository repository, UserService userService, ChannelService channelService) {
+ this.repository = repository;
+ this.userService = userService;
+ this.channelService = channelService;
+ }
+
+ @Override
+ public Message createMessage(UUID userId, UUID channelId, String content) {
+ User user = userService.getUser(userId);
+ Channel channel = channelService.getChannel(channelId);
+
+ if (user == null) {
+ throw new IllegalArgumentException("유저를 찾을 수 없습니다. userId: " + userId);
+ }
+ if (channel == null) {
+ throw new IllegalArgumentException("채널을 찾을 수 없습니다. channelId: " + channelId);
+ }
+
+ Message message = new Message(userId, channelId, content);
+ repository.save(message);
+ return message;
+ }
+
+ @Override
+ public Message getMessage(UUID id) {
+ return repository.findById(id);
+ }
+
+ @Override
+ public List getAllMessages() {
+ return repository.findAll();
+ }
+
+ @Override
+ public Message updateMessage(UUID id, String content) {
+ Message message = repository.findById(id);
+ if (message != null) {
+ message.update(content);
+ repository.save(message);
+ return message;
+ }
+ return null;
+ }
+
+ @Override
+ public void deleteMessage(UUID id) {
+ repository.delete(id);
+ }
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/service/file/FileUserService.java b/src/main/java/com/sprint/mission/discodeit/service/file/FileUserService.java
new file mode 100644
index 0000000000..39a25f39de
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/service/file/FileUserService.java
@@ -0,0 +1,50 @@
+package com.sprint.mission.discodeit.service.file;
+
+import com.sprint.mission.discodeit.entity.User;
+import com.sprint.mission.discodeit.repository.UserRepository;
+import com.sprint.mission.discodeit.repository.file.FileUserRepository;
+import com.sprint.mission.discodeit.service.UserService;
+
+import java.util.List;
+import java.util.UUID;
+
+public class FileUserService implements UserService {
+ private final UserRepository repository;
+
+ public FileUserService(UserRepository repository) {
+ this.repository = repository;
+ }
+
+ @Override
+ public User createUser(String username, String email) {
+ User user = new User(username, email);
+ repository.save(user);
+ return user;
+ }
+
+ @Override
+ public User getUser(UUID id) {
+ return repository.findById(id);
+ }
+
+ @Override
+ public List getAllUsers() {
+ return repository.findAll();
+ }
+
+ @Override
+ public User updateUser(UUID id, String username, String email) {
+ User user = repository.findById(id);
+ if (user != null) {
+ user.update(username, email);
+ repository.save(user);
+ return user;
+ }
+ return null;
+ }
+
+ @Override
+ public void deleteUser(UUID id) {
+ repository.delete(id);
+ }
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/service/jcf/JCFChannelService.java b/src/main/java/com/sprint/mission/discodeit/service/jcf/JCFChannelService.java
new file mode 100644
index 0000000000..f366538df4
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/service/jcf/JCFChannelService.java
@@ -0,0 +1,49 @@
+package com.sprint.mission.discodeit.service.jcf;
+
+import com.sprint.mission.discodeit.entity.Channel;
+import com.sprint.mission.discodeit.service.ChannelService;
+
+import java.util.*;
+
+public class JCFChannelService implements ChannelService {
+
+ private final Map data;
+
+ public JCFChannelService() {
+ this.data = new HashMap<>();
+ }
+
+
+ @Override
+ public Channel createChannel(String name, String description){
+ Channel channel = new Channel(name, description);
+ data.put(channel.getId(), channel);
+ return channel;
+ }
+
+ @Override
+ public Channel getChannel(UUID id) {
+ return data.get(id);
+ }
+
+ @Override
+ public List getAllChannels() {
+ return new ArrayList<>(data.values());
+ }
+
+ @Override
+ public Channel updateChannel(UUID id, String name, String description) {
+ Channel channel = data.get(id);
+ if(channel != null) {
+ channel.update(name, description);
+ return channel;
+
+ }
+ return null;
+ }
+
+ @Override
+ public void deleteChannel(UUID id) {
+ data.remove(id);
+ }
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/service/jcf/JCFMessageService.java b/src/main/java/com/sprint/mission/discodeit/service/jcf/JCFMessageService.java
new file mode 100644
index 0000000000..1baabb1c4a
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/service/jcf/JCFMessageService.java
@@ -0,0 +1,71 @@
+package com.sprint.mission.discodeit.service.jcf;
+
+import com.sprint.mission.discodeit.entity.Message;
+import com.sprint.mission.discodeit.entity.User;
+import com.sprint.mission.discodeit.entity.Channel;
+import com.sprint.mission.discodeit.service.MessageService;
+
+import java.util.*;
+
+
+public class JCFMessageService implements MessageService {
+ private final Map data;
+ private final JCFUserService userService;
+ private final JCFChannelService channelService;
+
+ public JCFMessageService(JCFUserService userService, JCFChannelService channelService) {
+ this.data = new HashMap<>();
+ this.userService = userService;
+ this.channelService = channelService;
+ }
+
+ private void validateUser(User user, UUID userId) {
+ if (user == null) {
+ throw new IllegalArgumentException("유저를 찾을 수 없습니다. userId: " + userId);
+ }
+ }
+
+ private void validateChannel(Channel channel, UUID channelId) {
+ if (channel == null) {
+ throw new IllegalArgumentException("채널을 찾을 수 없습니다. channelId: " + channelId);
+ }
+ }
+
+ @Override
+ public Message createMessage(UUID userId, UUID channelId, String content) {
+ User user = userService.getUser(userId);
+ Channel channel = channelService.getChannel(channelId);
+
+ validateUser(user, userId);
+ validateChannel(channel, channelId);
+
+ Message message = new Message(userId, channelId, content);
+ data.put(message.getId(), message);
+ return message;
+ }
+
+ @Override
+ public Message getMessage(UUID id) {
+ return data.get(id);
+ }
+
+ @Override
+ public List getAllMessages() {
+ return new ArrayList<>(data.values());
+ }
+
+ @Override
+ public Message updateMessage(UUID id, String content) {
+ Message message = data.get(id);
+ if (message != null) {
+ message.update(content);
+ return message;
+ }
+ return null;
+ }
+
+ @Override
+ public void deleteMessage(UUID id) {
+ data.remove(id);
+ }
+}
diff --git a/src/main/java/com/sprint/mission/discodeit/service/jcf/JCFUserService.java b/src/main/java/com/sprint/mission/discodeit/service/jcf/JCFUserService.java
new file mode 100644
index 0000000000..fab3971364
--- /dev/null
+++ b/src/main/java/com/sprint/mission/discodeit/service/jcf/JCFUserService.java
@@ -0,0 +1,47 @@
+package com.sprint.mission.discodeit.service.jcf;
+
+import com.sprint.mission.discodeit.entity.User;
+import com.sprint.mission.discodeit.service.UserService;
+
+import java.util.*;
+
+public class JCFUserService implements UserService {
+ private final Map data;
+
+ public JCFUserService() {
+ this.data = new HashMap<>();
+ }
+
+ @Override
+ public User createUser(String username, String email) {
+ User user = new User(username, email);
+ data.put(user.getId(), user);
+ return user;
+ }
+
+ @Override
+ public User getUser(UUID id) {
+ return data.get(id);
+ }
+
+ @Override
+ public List getAllUsers() {
+ return new ArrayList<>(data.values());
+ }
+
+ @Override
+ public User updateUser(UUID id, String username, String email) {
+ User user = data.get(id);
+ if(user != null) {
+ user.update(username, email);
+ return user;
+ }
+ return null;
+ }
+
+ @Override
+ public void deleteUser(UUID id) {
+ data.remove(id);
+ }
+}
+
diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml
new file mode 100644
index 0000000000..08f924e514
--- /dev/null
+++ b/src/main/resources/application.yaml
@@ -0,0 +1,10 @@
+spring:
+ application:
+ name: discodeit
+
+discodeit:
+ repository:
+ type: file # jcf | file
+ file-directory: .discodeit
+server:
+ port: 8081
diff --git a/src/test/java/com/sprint/mission/discodeit/DiscodeitApplicationTests.java b/src/test/java/com/sprint/mission/discodeit/DiscodeitApplicationTests.java
new file mode 100644
index 0000000000..3a987a2148
--- /dev/null
+++ b/src/test/java/com/sprint/mission/discodeit/DiscodeitApplicationTests.java
@@ -0,0 +1,13 @@
+package com.sprint.mission.discodeit;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class DiscodeitApplicationTests {
+
+ @Test
+ void contextLoads() {
+ }
+
+}