diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 0000000..d0f2215
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,25 @@
+이슈 제목 예시(이슈 생성시 삭제)
+---
+| 태그 | 제목 |
+| --- |-------------------------------------------------------------------------|
+| feat | 새로운 기능 구현
ex. [feat]:Main #11 구글 로그인 API 기능 구현 |
+| fix | 코드 오류 수정
ex. [fix]:Main #10 회원가입 비즈니스 로직 오류 수정 |
+| del | 쓸모없는 코드 삭제
ex. [del]:Main #12 불필요한 import 제거 |
+| docs | README나 wiki 등의 문서 개정
ex. [docs]:global #14 리드미 수정 |
+| refactor | 내부 로직은 변경 하지 않고 기존의 코드를 개선하는 리팩토링
ex. [refactor]:Global #15 코드 로직 개선 |
+| chore | 의존성 추가, yml 추가와 수정, 패키지 구조 변경, 파일 이동
ex. [chore]:Socket #21 yml 수정 |
+| test | 테스트 코드 작성, 수정
ex. [test]:Global #20 로그인 API 테스트 코드 작성 |
+
+---
+
+### 📝 Description
+
+- 구현할 내용 1
+- 구현할 내용 2
+
+---
+
+### 📝 Todo
+
+- [ ] : 구현할 내용 1
+- [ ] : 구현할 내용 2
diff --git "a/.github/ISSUE_TEMPLATE/\354\235\264\354\212\210-\355\205\234\355\224\214\353\246\277.md" "b/.github/ISSUE_TEMPLATE/\354\235\264\354\212\210-\355\205\234\355\224\214\353\246\277.md"
new file mode 100644
index 0000000..b90ed06
--- /dev/null
+++ "b/.github/ISSUE_TEMPLATE/\354\235\264\354\212\210-\355\205\234\355\224\214\353\246\277.md"
@@ -0,0 +1,34 @@
+---
+name: 이슈 템플릿
+about: 이슈 템플릿
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+이슈 제목 예시(이슈 생성시 삭제)
+---
+| 태그 | 제목 |
+| --- |-------------------------------------------------------------------------|
+| feat | 새로운 기능 구현
ex. [feat]:Main 구글 로그인 API 기능 구현 |
+| fix | 코드 오류 수정
ex. [fix]:Main 회원가입 비즈니스 로직 오류 수정 |
+| del | 쓸모없는 코드 삭제
ex. [del]:Main 불필요한 import 제거 |
+| docs | README나 wiki 등의 문서 개정
ex. [docs]:global 리드미 수정 |
+| refactor | 내부 로직은 변경 하지 않고 기존의 코드를 개선하는 리팩토링
ex. [refactor]:Global 코드 로직 개선 |
+| chore | 의존성 추가, yml 추가와 수정, 패키지 구조 변경, 파일 이동
ex. [chore]:Socket yml 수정 |
+| test | 테스트 코드 작성, 수정
ex. [test]:Global 로그인 API 테스트 코드 작성 |
+
+---
+
+### 📝 Description
+
+- 구현할 내용 1
+- 구현할 내용 2
+
+---
+
+### 📝 Todo
+
+- [ ] : 구현할 내용 1
+- [ ] : 구현할 내용 2
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 0000000..7316fa7
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1,38 @@
+제목 예시: [Main]: #27 엔티티 수정
+
+### ✅ PR 유형
+어떤 변경 사항이 있었나요?
+
+- [ ] 새로운 기능 추가
+- [ ] 버그 수정
+- [ ] 코드에 영향을 주지 않는 변경사항(오타 수정, 탭 사이즈 변경, 변수명 변경)
+- [ ] 코드 리팩토링
+- [ ] 주석 추가 및 수정
+- [ ] 문서 수정
+- [ ] 빌드 부분 혹은 패키지 매니저 수정
+- [ ] 파일 혹은 폴더명 수정
+- [ ] 파일 혹은 폴더 삭제
+
+---
+
+### 📝 작업 내용
+이번 PR에서 작업한 내용을 간략히 설명해주세요(이미지 첨부 가능)
+
+- 작업한 내용 1
+- 작업한 내용 2
+
+---
+
+### ✏️ 이슈닫기(선택 사항)
+해결한 이슈 닫기
+
+ex)
+closed #(이슈번호)
+
+---
+
+### 🎸 기타 사항 or 추가 코멘트
+
+
+
+
diff --git a/.github/workflows/main-service-ci.yml b/.github/workflows/main-service-ci.yml
new file mode 100644
index 0000000..d3dfb3b
--- /dev/null
+++ b/.github/workflows/main-service-ci.yml
@@ -0,0 +1,45 @@
+name: Main Service CI
+
+on:
+ pull_request:
+ branches: [ "develop" ]
+
+jobs:
+ check-skip:
+ name: Check ot skip CI
+ runs-on: ubuntu-latest
+ if: ${{ contains(github.event.head_commit.message, 'Main') || contains(github.event.head_commit.message, 'Global') }}
+ steps:
+ - run: echo "${{ github.event.head_commit.message }}"
+
+ build:
+ runs-on: ubuntu-latest
+ needs: check-skip
+ steps:
+ - uses: actions/checkout@v3
+ - name: 🍀 JDK 17 설정
+ uses: actions/setup-java@v3
+ with:
+ java-version: '17'
+ distribution: 'temurin'
+
+ - name: 🍀 application.yml 설정
+ run: |
+ cd ./MainService
+ cd ./src/main
+ mkdir resources
+ cd ./resources
+ touch ./application.yml
+ echo "$APPLICATION_DEV" > ./application.yml
+ env:
+ APPLICATION_MAIN: ${{ secrets.APPLICATION_DEV }}
+
+ - name: 🍀 gradle build를 위한 권한 설정
+ run: |
+ cd ./Main
+ chmod +x gradlew
+
+ - name: 🍀 gradle build
+ run: |
+ cd ./Main
+ ./gradlew build -x test
\ No newline at end of file
diff --git a/.github/workflows/main-service-cicd.yml b/.github/workflows/main-service-cicd.yml
new file mode 100644
index 0000000..f1009a7
--- /dev/null
+++ b/.github/workflows/main-service-cicd.yml
@@ -0,0 +1,87 @@
+name: Main Service CICD
+
+on:
+ push:
+ branches: [ "develop" ]
+ pull_request:
+ branches: [ "develop" ]
+
+jobs:
+ check-skip:
+ name: Check ot skip CI
+ runs-on: ubuntu-latest
+ if: ${{ contains(github.event.head_commit.message, 'Main') || contains(github.event.head_commit.message, 'Global') }}
+ steps:
+ - run: echo "${{ github.event.head_commit.message }}"
+
+ build:
+ runs-on: ubuntu-latest
+ needs: check-skip
+ steps:
+ - uses: actions/checkout@v3
+ - name: 🍀 JDK 17 설정
+ uses: actions/setup-java@v3
+ with:
+ java-version: '17'
+ distribution: 'temurin'
+
+ - name: 🍀 application.yml 설정
+ run: |
+ cd ./Main
+ cd ./src/main
+ mkdir resources
+ cd ./resources
+ touch ./application.yml
+ echo "$APPLICATION_DEV" > ./application.yml
+ env:
+ APPLICATION_MAIN: ${{ secrets.APPLICATION_DEV }}
+
+ - name: 🍀 gradle build를 위한 권한 설정
+ run: |
+ cd ./Main
+ chmod +x gradlew
+
+ - name: 🍀 gradle build
+ run: |
+ cd ./Main
+ ./gradlew build -x test
+
+ - name: 🍀 docker image build 후 docker hub에 push
+ run: |
+ cd ./Main
+ docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }}
+ docker build -t ${{ secrets.DOCKER_REPOSITORY }}/${{ secrets.MAIN_DOCKER_IMAGE }} .
+ docker push ${{ secrets.DOCKER_REPOSITORY }}/${{ secrets.DOCKER_IMAGE }}
+
+ - name: 🍀 deploy.sh 파일을 EC2 development server로 전달
+ uses: appleboy/scp-action@master
+ with:
+ username: ubuntu
+ host: ${{ secrets.EC2_HOST }}
+ key: ${{ secrets.EC2_KEY }}
+ port: ${{ secrets.EC2_PORT }}
+ source: "./scripts/deploy.sh"
+ target: "/home/ubuntu/"
+
+ - name: 🍀 docker-compose.yml 파일을 EC2 development server로 전달
+ uses: appleboy/scp-action@master
+ with:
+ username: ubuntu
+ host: ${{ secrets.MAIN_EC2_HOST }}
+ key: ${{ secrets.MAIN_EC2_KEY }}
+ port: ${{ secrets.MAIN_EC2_PORT }}
+ source: "./Main/docker-compose.yml"
+ target: "/home/ubuntu/"
+
+ - name: 🍀 docker hub 에서 pull 후 deploy
+ uses: appleboy/ssh-action@master
+ with:
+ username: ubuntu
+ host: ${{ secrets.EC2_HOST }}
+ key: ${{ secrets.EC2_KEY }}
+ script: |
+ sudo docker pull ${{ secrets.DOCKER_REPOSITORY }}/${{ secrets.DOCKER_IMAGE }}
+ chmod 777 ./scripts/deploy.sh
+ cp ./scripts/deploy.sh ./deploy.sh
+ ./deploy.sh
+ docker image prune -f
diff --git a/.github/workflows/socket-service-ci.yml b/.github/workflows/socket-service-ci.yml
new file mode 100644
index 0000000..577f3f7
--- /dev/null
+++ b/.github/workflows/socket-service-ci.yml
@@ -0,0 +1,46 @@
+name: Socket Service CI
+
+on:
+ pull_request:
+ branches: [ "develop" ]
+
+jobs:
+ check-skip:
+ name: Check ot skip CI
+ runs-on: ubuntu-latest
+ if: ${{ contains(github.event.head_commit.message, 'Socket') || contains(github.event.head_commit.message, 'Global') }}
+ steps:
+ - run: echo "${{ github.event.head_commit.message }}"
+
+ build:
+ runs-on: ubuntu-latest
+ needs: check-skip
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: 🍀 JDK 17 설정
+ uses: actions/setup-java@v3
+ with:
+ java-version: '17'
+ distribution: 'temurin'
+
+ - name: 🍀 application.yml 설정
+ run: |
+ cd ./socket
+ cd ./src/main
+ mkdir resources
+ cd ./resources
+ touch ./application.yml
+ echo "$APPLICATION_SOCKET" > ./application.yml
+ env:
+ APPLICATION_SOCKET: ${{ secrets.APPLICATION_SOCKET }}
+
+ - name: 🍀 gradle build를 위한 권한 설정
+ run: |
+ cd ./socket
+ chmod +x gradlew
+
+ - name: 🍀 gradle build
+ run: |
+ cd ./socket
+ ./gradlew build -x test
\ No newline at end of file
diff --git a/.github/workflows/socket-service-cicd.yml b/.github/workflows/socket-service-cicd.yml
new file mode 100644
index 0000000..8474791
--- /dev/null
+++ b/.github/workflows/socket-service-cicd.yml
@@ -0,0 +1,85 @@
+name: Socket Service CICD
+
+on:
+ push:
+ branches: [ "develop" ]
+
+jobs:
+ check-skip:
+ name: Check ot skip CI
+ runs-on: ubuntu-latest
+ if: ${{ contains(github.event.head_commit.message, 'Socket') || contains(github.event.head_commit.message, 'Global') }}
+ steps:
+ - run: echo "${{ github.event.head_commit.message }}"
+
+ build:
+ runs-on: ubuntu-latest
+ needs: check-skip
+ steps:
+ - uses: actions/checkout@v3
+ - name: 🍀 JDK 17 설정
+ uses: actions/setup-java@v3
+ with:
+ java-version: '17'
+ distribution: 'temurin'
+
+ - name: 🍀 application.yml 설정
+ run: |
+ cd ./socket
+ cd ./src/main
+ mkdir resources
+ cd ./resources
+ touch ./application.yml
+ echo "$APPLICATION_SOCKET" > ./application.yml
+ env:
+ APPLICATION_SOCKET: ${{ secrets.APPLICATION_SOCKET }}
+
+ - name: 🍀 gradle build를 위한 권한 설정정
+ run: |
+ cd ./socket
+ chmod +x gradlew
+
+ - name: 🍀 gradle build
+ run: |
+ cd ./socket
+ ./gradlew build -x test
+
+ - name: 🍀 docker image build 후 docker hub에 push
+ run: |
+ cd ./socket
+ docker login -u ${{ secrets.SOCKET_DOCKER_USERNAME }} -p ${{ secrets.SOCKET_DOCKER_PASSWORD }}
+ docker build -t ${{ secrets.SOCKET_DOCKER_REPOSITORY }}/${{ secrets.SOCKET_DOCKER_IMAGE }} .
+ docker push ${{ secrets.SOCKET_DOCKER_REPOSITORY }}/${{ secrets.SOCKET_DOCKER_IMAGE }}
+
+ - name: 🍀 deploy.sh 파일을 EC2 development server로 전달
+ uses: appleboy/scp-action@master
+ with:
+ username: ubuntu
+ host: ${{ secrets.SOCKET_EC2_HOST }}
+ key: ${{ secrets.SOCKET_EC2_KEY }}
+ port: ${{ secrets.SOCKET_EC2_PORT }}
+ source: "./scripts/deploy.sh"
+ target: "/home/ubuntu/"
+
+ - name: 🍀 docker-compose.yml 파일을 EC2 development server로 전달
+ uses: appleboy/scp-action@master
+ with:
+ username: ubuntu
+ host: ${{ secrets.SOCKET_EC2_HOST }}
+ key: ${{ secrets.SOCKET_EC2_KEY }}
+ port: ${{ secrets.SOCKET_EC2_PORT }}
+ source: "./socket/docker-compose.yml"
+ target: "/home/ubuntu/"
+
+ - name: 🍀 docker hub 에서 pull 후 deploy
+ uses: appleboy/ssh-action@master
+ with:
+ username: ubuntu
+ host: ${{ secrets.SOCKET_EC2_HOST }}
+ key: ${{ secrets.SOCKET_EC2_KEY }}
+ script: |
+ sudo docker pull ${{ secrets.SOCKET_DOCKER_REPOSITORY }}/${{ secrets.SOCKET_DOCKER_IMAGE }}
+ chmod 777 ./scripts/deploy.sh
+ cp ./scripts/deploy.sh ./deploy.sh
+ ./deploy.sh
+ docker image prune -f
\ No newline at end of file
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..26d3352
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/.idea/dbnavigator.xml b/.idea/dbnavigator.xml
new file mode 100644
index 0000000..70f212e
--- /dev/null
+++ b/.idea/dbnavigator.xml
@@ -0,0 +1,414 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..9de7d72
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git "a/.idea/\354\213\261\355\201\254.iml" "b/.idea/\354\213\261\355\201\254.iml"
new file mode 100644
index 0000000..d6ebd48
--- /dev/null
+++ "b/.idea/\354\213\261\355\201\254.iml"
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Main/.gitignore b/Main/.gitignore
new file mode 100644
index 0000000..7a5803f
--- /dev/null
+++ b/Main/.gitignore
@@ -0,0 +1,42 @@
+HELP.md
+.gradle
+build/
+!gradle/wrapper/gradle-wrapper.jar
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+bin/
+!**/src/main/**/bin/
+!**/src/test/**/bin/
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+out/
+!**/src/main/**/out/
+!**/src/test/**/out/
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+
+### VS Code ###
+.vscode/
+
+### Yml ###
+**/src/main/resources/application.yml
+### firebase ###
+/src/main/resources/firebase/
\ No newline at end of file
diff --git a/Main/Dockerfile b/Main/Dockerfile
new file mode 100644
index 0000000..a8f336c
--- /dev/null
+++ b/Main/Dockerfile
@@ -0,0 +1,3 @@
+FROM openjdk:17
+COPY build/libs/backendH-0.0.1-SNAPSHOT.jar app.jar
+CMD ["java", "-jar", "app.jar"]
\ No newline at end of file
diff --git a/Main/build.gradle b/Main/build.gradle
new file mode 100644
index 0000000..8d6ad3c
--- /dev/null
+++ b/Main/build.gradle
@@ -0,0 +1,26 @@
+plugins {
+ id 'java'
+ id 'org.springframework.boot' version '3.2.5'
+ id 'io.spring.dependency-management' version '1.1.4'
+}
+
+group = 'com.kusitms29'
+version = '0.0.1-SNAPSHOT'
+
+java {
+ sourceCompatibility = '17'
+}
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ implementation 'org.springframework.boot:spring-boot-starter'
+ testImplementation 'org.springframework.boot:spring-boot-starter-test'
+ testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
+}
+
+tasks.named('test') {
+ useJUnitPlatform()
+}
diff --git a/Main/docker-compose.yml b/Main/docker-compose.yml
new file mode 100644
index 0000000..926dce5
--- /dev/null
+++ b/Main/docker-compose.yml
@@ -0,0 +1,20 @@
+version: '3'
+services:
+ blue:
+ container_name: blue
+ image: kusitms29h/kusitms29h
+ expose:
+ - 8080
+ ports:
+ - 8081:8080
+ environment:
+ - TZ=Asia/Seoul
+ green:
+ container_name: green
+ image: kusitms29h/kusitms29h
+ expose:
+ - 8080
+ ports:
+ - 8082:8080
+ environment:
+ - TZ=Asia/Seoul
\ No newline at end of file
diff --git a/Main/gradle/wrapper/gradle-wrapper.jar b/Main/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..e644113
Binary files /dev/null and b/Main/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/Main/gradle/wrapper/gradle-wrapper.properties b/Main/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..b82aa23
--- /dev/null
+++ b/Main/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,7 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/Main/gradlew b/Main/gradlew
new file mode 100644
index 0000000..1aa94a4
--- /dev/null
+++ b/Main/gradlew
@@ -0,0 +1,249 @@
+#!/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.
+#
+
+##############################################################################
+#
+# 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/subprojects/plugins/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 "${APP_HOME:-./}" > /dev/null && pwd -P ) || 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/Main/gradlew.bat b/Main/gradlew.bat
new file mode 100644
index 0000000..25da30d
--- /dev/null
+++ b/Main/gradlew.bat
@@ -0,0 +1,92 @@
+@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
+
+@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/Main/settings.gradle b/Main/settings.gradle
new file mode 100644
index 0000000..b5f9240
--- /dev/null
+++ b/Main/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = 'backendH'
diff --git a/Main/src/main/java/com/kusitms29/backendH/BackendHApplication.java b/Main/src/main/java/com/kusitms29/backendH/BackendHApplication.java
new file mode 100644
index 0000000..21d6cac
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/BackendHApplication.java
@@ -0,0 +1,13 @@
+package com.kusitms29.backendH;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class BackendHApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(BackendHApplication.class, args);
+ }
+
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/TestController.java b/Main/src/main/java/com/kusitms29/backendH/TestController.java
new file mode 100644
index 0000000..242bd56
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/TestController.java
@@ -0,0 +1,12 @@
+package com.kusitms29.backendH;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class TestController {
+ @GetMapping("/test1")
+ public String test() {
+ return "hello!";
+ }
+}
\ No newline at end of file
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/community/controller/CommunityController.java b/Main/src/main/java/com/kusitms29/backendH/api/community/controller/CommunityController.java
new file mode 100644
index 0000000..d97887c
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/community/controller/CommunityController.java
@@ -0,0 +1,144 @@
+package com.kusitms29.backendH.api.community.controller;
+
+import com.kusitms29.backendH.api.community.service.*;
+import com.kusitms29.backendH.api.community.service.dto.request.CommentCreateRequestDto;
+import com.kusitms29.backendH.api.community.service.dto.request.PostCreateRequestDto;
+import com.kusitms29.backendH.api.community.service.dto.response.*;
+import com.kusitms29.backendH.api.user.service.UserService;
+import com.kusitms29.backendH.global.common.SuccessResponse;
+import com.kusitms29.backendH.infra.config.auth.UserId;
+import com.kusitms29.backendH.infra.external.clova.papago.PapagoService;
+import com.kusitms29.backendH.infra.external.clova.papago.detection.LanguageDetectionRequest;
+import com.kusitms29.backendH.infra.external.clova.papago.detection.LanguageDetectionResponse;
+import com.kusitms29.backendH.infra.external.clova.papago.translation.TextTranslationRequest;
+import com.kusitms29.backendH.infra.external.clova.papago.translation.TextTranslationResponse;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.List;
+
+@RequiredArgsConstructor
+@RequestMapping("/api/community")
+@RestController
+public class CommunityController {
+ private final UserService userService;
+ private final PostService postService;
+ private final PostSearchService postSearchService;
+ private final PostLikeService postLikeService;
+ private final CommentService commentService;
+ private final CommentLikeService commentLikeService;
+ private final ReplyService replyService;
+ private final ReplyLikeService replyLikeService;
+ private final PapagoService papagoService;
+
+ @GetMapping("/banner-image")
+ public ResponseEntity> getLoginUserImage(@UserId Long userId) {
+ BannerImageResponseDto responseDto = userService.getLoginUserImage(userId);
+ return SuccessResponse.ok(responseDto);
+ }
+
+ @GetMapping("/post")
+ public ResponseEntity> getPostByPostType(@UserId Long userId, @RequestParam String postType) {
+ List responseDto = postService.getPostByPostType(userId, postType);
+ return SuccessResponse.ok(responseDto);
+ }
+
+ @GetMapping("/post/{postId}")
+ public ResponseEntity> getDetailPost(@UserId Long userId, @PathVariable Long postId) {
+ PostDetailResponseDto responseDto = postService.getDetailPost(userId, postId);
+ return SuccessResponse.ok(responseDto);
+ }
+
+ @PostMapping("/post")
+ public ResponseEntity> createPost(@UserId Long userId,
+ @RequestPart(required = false) List images,
+ @RequestPart PostCreateRequestDto requestDto) {
+ PostCreateResponseDto responseDto = postService.createPost(userId, images, requestDto);
+ return SuccessResponse.ok(responseDto);
+ }
+
+ @GetMapping("/post/search")
+ public ResponseEntity> searchPost(@UserId Long userId, @RequestParam String keyword) {
+ List responseDtos = postSearchService.searchPosts(userId, keyword);
+ return SuccessResponse.ok(responseDtos);
+ }
+ @PostMapping("/post/like/{postId}")
+ public ResponseEntity> createPostLike(@UserId Long userId, @PathVariable Long postId) {
+ postLikeService.createPostLike(userId, postId);
+ return SuccessResponse.ok(true);
+ }
+ @DeleteMapping("/post/like/{postId}")
+ public ResponseEntity> deletePostLike(@UserId Long userId, @PathVariable Long postId) {
+ postLikeService.deletePostLike(userId, postId);
+ return SuccessResponse.ok(true);
+ }
+
+ @GetMapping("/comment/{postId}")
+ public ResponseEntity> getCommentsInPost(@UserId Long userId, @PathVariable Long postId) {
+ List comments = commentService.getCommentsInPost(userId, postId);
+ return SuccessResponse.ok(comments);
+ }
+ @PostMapping("/comment/{postId}")
+ public ResponseEntity> createComment(@UserId Long userId, @PathVariable Long postId,
+ @RequestBody CommentCreateRequestDto content) {
+ CommentCreateResponseDto commentCreateResponseDto = commentService.createComment(userId, postId, content.getContent());
+ return SuccessResponse.ok(commentCreateResponseDto);
+ }
+ @PostMapping("/comment/like/{commentId}")
+ public ResponseEntity> createCommentLike(@UserId Long userId, @PathVariable Long commentId) {
+ commentLikeService.createCommentLike(userId, commentId);
+ return SuccessResponse.ok(true);
+ }
+
+ @DeleteMapping("/comment/like/{commentId}")
+ public ResponseEntity> deleteCommentLike(@UserId Long userId, @PathVariable Long commentId) {
+ commentLikeService.deleteCommentLike(userId, commentId);
+ return SuccessResponse.ok(true);
+ }
+
+ @PostMapping("/comment/report/{commentId}")
+ public ResponseEntity> reportComment(@UserId Long userId, @PathVariable Long commentId) {
+ int reportedCount = commentService.reportComment(userId, commentId);
+ return SuccessResponse.ok(true);
+ }
+
+ @PostMapping("/reply/{commentId}")
+ public ResponseEntity> createReply(@UserId Long userId, @PathVariable Long commentId,
+ @RequestBody CommentCreateRequestDto requestDto) {
+ ReplyCreateResponseDto responseDto = replyService.createReply(userId, commentId, requestDto.getContent());
+ return SuccessResponse.ok(responseDto);
+ }
+
+ @PostMapping("/reply/like/{replyId}")
+ public ResponseEntity> createReplyLike(@UserId Long userId, @PathVariable Long replyId) {
+ replyLikeService.createReplyLike(userId, replyId);
+ return SuccessResponse.ok(true);
+ }
+
+ @DeleteMapping("/reply/like/{replyId}")
+ public ResponseEntity> deleteReplyLike(@UserId Long userId, @PathVariable Long replyId) {
+ replyLikeService.deleteReplyLike(userId, replyId);
+ return SuccessResponse.ok(true);
+ }
+
+ @PostMapping("/reply/report/{replyId}")
+ public ResponseEntity> reportReply(@UserId Long userId, @PathVariable Long replyId) {
+ int reportedCount = replyService.reportReply(userId, replyId);
+ return SuccessResponse.ok(true);
+ }
+
+ @PostMapping("/translate")
+ public ResponseEntity> translateText(@RequestBody TextTranslationRequest requestDto) {
+ TextTranslationResponse responseDto = papagoService.translateText(requestDto);
+ return SuccessResponse.ok(responseDto.getMessage().getResult());
+ }
+
+ @PostMapping("/check-language")
+ public ResponseEntity> whatLanguageIsIt(@RequestBody LanguageDetectionRequest requestDto) {
+ LanguageDetectionResponse responseDto = papagoService.checkLanguage(requestDto);
+ return SuccessResponse.ok(responseDto);
+ }
+
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/community/service/CommentLikeService.java b/Main/src/main/java/com/kusitms29/backendH/api/community/service/CommentLikeService.java
new file mode 100644
index 0000000..13d8e18
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/community/service/CommentLikeService.java
@@ -0,0 +1,50 @@
+package com.kusitms29.backendH.api.community.service;
+
+import com.kusitms29.backendH.domain.comment.entity.Comment;
+import com.kusitms29.backendH.domain.comment.entity.CommentLike;
+import com.kusitms29.backendH.domain.comment.service.CommentLikeModifier;
+import com.kusitms29.backendH.domain.comment.service.CommentLikeReader;
+import com.kusitms29.backendH.domain.comment.service.CommentReader;
+import com.kusitms29.backendH.domain.user.entity.User;
+import com.kusitms29.backendH.domain.user.service.UserReader;
+import com.kusitms29.backendH.global.error.exception.ConflictException;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import static com.kusitms29.backendH.global.error.ErrorCode.*;
+
+@Slf4j
+@RequiredArgsConstructor
+@Transactional
+@Service
+public class CommentLikeService {
+ private final UserReader userReader;
+ private final CommentReader commentReader;
+ private final CommentLikeReader commentLikeReader;
+ private final CommentLikeModifier commentLikeModifier;
+
+ public void createCommentLike(Long userId, Long commentId) {
+ User user = userReader.findByUserId(userId);
+ Comment comment = commentReader.findById(commentId);
+
+ if(commentLikeReader.existsByCommentIdAndUserId(commentId, userId)) {
+ throw new ConflictException(DUPLICATE_COMMENT_LIKE);
+ }
+
+ commentLikeModifier.save
+ (CommentLike.builder()
+ .user(user)
+ .comment(comment)
+ .build());
+ }
+
+ public void deleteCommentLike(Long userId, Long commentId) {
+ User user = userReader.findByUserId(userId);
+ Comment comment = commentReader.findById(commentId);
+ CommentLike commentLike = commentLikeReader.findByCommentIdAndUserId(commentId, userId);
+ commentLikeModifier.delete(commentLike);
+ }
+
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/community/service/CommentService.java b/Main/src/main/java/com/kusitms29/backendH/api/community/service/CommentService.java
new file mode 100644
index 0000000..49a93fb
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/community/service/CommentService.java
@@ -0,0 +1,145 @@
+package com.kusitms29.backendH.api.community.service;
+
+import com.kusitms29.backendH.api.community.service.dto.response.CommentCreateResponseDto;
+import com.kusitms29.backendH.api.community.service.dto.response.CommentResponseDto;
+import com.kusitms29.backendH.api.community.service.dto.response.ReplyResponseDto;
+import com.kusitms29.backendH.domain.comment.entity.Comment;
+import com.kusitms29.backendH.domain.comment.entity.Reply;
+import com.kusitms29.backendH.domain.comment.service.*;
+import com.kusitms29.backendH.domain.post.entity.Post;
+import com.kusitms29.backendH.domain.post.service.PostReader;
+import com.kusitms29.backendH.domain.user.entity.User;
+import com.kusitms29.backendH.domain.user.service.UserReader;
+import com.kusitms29.backendH.global.common.TimeCalculator;
+import com.kusitms29.backendH.global.error.exception.NotAllowedException;
+import com.kusitms29.backendH.infra.external.fcm.service.PushNotificationService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.hibernate.Hibernate;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static com.kusitms29.backendH.global.error.ErrorCode.*;
+
+@Slf4j
+@RequiredArgsConstructor
+@Transactional
+@Service
+public class CommentService {
+ private final CommentReader commentReader;
+ private final CommentLikeReader commentLikeReader;
+ private final CommentLikeManager commentLikeManager;
+ private final CommentLikeModifier commentLikeModifier;
+ private final PostReader postReader;
+ private final UserReader userReader;
+ private final CommentModifier commentModifier;
+ private final ReplyReader replyReader;
+ private final ReplyModifier replyModifier;
+ private final ReplyLikeReader replyLikeReader;
+ private final ReplyLikeManager replyLikeManager;
+ private final ReplyLikeModifier replyLikeModifier;
+ private final PushNotificationService pushNotificationService;
+
+ public List getCommentsInPost(Long userId, Long postId) {
+ List comments = commentReader.findByPostId(postId);
+ return comments.stream()
+ .map(comment -> mapToCommentResponseDto(comment, userId))
+ .collect(Collectors.toList());
+ }
+
+ private CommentResponseDto mapToCommentResponseDto(Comment comment, Long userId) {
+ User user = userReader.findByUserId(userId);
+ int commentLikeCnt = commentLikeManager.countByCommentId(comment.getId());
+
+ boolean isLikedByUser = commentLikeReader.findByCommentId(comment.getId())
+ .stream()
+ .anyMatch(commentLike -> commentLike.getUser().getId() == userId);
+
+ boolean isCommentedByUser = comment.getUser().getId() == userId;
+
+ List replyList = replyReader.findByCommentId(comment.getId());
+ List replyResponseDto = replyList.stream()
+ .map(reply ->
+ ReplyResponseDto.builder()
+ .replyId(reply.getId())
+ .writerImage(reply.getUser().getProfile())
+ .writerName(reply.getUser().getUserName())
+ .createdDate(TimeCalculator.calculateTimeDifference(reply.getCreatedAt()))
+ .content(reply.getContent())
+ .likeCnt(replyLikeManager.countByReplyId(reply.getId()))
+ .isLikedByUser(replyLikeReader.findByReplyId(reply.getId())
+ .stream().anyMatch(replyLike -> replyLike.getUser().getId() == userId))
+ .isRepliedByUser(reply.getUser().getId() == userId)
+ .reportedCnt(reply.getReported())
+ .build())
+ .collect(Collectors.toList());
+
+ return CommentResponseDto.of(
+ comment.getId(),
+ comment.getUser().getProfile(),
+ comment.getUser().getUserName(),
+ comment.getCreatedAt(),
+ comment.getContent(),
+ commentLikeCnt,
+ isLikedByUser,
+ comment.getReported(),
+ isCommentedByUser,
+ replyResponseDto
+ );
+ }
+
+ public CommentCreateResponseDto createComment(Long userId, Long postId, String content) {
+ Post post = postReader.findById(postId);
+ User writer = userReader.findByUserId(userId);
+
+ if(content.length() > 30) {
+ throw new NotAllowedException(TOO_LONG_COMMENT_NOT_ALLOWED);
+ }
+
+ Comment newComment = commentModifier.save
+ (Comment.builder()
+ .post(post)
+ .user(writer)
+ .content(content)
+ .build());
+
+ pushNotificationService.sendCommentNotification(postId, newComment);
+
+ return CommentCreateResponseDto.of(
+ newComment.getId(),
+ newComment.getUser().getProfile(),
+ newComment.getUser().getUserName(),
+ newComment.getCreatedAt(),
+ newComment.getContent(),
+ newComment.getUser().getId() == userId
+ );
+ }
+
+ public int reportComment(Long userId, Long commentId) {
+ Comment comment = commentReader.findById(commentId);
+ User user = userReader.findByUserId(userId);
+
+ if(comment.getReported() >= 2) {
+ List replyList = replyReader.findByCommentId(commentId);
+ for(Reply reply : replyList) {
+ //대댓글좋아요 삭제
+ replyLikeModifier.deleteAllByReplyId(reply.getId());
+ }
+ //대댓글 삭제
+ replyModifier.deleteAllByCommentId(commentId);
+ //댓글 좋아요 삭제
+ commentLikeModifier.deleteAllByCommentId(commentId);
+ commentModifier.delete(comment);
+ return 3;
+ }
+
+ commentModifier.increaseReportedCount(commentId);
+ return comment.getReported();
+ }
+
+
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/community/service/PostLikeService.java b/Main/src/main/java/com/kusitms29/backendH/api/community/service/PostLikeService.java
new file mode 100644
index 0000000..ab123e5
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/community/service/PostLikeService.java
@@ -0,0 +1,52 @@
+package com.kusitms29.backendH.api.community.service;
+
+import com.kusitms29.backendH.domain.post.entity.Post;
+import com.kusitms29.backendH.domain.post.entity.PostLike;
+import com.kusitms29.backendH.domain.post.service.*;
+import com.kusitms29.backendH.domain.user.entity.User;
+import com.kusitms29.backendH.domain.user.service.UserReader;
+import com.kusitms29.backendH.global.error.exception.ConflictException;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import static com.kusitms29.backendH.global.error.ErrorCode.*;
+
+@Slf4j
+@RequiredArgsConstructor
+@Transactional
+@Service
+public class PostLikeService {
+ private final UserReader userReader;
+ private final PostReader postReader;
+ private final PostLikeManager postLikeManager;
+ private final PostLikeAppender postLikeAppender;
+ private final PostLikeReader postLikeReader;
+ private final PostLikeModifier postLikeModifier;
+
+ public void createPostLike(Long userId, Long postId) {
+ User user = userReader.findByUserId(userId);
+ Post post = postReader.findById(postId);
+
+ if(postLikeManager.existsByPostIdAndUserId(postId, userId)) {
+ throw new ConflictException(DUPLICATE_POST_LIKE);
+ }
+
+ postLikeAppender.save(
+ PostLike.builder()
+ .user(user)
+ .post(post)
+ .build()
+ );
+ }
+
+ public void deletePostLike(Long userId, Long postId) {
+ User user = userReader.findByUserId(userId);
+ Post post = postReader.findById(postId);
+ PostLike postLike = postLikeReader.findByPostIdAndUserId(postId, userId);
+
+
+ postLikeModifier.delete(postLike);
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/community/service/PostSearchService.java b/Main/src/main/java/com/kusitms29/backendH/api/community/service/PostSearchService.java
new file mode 100644
index 0000000..d0e43e1
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/community/service/PostSearchService.java
@@ -0,0 +1,63 @@
+package com.kusitms29.backendH.api.community.service;
+
+
+import com.kusitms29.backendH.api.community.service.dto.request.PostCalculateDto;
+import com.kusitms29.backendH.api.community.service.dto.response.PostSearchResponseDto;
+import com.kusitms29.backendH.domain.post.entity.Post;
+import com.kusitms29.backendH.domain.post.entity.PostImage;
+import com.kusitms29.backendH.domain.post.service.PostImageReader;
+import com.kusitms29.backendH.domain.post.service.PostReader;
+import com.kusitms29.backendH.domain.user.entity.User;
+import com.kusitms29.backendH.domain.user.service.UserReader;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+@Slf4j
+@RequiredArgsConstructor
+@Transactional
+@Service
+public class PostSearchService {
+ private final UserReader userReader;
+ private final PostReader postReader;
+ private final PostImageReader postImageReader;
+ private final PostService postService;
+
+ public List searchPosts(Long userId, String keyword) {
+ User user = userReader.findByUserId(userId);
+
+ if(keyword == null || keyword.isEmpty()) {
+ return new ArrayList<>();
+ }
+
+ List posts = postReader.searchByTitleOrContent(keyword);
+ return posts.stream()
+ .map(post -> {
+ PostCalculateDto postCalculateDto = postService.calculatePostDetail(post, user.getId());
+ PostImage postImage = postImageReader.findByPostIdAndIsRepresentative(post.getId(), true);
+
+ return PostSearchResponseDto.of(
+ post.getId(),
+ post.getPostType().getStringPostType(),
+ post.getUser().getProfile(),
+ post.getUser().getUserName(),
+ post.getCreatedAt(),
+ post.getTitle(),
+ post.getContent(),
+ (postImage != null) ? postImage.getImage_url() : null,
+ postCalculateDto.getLikeCount(),
+ postCalculateDto.isLikedByUser(),
+ postCalculateDto.getCommentCount(),
+ postCalculateDto.isPostedByUser()
+ );
+ })
+ .collect(Collectors.toList());
+ }
+
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/community/service/PostService.java b/Main/src/main/java/com/kusitms29/backendH/api/community/service/PostService.java
new file mode 100644
index 0000000..608ea51
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/community/service/PostService.java
@@ -0,0 +1,160 @@
+package com.kusitms29.backendH.api.community.service;
+
+import com.kusitms29.backendH.api.community.service.dto.request.PostCalculateDto;
+import com.kusitms29.backendH.api.community.service.dto.request.PostCreateRequestDto;
+import com.kusitms29.backendH.api.community.service.dto.response.PostCreateResponseDto;
+import com.kusitms29.backendH.api.community.service.dto.response.PostDetailResponseDto;
+import com.kusitms29.backendH.api.community.service.dto.response.PostResponseDto;
+import com.kusitms29.backendH.domain.comment.service.CommentManager;
+import com.kusitms29.backendH.domain.comment.service.CommentReader;
+import com.kusitms29.backendH.domain.comment.service.ReplyManager;
+import com.kusitms29.backendH.domain.post.entity.Post;
+import com.kusitms29.backendH.domain.post.entity.PostImage;
+import com.kusitms29.backendH.domain.post.entity.PostType;
+import com.kusitms29.backendH.domain.post.service.*;
+import com.kusitms29.backendH.domain.user.entity.User;
+import com.kusitms29.backendH.domain.user.service.UserReader;
+import com.kusitms29.backendH.global.error.exception.NotAllowedException;
+import com.kusitms29.backendH.infra.config.AwsS3Service;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.Comparator;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static com.kusitms29.backendH.global.error.ErrorCode.*;
+
+@Slf4j
+@RequiredArgsConstructor
+@Transactional
+@Service
+public class PostService {
+ private final AwsS3Service awsS3Service;
+ private final PostReader postReader;
+ private final PostLikeManager postLikeManager;
+ private final CommentManager commentManager;
+ private final CommentReader commentReader;
+ private final ReplyManager replyManager;
+ private final PostImageReader postImageReader;
+ private final UserReader userReader;
+ private final PostAppender postAppender;
+ private final PostImageAppender postImageAppender;
+
+ public List getPostByPostType(Long userId, String postType) {
+ PostType enumPostType = PostType.getEnumPostTypeFromStringPostType(postType);
+ List posts = postReader.findByPostType(enumPostType);
+
+ posts.sort(Comparator.comparing(Post :: getCreatedAt).reversed());
+
+ return posts.stream()
+ .map(post -> mapToPostResponseDto(post, userId))
+ .collect(Collectors.toList());
+ }
+
+ private PostResponseDto mapToPostResponseDto(Post post, Long userId) {
+ PostCalculateDto postCalculateDto = calculatePostDetail(post, userId);
+ PostImage postImage = postImageReader.findByPostIdAndIsRepresentative(post.getId(), true);
+
+ return PostResponseDto.of(
+ post.getId(),
+ post.getPostType().getStringPostType(),
+ post.getUser().getProfile(),
+ post.getUser().getUserName(),
+ post.getCreatedAt(),
+ post.getTitle(),
+ post.getContent(),
+ (postImage != null) ? postImage.getImage_url() : null,
+ postCalculateDto.getLikeCount(),
+ postCalculateDto.isLikedByUser(),
+ postCalculateDto.getCommentCount(),
+ postCalculateDto.isPostedByUser()
+ );
+ }
+
+ public PostDetailResponseDto getDetailPost(Long userId, Long postId) {
+ Post post = postReader.findById(postId);
+ PostCalculateDto postCalculateDto = calculatePostDetail(post, userId);
+
+ List imageUrls = postImageReader.findByPostId(post.getId())
+ .stream()
+ .map(PostImage::getImage_url)
+ .collect(Collectors.toList());
+
+ return PostDetailResponseDto.of(
+ post.getPostType().getStringPostType(),
+ post.getUser().getProfile(),
+ post.getUser().getUserName(),
+ post.getCreatedAt(),
+ post.getTitle(),
+ post.getContent(),
+ postCalculateDto.getLikeCount(),
+ postCalculateDto.isLikedByUser(),
+ postCalculateDto.getCommentCount(),
+ postCalculateDto.isPostedByUser(),
+ imageUrls
+ );
+ }
+
+ public PostCalculateDto calculatePostDetail(Post post, Long userId) {
+ int likeCount = postLikeManager.countByPostId(post.getId());
+ boolean isLikedByUser = postLikeManager.existsByPostIdAndUserId(post.getId(), userId);
+
+ int totalCommentCount = commentManager.countByPostId(post.getId());
+ int replyCount = commentReader.findByPostId(post.getId()).stream()
+ .mapToInt(comment -> replyManager.countByCommentId(comment.getId()))
+ .sum();
+ totalCommentCount += replyCount;
+
+ boolean isPostedByUser = post.getUser().getId() == userId;
+ return new PostCalculateDto(likeCount, isLikedByUser, totalCommentCount, isPostedByUser);
+ }
+
+ public PostCreateResponseDto createPost(Long userId, List images, PostCreateRequestDto requestDto) {
+ User writer = userReader.findByUserId(userId);
+ PostType postType = PostType.getEnumPostTypeFromStringPostType(requestDto.getPostType());
+
+ String title = requestDto.getTitle();
+ String content = requestDto.getContent();
+ if(title.length() > 30) {
+ throw new NotAllowedException(TOO_LONG_TITLE_NOT_ALLOWED);
+ }
+ if(content.length() > 300) {
+ throw new NotAllowedException(TOO_LONG_CONTENT_NOT_ALLOWED);
+ }
+ if(images != null && !images.isEmpty() && images.size() > 5) {
+ throw new NotAllowedException(TOO_MANY_IMAGES_NOT_ALLOWED);
+ }
+
+ Post newPost = postAppender.save
+ (Post.builder()
+ .user(writer)
+ .postType(postType)
+ .title(requestDto.getTitle())
+ .content(requestDto.getContent())
+ .build());
+
+ List imageUrls = null;
+ if(images != null && !images.isEmpty()) {
+ imageUrls = awsS3Service.uploadImages(images);
+ for(int i=0; i= 2) {
+ replyLikeModifier.deleteAllByReplyId(replyId);
+ replyModifier.delete(reply);
+ return 3;
+ }
+
+ replyModifier.increaseReportedCount(replyId);
+ return reply.getReported();
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/community/service/dto/request/CommentCreateRequestDto.java b/Main/src/main/java/com/kusitms29/backendH/api/community/service/dto/request/CommentCreateRequestDto.java
new file mode 100644
index 0000000..8fdb7ec
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/community/service/dto/request/CommentCreateRequestDto.java
@@ -0,0 +1,12 @@
+package com.kusitms29.backendH.api.community.service.dto.request;
+
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@Getter
+public class CommentCreateRequestDto {
+ private String content;
+}
+
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/community/service/dto/request/PostCalculateDto.java b/Main/src/main/java/com/kusitms29/backendH/api/community/service/dto/request/PostCalculateDto.java
new file mode 100644
index 0000000..745f443
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/community/service/dto/request/PostCalculateDto.java
@@ -0,0 +1,13 @@
+package com.kusitms29.backendH.api.community.service.dto.request;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@AllArgsConstructor
+@Getter
+public class PostCalculateDto {
+ private int likeCount;
+ private boolean isLikedByUser;
+ private int commentCount;
+ private boolean isPostedByUser;
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/community/service/dto/request/PostCreateRequestDto.java b/Main/src/main/java/com/kusitms29/backendH/api/community/service/dto/request/PostCreateRequestDto.java
new file mode 100644
index 0000000..3d7eb4e
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/community/service/dto/request/PostCreateRequestDto.java
@@ -0,0 +1,13 @@
+package com.kusitms29.backendH.api.community.service.dto.request;
+
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@Getter
+public class PostCreateRequestDto {
+ private String postType;
+ private String title;
+ private String content;
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/community/service/dto/response/BannerImageResponseDto.java b/Main/src/main/java/com/kusitms29/backendH/api/community/service/dto/response/BannerImageResponseDto.java
new file mode 100644
index 0000000..952995a
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/community/service/dto/response/BannerImageResponseDto.java
@@ -0,0 +1,16 @@
+package com.kusitms29.backendH.api.community.service.dto.response;
+
+import lombok.Builder;
+import lombok.Getter;
+
+@Builder
+@Getter
+public class BannerImageResponseDto {
+ String image;
+
+ public static BannerImageResponseDto of(String image) {
+ return BannerImageResponseDto.builder()
+ .image(image)
+ .build();
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/community/service/dto/response/CommentCreateResponseDto.java b/Main/src/main/java/com/kusitms29/backendH/api/community/service/dto/response/CommentCreateResponseDto.java
new file mode 100644
index 0000000..dd80b87
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/community/service/dto/response/CommentCreateResponseDto.java
@@ -0,0 +1,31 @@
+package com.kusitms29.backendH.api.community.service.dto.response;
+
+import com.kusitms29.backendH.global.common.TimeCalculator;
+import lombok.Builder;
+import lombok.Getter;
+
+import java.time.LocalDateTime;
+
+@Builder
+@Getter
+public class CommentCreateResponseDto {
+ private Long commentId;
+ private String writerImage;
+ private String writerName;
+ private String createdDate;
+ private String content;
+ private boolean isCommentedByUser;
+
+ public static CommentCreateResponseDto of(Long commentId, String writerImage, String writerName,
+ LocalDateTime createdDate, String content, boolean isCommentedByUser) {
+
+ return CommentCreateResponseDto.builder()
+ .commentId(commentId)
+ .writerImage(writerImage)
+ .writerName(writerName)
+ .createdDate(TimeCalculator.calculateTimeDifference(createdDate))
+ .content(content)
+ .isCommentedByUser(isCommentedByUser)
+ .build();
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/community/service/dto/response/CommentResponseDto.java b/Main/src/main/java/com/kusitms29/backendH/api/community/service/dto/response/CommentResponseDto.java
new file mode 100644
index 0000000..da02964
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/community/service/dto/response/CommentResponseDto.java
@@ -0,0 +1,42 @@
+package com.kusitms29.backendH.api.community.service.dto.response;
+
+import com.kusitms29.backendH.global.common.TimeCalculator;
+import lombok.Builder;
+import lombok.Getter;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Builder
+@Getter
+public class CommentResponseDto {
+ private Long commentId;
+ private String writerImage;
+ private String writerName;
+ private String createdDate;
+ private String content;
+ private int likeCnt;
+ private boolean isLikedByUser;
+ private int reportedCnt;
+ private boolean isCommentedByUser;
+ private List replyList;
+
+ public static CommentResponseDto of(Long commentId, String writerImage, String writerName,
+ LocalDateTime createdDate, String content, int likeCnt,
+ boolean isLikedByUser, int reportedCnt, Boolean isCommentedByUser,
+ List replyList) {
+
+ return CommentResponseDto.builder()
+ .commentId(commentId)
+ .writerImage(writerImage)
+ .writerName(writerName)
+ .createdDate(TimeCalculator.calculateTimeDifference(createdDate))
+ .content(content)
+ .likeCnt(likeCnt)
+ .isLikedByUser(isLikedByUser)
+ .reportedCnt(reportedCnt)
+ .isCommentedByUser(isCommentedByUser)
+ .replyList(replyList)
+ .build();
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/community/service/dto/response/PostCreateResponseDto.java b/Main/src/main/java/com/kusitms29/backendH/api/community/service/dto/response/PostCreateResponseDto.java
new file mode 100644
index 0000000..68856b5
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/community/service/dto/response/PostCreateResponseDto.java
@@ -0,0 +1,25 @@
+package com.kusitms29.backendH.api.community.service.dto.response;
+
+import lombok.Builder;
+import lombok.Getter;
+
+import java.util.List;
+
+@Builder
+@Getter
+public class PostCreateResponseDto {
+ private String postType;
+ private String title;
+ private String content;
+ private List imageUrls;
+
+ public static PostCreateResponseDto of(String postType, String title,
+ String content, List imageUrls) {
+ return PostCreateResponseDto.builder()
+ .postType(postType)
+ .title(title)
+ .content(content)
+ .imageUrls(imageUrls)
+ .build();
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/community/service/dto/response/PostDetailResponseDto.java b/Main/src/main/java/com/kusitms29/backendH/api/community/service/dto/response/PostDetailResponseDto.java
new file mode 100644
index 0000000..c5b7751
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/community/service/dto/response/PostDetailResponseDto.java
@@ -0,0 +1,45 @@
+package com.kusitms29.backendH.api.community.service.dto.response;
+
+import com.kusitms29.backendH.global.common.TimeCalculator;
+import lombok.Builder;
+import lombok.Getter;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Builder
+@Getter
+public class PostDetailResponseDto {
+ private String postType;
+ private String writerImage;
+ private String writerName;
+ private String createdDate;
+ private String title;
+ private String content;
+ private int likeCnt;
+ private boolean isLikedByUser;
+ private int commentCnt;
+ private boolean isPostedByUser;
+ private List imageUrls;
+
+ public static PostDetailResponseDto of(String postType, String writerImage, String writerName,
+ LocalDateTime createdDate, String title, String content,
+ int likeCnt, boolean isLikedByUser, int commentCnt, boolean isPostedByUser,
+ List imageUrls) {
+ return PostDetailResponseDto.builder()
+ .postType(postType)
+ .writerImage(writerImage)
+ .writerName(writerName)
+ .createdDate(TimeCalculator.calculateTimeDifference(createdDate))
+ .title(title)
+ .content(content)
+ .likeCnt(likeCnt)
+ .isLikedByUser(isLikedByUser)
+ .commentCnt(commentCnt)
+ .isPostedByUser(isPostedByUser)
+ .imageUrls(imageUrls)
+ .build();
+ }
+
+
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/community/service/dto/response/PostResponseDto.java b/Main/src/main/java/com/kusitms29/backendH/api/community/service/dto/response/PostResponseDto.java
new file mode 100644
index 0000000..b02a145
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/community/service/dto/response/PostResponseDto.java
@@ -0,0 +1,44 @@
+package com.kusitms29.backendH.api.community.service.dto.response;
+
+import com.kusitms29.backendH.global.common.TimeCalculator;
+import lombok.Builder;
+import lombok.Getter;
+
+import java.time.Duration;
+import java.time.LocalDateTime;
+
+@Builder
+@Getter
+public class PostResponseDto {
+ private long postId;
+ private String postType;
+ private String writerImage;
+ private String writerName;
+ private String createdDate;
+ private String title;
+ private String content;
+ private String representativeImage;
+ private int likeCnt;
+ private boolean isLikedByUser;
+ private int commentCnt;
+ private boolean isPostedByUser;
+
+ public static PostResponseDto of(Long postId, String postType, String writerImage, String writerName,
+ LocalDateTime createdDate, String title, String content, String representativeImage,
+ int likeCnt, boolean isLikedByUser, int commentCnt, boolean isPostedByUser) {
+ return PostResponseDto.builder()
+ .postId(postId)
+ .postType(postType)
+ .writerImage(writerImage)
+ .writerName(writerName)
+ .createdDate(TimeCalculator.calculateTimeDifference(createdDate))
+ .title(title)
+ .content(content)
+ .representativeImage(representativeImage)
+ .likeCnt(likeCnt)
+ .isLikedByUser(isLikedByUser)
+ .commentCnt(commentCnt)
+ .isPostedByUser(isPostedByUser)
+ .build();
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/community/service/dto/response/PostSearchResponseDto.java b/Main/src/main/java/com/kusitms29/backendH/api/community/service/dto/response/PostSearchResponseDto.java
new file mode 100644
index 0000000..316fcad
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/community/service/dto/response/PostSearchResponseDto.java
@@ -0,0 +1,43 @@
+package com.kusitms29.backendH.api.community.service.dto.response;
+
+import com.kusitms29.backendH.global.common.TimeCalculator;
+import lombok.Builder;
+import lombok.Getter;
+
+import java.time.LocalDateTime;
+
+@Builder
+@Getter
+public class PostSearchResponseDto {
+ private Long postId;
+ private String postType;
+ private String writerImage;
+ private String writerName;
+ private String createdDate;
+ private String title;
+ private String content;
+ private String representativeImage;
+ private int likeCnt;
+ private boolean isLikedByUser;
+ private int commentCnt;
+ private boolean isPostedByUser;
+
+ public static PostSearchResponseDto of(Long postId, String postType, String writerImage, String writerName, LocalDateTime createdDate,
+ String title, String content, String representativeImage,
+ int likeCnt, boolean isLikedByUser, int commentCnt, boolean isPostedByUser) {
+ return PostSearchResponseDto.builder()
+ .postId(postId)
+ .postType(postType)
+ .writerImage(writerImage)
+ .writerName(writerName)
+ .createdDate(TimeCalculator.calculateTimeDifference(createdDate))
+ .title(title)
+ .content(content)
+ .representativeImage(representativeImage)
+ .likeCnt(likeCnt)
+ .isLikedByUser(isLikedByUser)
+ .commentCnt(commentCnt)
+ .isPostedByUser(isPostedByUser)
+ .build();
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/community/service/dto/response/ReplyCreateResponseDto.java b/Main/src/main/java/com/kusitms29/backendH/api/community/service/dto/response/ReplyCreateResponseDto.java
new file mode 100644
index 0000000..472f8d5
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/community/service/dto/response/ReplyCreateResponseDto.java
@@ -0,0 +1,31 @@
+package com.kusitms29.backendH.api.community.service.dto.response;
+
+import com.kusitms29.backendH.global.common.TimeCalculator;
+import lombok.Builder;
+import lombok.Getter;
+
+import java.time.LocalDateTime;
+
+@Builder
+@Getter
+public class ReplyCreateResponseDto {
+ private Long replyId;
+ private String writerImage;
+ private String writerName;
+ private String createdDate;
+ private String content;
+ private boolean isRepliedByUser;
+
+ public static ReplyCreateResponseDto of(Long commentId, String writerImage, String writerName,
+ LocalDateTime createdDate, String content, boolean isRepliedByUser) {
+
+ return ReplyCreateResponseDto.builder()
+ .replyId(commentId)
+ .writerImage(writerImage)
+ .writerName(writerName)
+ .createdDate(TimeCalculator.calculateTimeDifference(createdDate))
+ .content(content)
+ .isRepliedByUser(isRepliedByUser)
+ .build();
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/community/service/dto/response/ReplyResponseDto.java b/Main/src/main/java/com/kusitms29/backendH/api/community/service/dto/response/ReplyResponseDto.java
new file mode 100644
index 0000000..bc542de
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/community/service/dto/response/ReplyResponseDto.java
@@ -0,0 +1,38 @@
+package com.kusitms29.backendH.api.community.service.dto.response;
+
+import com.kusitms29.backendH.global.common.TimeCalculator;
+import lombok.Builder;
+import lombok.Getter;
+
+import java.time.LocalDateTime;
+
+@Builder
+@Getter
+public class ReplyResponseDto {
+ private Long replyId;
+ private String writerImage;
+ private String writerName;
+ private String createdDate;
+ private String content;
+ private int likeCnt;
+ private boolean isLikedByUser;
+ private int reportedCnt;
+ private boolean isRepliedByUser;
+
+ public static ReplyResponseDto of(Long replyId, String writerImage, String writerName,
+ LocalDateTime createdDate, String content,
+ int likeCnt, boolean isLikedByUser, int reportedCnt, boolean isRepliedByUser) {
+ return ReplyResponseDto.builder()
+ .replyId(replyId)
+ .writerImage(writerImage)
+ .writerName(writerName)
+ .createdDate(TimeCalculator.calculateTimeDifference(createdDate))
+ .content(content)
+ .likeCnt(likeCnt)
+ .isLikedByUser(isLikedByUser)
+ .reportedCnt(reportedCnt)
+ .isRepliedByUser(isRepliedByUser)
+ .build();
+ }
+
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/notification/controller/NotificationHistoryController.java b/Main/src/main/java/com/kusitms29/backendH/api/notification/controller/NotificationHistoryController.java
new file mode 100644
index 0000000..9803f2b
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/notification/controller/NotificationHistoryController.java
@@ -0,0 +1,29 @@
+package com.kusitms29.backendH.api.notification.controller;
+
+import com.kusitms29.backendH.api.notification.service.NotificationHistoryService;
+import com.kusitms29.backendH.api.notification.service.dto.NotificationHistoryResponseDto;
+import com.kusitms29.backendH.global.common.SuccessResponse;
+import com.kusitms29.backendH.infra.config.auth.UserId;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+@RequiredArgsConstructor
+@RequestMapping("/api/notification")
+@RestController
+public class NotificationHistoryController {
+
+ private final NotificationHistoryService notificationHistoryService;
+
+ @GetMapping
+ public ResponseEntity> getNotificationByTopCategory(@UserId Long userId, @RequestParam String topCategory) {
+ List responseDto = notificationHistoryService.getNotificationByTopCategory(userId, topCategory);
+ return SuccessResponse.ok(responseDto);
+ }
+
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/notification/service/NotificationHistoryService.java b/Main/src/main/java/com/kusitms29/backendH/api/notification/service/NotificationHistoryService.java
new file mode 100644
index 0000000..b38f9a3
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/notification/service/NotificationHistoryService.java
@@ -0,0 +1,72 @@
+package com.kusitms29.backendH.api.notification.service;
+
+import com.kusitms29.backendH.api.notification.service.dto.NotificationHistoryResponseDto;
+import com.kusitms29.backendH.domain.comment.service.CommentReader;
+import com.kusitms29.backendH.domain.notification.entity.NotificationHistory;
+import com.kusitms29.backendH.domain.notification.entity.TopCategory;
+import com.kusitms29.backendH.domain.notification.service.NotificationHistoryReader;
+import com.kusitms29.backendH.global.error.exception.InvalidValueException;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.util.Comparator;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static com.kusitms29.backendH.global.error.ErrorCode.INVALID_NOTIFICATION_TYPE;
+
+@Service
+@RequiredArgsConstructor
+public class NotificationHistoryService {
+
+ private final NotificationHistoryReader notificationHistoryReader;
+ private final CommentReader commentReader;
+
+ public List getNotificationByTopCategory(Long userId, String topCategory) {
+ TopCategory enumTopCategory = TopCategory.getEnumTopCategoryFromStringTopCategory(topCategory);
+ List notificationHistories = notificationHistoryReader.findByTopCategoryAndUserId(enumTopCategory, userId);
+
+ notificationHistories.sort(Comparator.comparing(NotificationHistory :: getSentAt).reversed());
+
+ return notificationHistories.stream()
+ .map(this::mapToNotificationHistoryResponseDto)
+ .collect(Collectors.toList());
+ }
+
+ private NotificationHistoryResponseDto mapToNotificationHistoryResponseDto(NotificationHistory notificationHistory) {
+ String detailContent = "";
+
+ switch (notificationHistory.getNotificationType().name()) {
+ case "CHAT":
+ detailContent = notificationHistory.getInfoId2();
+ break;
+ case "CHAT_ROOM_NOTICE":
+ detailContent = "지금 바로 채팅방에 입장해서 멤버들과 대화를 나눠보세요!";
+ break;
+ case "COMMENT":
+ Long infoId2 = ((notificationHistory.getInfoId2() != null)&&(!notificationHistory.getInfoId2().isEmpty()) ? Long.parseLong(notificationHistory.getInfoId2()) : null);
+ detailContent = commentReader.findById(infoId2).getContent();
+ break;
+ case "SYNC_REMINDER":
+ detailContent = "즐거운 싱크되세요!";
+ break;
+ case "REVIEW":
+ detailContent = "생생한 리뷰를 남겨보세요";
+ break;
+ default:
+ throw new InvalidValueException(INVALID_NOTIFICATION_TYPE);
+ }
+
+ return NotificationHistoryResponseDto.of(
+ notificationHistory.getInfoId(),
+ notificationHistory.getTitle(),
+ notificationHistory.getBody(),
+ detailContent,
+ notificationHistory.getSentAt()
+ );
+ }
+
+
+
+
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/notification/service/NotificationService.java b/Main/src/main/java/com/kusitms29/backendH/api/notification/service/NotificationService.java
new file mode 100644
index 0000000..5157521
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/notification/service/NotificationService.java
@@ -0,0 +1,36 @@
+package com.kusitms29.backendH.api.notification.service;
+
+import com.kusitms29.backendH.domain.notification.entity.NotificationSetting;
+import com.kusitms29.backendH.domain.notification.entity.NotificationType;
+import com.kusitms29.backendH.domain.notification.repository.NotificationRepository;
+import com.kusitms29.backendH.domain.user.entity.User;
+import com.kusitms29.backendH.global.error.exception.EntityNotFoundException;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import static com.kusitms29.backendH.global.error.ErrorCode.NOTIFICATION_NOT_FOUND;
+
+@Service
+@RequiredArgsConstructor
+public class NotificationService {
+ private final NotificationRepository notificationRepository;
+ @Transactional
+ public void createNotificationSetting(User user) {
+ for(NotificationType type : NotificationType.values()) {
+ NotificationSetting notificationSetting = NotificationSetting.builder()
+ .user(user)
+ .notificationType(type)
+ .build();
+ notificationRepository.save(notificationSetting);
+ }
+ }
+
+ public void updateSettingActive(User user, NotificationType type) {
+ NotificationSetting notificationSetting = notificationRepository.findByUserAndNotificationType(user, type)
+ .orElseThrow(() -> new EntityNotFoundException(NOTIFICATION_NOT_FOUND));
+ notificationSetting.setStatus(NotificationSetting.Status.ACTIVE);
+ notificationRepository.save(notificationSetting);
+ }
+
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/notification/service/dto/NotificationHistoryResponseDto.java b/Main/src/main/java/com/kusitms29/backendH/api/notification/service/dto/NotificationHistoryResponseDto.java
new file mode 100644
index 0000000..52e65da
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/notification/service/dto/NotificationHistoryResponseDto.java
@@ -0,0 +1,30 @@
+package com.kusitms29.backendH.api.notification.service.dto;
+
+import com.kusitms29.backendH.global.common.TimeCalculator;
+import lombok.Builder;
+import lombok.Getter;
+
+import java.time.LocalDateTime;
+
+@Builder
+@Getter
+public class NotificationHistoryResponseDto {
+ private String infoId; //커뮤니티: 게시글, 일정: 싱크, 리뷰: 싱크, 채팅: 채팅방, 채팅개설공지: 싱크
+ private String title;
+ private String content;
+ private String detailContent;
+ private String createdDate;
+
+ public static NotificationHistoryResponseDto of(String infoId, String title, String content,
+ String detailContent, LocalDateTime createdDate) {
+
+ return NotificationHistoryResponseDto.builder()
+ .infoId(infoId)
+ .title(title)
+ .content(content)
+ .detailContent(detailContent)
+ .createdDate(TimeCalculator.calculateTimeDifference(createdDate))
+ .build();
+ }
+
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/sync/controller/SyncDetailController.java b/Main/src/main/java/com/kusitms29/backendH/api/sync/controller/SyncDetailController.java
new file mode 100644
index 0000000..ffb87ac
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/sync/controller/SyncDetailController.java
@@ -0,0 +1,48 @@
+package com.kusitms29.backendH.api.sync.controller;
+
+import com.kusitms29.backendH.api.sync.service.SyncDetailService;
+import com.kusitms29.backendH.api.sync.service.dto.response.SyncDetailResponseDto;
+import com.kusitms29.backendH.api.sync.service.dto.response.SyncGraphResponseDto;
+import com.kusitms29.backendH.api.sync.service.dto.response.SyncInfoResponseDto;
+import com.kusitms29.backendH.api.sync.service.dto.response.SyncReviewResponseDto;
+import com.kusitms29.backendH.global.common.SuccessResponse;
+import com.kusitms29.backendH.infra.config.auth.UserId;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+
+@RequiredArgsConstructor
+@RequestMapping("/api/sync/detail")
+@RestController
+public class SyncDetailController {
+ private final SyncDetailService syncDetailService;
+ @GetMapping
+ public ResponseEntity> syncDetail(@RequestParam(name = "syncId") Long syncId){
+ SyncDetailResponseDto syncDetailResponseDto = syncDetailService.getSyncDetail(syncId);
+ return SuccessResponse.ok(syncDetailResponseDto);
+ }
+ @GetMapping("/{graph}")
+ public ResponseEntity> syncDetailGraph(@RequestParam(name = "syncId") Long syncId, @PathVariable(name = "graph") String graph){
+ SyncGraphResponseDto syncGraphResponseDto = syncDetailService.getSyncDetailGraph(syncId, graph);
+ return SuccessResponse.ok(syncGraphResponseDto);
+ }
+ @GetMapping("/recommend")
+ public ResponseEntity> getAnotherSync(@RequestParam(name = "syncId") Long syncId,@RequestParam(name = "take", defaultValue = "0") int take){
+ List syncInfoResponseDtos = syncDetailService.getSyncListBySameDateAndSameLocation(syncId, take);
+ return SuccessResponse.ok(syncInfoResponseDtos);
+ }
+ @GetMapping("/review")
+ public ResponseEntity> getSyncReviewList(@RequestParam(name = "syncId") Long syncId, @RequestParam(name = "take",defaultValue = "0") int take){
+ List syncReviewResponseDtos = syncDetailService.getSyncReviewList(syncId, take);
+ return SuccessResponse.ok(syncReviewResponseDtos);
+ }
+ @GetMapping("/join")
+ public ResponseEntity> joinSync(@UserId Long userId, @RequestParam(name = "syncId") Long syncId){
+ syncDetailService.joinSync(userId, syncId);
+ return SuccessResponse.ok("join");
+ }
+}
+
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/sync/controller/SyncMainController.java b/Main/src/main/java/com/kusitms29/backendH/api/sync/controller/SyncMainController.java
new file mode 100644
index 0000000..0abbe70
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/sync/controller/SyncMainController.java
@@ -0,0 +1,49 @@
+package com.kusitms29.backendH.api.sync.controller;
+
+import com.kusitms29.backendH.api.sync.service.SyncService;
+import com.kusitms29.backendH.api.sync.service.dto.request.SyncInfoRequestDto;
+import com.kusitms29.backendH.api.sync.service.dto.response.SyncAssociateInfoResponseDto;
+import com.kusitms29.backendH.api.sync.service.dto.response.SyncInfoResponseDto;
+import com.kusitms29.backendH.domain.user.ip.IpService;
+import com.kusitms29.backendH.global.common.SuccessResponse;
+import com.kusitms29.backendH.infra.external.clova.map.GeoLocationService;
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.List;
+
+@RequiredArgsConstructor
+@RequestMapping("/api/sync")
+@RestController
+public class SyncMainController {
+ private final SyncService syncManageService;
+ private final IpService ipService;
+ private final GeoLocationService geoLocationService;
+ @GetMapping("/recommend")
+ public ResponseEntity> recommendSync(@RequestParam(name = "userId") Long userId, HttpServletRequest request) throws NoSuchAlgorithmException, InvalidKeyException, IOException {
+ String clientIp = ipService.getClientIpAddress(request);
+// GeoLocation geoLocation = geoLocationService.getGeoLocation(clientIp);
+ List syncInfoResponseDtos = syncManageService.recommendSync(userId, clientIp);
+ return SuccessResponse.ok(syncInfoResponseDtos);
+ }
+ @PostMapping("/friend")
+ public ResponseEntity> friendSync(@RequestBody SyncInfoRequestDto syncInfoRequestDto) {
+ List syncInfoResponseDtos = syncManageService.friendSync(syncInfoRequestDto);
+ return SuccessResponse.ok(syncInfoResponseDtos);
+ }
+ @PostMapping("/search")
+ public ResponseEntity> searchSync(@RequestBody SyncInfoRequestDto syncInfoRequestDto) {
+ List syncInfoResponseDtos = syncManageService.searchSync(syncInfoRequestDto);
+ return SuccessResponse.ok(syncInfoResponseDtos);
+ }
+ @PostMapping("/associate")
+ public ResponseEntity> associateSync(@RequestBody SyncInfoRequestDto syncInfoRequestDto) {
+ List syncInfoResponseDtos = syncManageService.associateSync(syncInfoRequestDto);
+ return SuccessResponse.ok(syncInfoResponseDtos);
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/sync/controller/SyncManageController.java b/Main/src/main/java/com/kusitms29/backendH/api/sync/controller/SyncManageController.java
new file mode 100644
index 0000000..498835c
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/sync/controller/SyncManageController.java
@@ -0,0 +1,34 @@
+package com.kusitms29.backendH.api.sync.controller;
+
+import com.kusitms29.backendH.api.sync.service.SyncService;
+import com.kusitms29.backendH.api.sync.service.dto.request.SyncCreateRequestDto;
+import com.kusitms29.backendH.api.sync.service.dto.response.SyncSaveResponseDto;
+import com.kusitms29.backendH.global.common.SuccessResponse;
+import com.kusitms29.backendH.infra.config.auth.UserId;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.List;
+
+@RequiredArgsConstructor
+@RequestMapping("/api/sync")
+@RestController
+public class SyncManageController {
+ private final SyncService syncService;
+ @PostMapping
+ public ResponseEntity> createSync(@UserId Long userId,
+ @RequestPart(required = false) MultipartFile image,
+ @RequestPart SyncCreateRequestDto requestDto) {
+ SyncSaveResponseDto responseDto = syncService.createSync(userId, image, requestDto);
+ return SuccessResponse.ok(responseDto);
+ }
+
+ @GetMapping("/seoul-address")
+ public ResponseEntity> getSeoulAddresses() {
+ List responseDto = syncService.getSeoulAddresses();
+ return SuccessResponse.ok(responseDto);
+ }
+
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/sync/service/SyncDetailService.java b/Main/src/main/java/com/kusitms29/backendH/api/sync/service/SyncDetailService.java
new file mode 100644
index 0000000..0d5577e
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/sync/service/SyncDetailService.java
@@ -0,0 +1,132 @@
+package com.kusitms29.backendH.api.sync.service;
+
+
+import com.kusitms29.backendH.api.sync.service.dto.response.SyncDetailResponseDto;
+import com.kusitms29.backendH.api.sync.service.dto.response.SyncGraphResponseDto;
+import com.kusitms29.backendH.api.sync.service.dto.response.SyncInfoResponseDto;
+import com.kusitms29.backendH.api.sync.service.dto.response.SyncReviewResponseDto;
+import com.kusitms29.backendH.domain.chat.service.RoomAppender;
+import com.kusitms29.backendH.domain.sync.entity.Participation;
+import com.kusitms29.backendH.domain.sync.service.ParticipationManager;
+import com.kusitms29.backendH.domain.sync.service.ParticipationReader;
+import com.kusitms29.backendH.domain.sync.entity.Sync;
+import com.kusitms29.backendH.domain.sync.entity.SyncType;
+import com.kusitms29.backendH.domain.sync.service.SyncManager;
+import com.kusitms29.backendH.domain.sync.service.SyncReader;
+import com.kusitms29.backendH.domain.sync.entity.SyncReview;
+import com.kusitms29.backendH.domain.sync.service.SyncReviewReader;
+import com.kusitms29.backendH.domain.user.entity.User;
+import com.kusitms29.backendH.domain.user.service.UserReader;
+import com.kusitms29.backendH.global.error.ErrorCode;
+import com.kusitms29.backendH.global.error.exception.EntityNotFoundException;
+import com.kusitms29.backendH.global.error.exception.InvalidValueException;
+import com.kusitms29.backendH.global.error.exception.ListException;
+import com.kusitms29.backendH.infra.utils.ListUtils;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+import static com.kusitms29.backendH.domain.chat.entity.Room.createRoom;
+import static com.kusitms29.backendH.global.error.ErrorCode.INVALID_SYNC_TYPE;
+
+@Service
+@RequiredArgsConstructor
+public class SyncDetailService {
+ private final SyncReader syncReader;
+ private final UserReader userReader;
+ private final ParticipationManager participationManager;
+ private final SyncManager syncManager;
+ private final ParticipationReader participationReader;
+ private final ListUtils listUtils;
+ private final RoomAppender roomAppender;
+ public SyncDetailResponseDto getSyncDetail(Long syncId){
+ Sync sync = syncReader.findById(syncId);
+ User user = userReader.findByUserId(sync.getUser().getId());
+ int count = participationManager.countParticipationBySyncId(syncId);
+ Boolean isFull = syncManager.validateJoinRoom(sync,count);
+ if (sync.getSyncType() == SyncType.ONETIME) {
+ return SyncDetailResponseDto.oneTimeOf(
+ sync.getSyncName(),
+ sync.getImage(),
+ sync.getSyncType(),
+ sync.getType(),
+ sync.getSyncIntro(),
+ sync.getDate(),
+ sync.getLocation(),
+ participationManager.countParticipationBySyncId(sync.getId()),
+ sync.getMember_max(),
+ user.getProfile(),
+ user.getUserName(),
+ user.getUniversity(),
+ sync.getUserIntro(),
+ isFull
+ );
+ } else if (sync.getSyncType() == SyncType.LONGTIME) {
+ return SyncDetailResponseDto.longTimeOf(
+ sync.getSyncName(),
+ sync.getImage(),
+ sync.getSyncType(),
+ sync.getType(),
+ sync.getSyncIntro(),
+ sync.getRegularDay(),
+ sync.getRegularTime(),
+ sync.getDate(),
+ sync.getLocation(),
+ participationManager.countParticipationBySyncId(sync.getId()),
+ sync.getMember_max(),
+ user.getProfile(),
+ user.getUserName(),
+ user.getUniversity(),
+ sync.getUserIntro(),
+ isFull
+ );
+ } else {
+ throw new InvalidValueException(INVALID_SYNC_TYPE);
+ }
+ }
+ public SyncGraphResponseDto getSyncDetailGraph(Long syncId, String graph){
+ List participations = participationReader.findAllBySyncId(syncId);
+ SyncGraphResponseDto graphElements = syncManager.createGraphElementList(participations, graph);
+ return graphElements;
+ }
+ public List getSyncListBySameDateAndSameLocation(Long syncId, int take){
+ Sync csync = syncReader.findById(syncId);
+ List syncList= syncReader.findAllByLocationAndDate(csync.getLocation(), csync.getDate());
+ List syncInfoResponseDtos = listUtils.getListByTake(syncList.stream()
+ .filter(sync -> !sync.getId().equals(syncId))
+ .map( sync -> SyncInfoResponseDto.of(
+ sync.getId(),
+ sync.getSyncType(),
+ sync.getType(),
+ sync.getImage(),
+ participationManager.countParticipationBySyncId(sync.getId()),
+ sync.getMember_max(),
+ sync.getSyncName(),
+ sync.getLocation(),
+ sync.getDate()
+ )).toList(), take);
+ return ListException.throwIfEmpty(syncInfoResponseDtos, () -> new EntityNotFoundException(ErrorCode.SYNC_NOT_FOUND));
+ }
+ private final SyncReviewReader syncReviewReader;
+ public List getSyncReviewList(Long syncId, int take){
+ List syncReviews = syncReviewReader.findAllBySyncId(syncId);
+ List syncReviewResponseDtos = syncReviews.stream().
+ map(syncReview -> SyncReviewResponseDto.of(
+ syncReview.getUser().getProfile(),
+ syncReview.getUser().getUserName(),
+ syncReview.getUser().getUniversity(),
+ syncReview.getContent(),
+ syncReview.getCreatedAt()
+ )).toList();
+ return listUtils.getListByTake(syncReviewResponseDtos, take);
+ }
+ public void joinSync(Long userId, Long syncId){
+ Participation.createParticipation(User.from(userId), Sync.from(syncId));
+ int count = participationManager.countParticipationBySyncId(syncId);
+ Boolean isPossible = syncManager.validateCreateRoom(syncReader.findById(syncId),count);
+ List userList = participationReader.findAllBySyncId(syncId).stream().map(participation -> participation.getUser()).toList();
+ roomAppender.createRoom(userList,isPossible,syncId);
+ }
+}
+
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/sync/service/SyncService.java b/Main/src/main/java/com/kusitms29/backendH/api/sync/service/SyncService.java
new file mode 100644
index 0000000..ceb2f5d
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/sync/service/SyncService.java
@@ -0,0 +1,233 @@
+package com.kusitms29.backendH.api.sync.service;
+
+
+import com.kusitms29.backendH.api.sync.service.dto.request.SyncCreateRequestDto;
+import com.kusitms29.backendH.api.sync.service.dto.request.SyncInfoRequestDto;
+import com.kusitms29.backendH.api.sync.service.dto.response.*;
+import com.kusitms29.backendH.domain.category.entity.Category;
+import com.kusitms29.backendH.domain.category.entity.Type;
+import com.kusitms29.backendH.domain.category.service.CategoryReader;
+import com.kusitms29.backendH.domain.category.service.UserCategoryManager;
+import com.kusitms29.backendH.domain.category.service.UserCategoryReader;
+import com.kusitms29.backendH.domain.sync.entity.SyncType;
+import com.kusitms29.backendH.domain.sync.service.ParticipationManager;
+import com.kusitms29.backendH.domain.sync.entity.Sync;
+import com.kusitms29.backendH.domain.sync.service.SyncAppender;
+import com.kusitms29.backendH.domain.sync.service.SyncReader;
+import com.kusitms29.backendH.domain.user.entity.User;
+import com.kusitms29.backendH.domain.category.entity.UserCategory;
+import com.kusitms29.backendH.domain.user.service.UserReader;
+import com.kusitms29.backendH.global.error.exception.InvalidValueException;
+import com.kusitms29.backendH.global.error.exception.NotAllowedException;
+import com.kusitms29.backendH.infra.config.AwsS3Service;
+import com.kusitms29.backendH.infra.external.SeoulAddressClient;
+import com.kusitms29.backendH.infra.utils.ListUtils;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static com.kusitms29.backendH.domain.category.entity.Type.getEnumTypeFromStringType;
+import static com.kusitms29.backendH.domain.sync.entity.SyncType.FROM_FRIEND;
+import static com.kusitms29.backendH.domain.sync.entity.SyncType.getEnumFROMStringSyncType;
+import static com.kusitms29.backendH.global.error.ErrorCode.*;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class SyncService {
+ private final SyncReader syncReader;
+ private final SyncAppender syncAppender;
+ private final UserReader userReader;
+ private final UserCategoryReader userCategoryReader;
+ private final UserCategoryManager userCategoryManager;
+ private final ParticipationManager participationManager;
+ private final ListUtils listUtils;
+ private final AwsS3Service awsS3Service;
+ private final CategoryReader categoryReader;
+ private final SeoulAddressClient seoulAddressClient;
+
+ public List recommendSync(Long userId, String clientIp){
+ User user = userReader.findByUserId(userId);
+ List userCategories = userCategoryReader.findAllByUserId(userId);
+ List types = userCategoryManager.getTypeByUserCategories(userCategories);
+ List syncList = syncReader.findBySyncTypeWithTypesWithLocation(user.getSyncType(), types, user.getLocation());
+ return syncList.stream().map( sync -> SyncInfoResponseDto.of(
+ sync.getId(),
+ sync.getSyncType(),
+ sync.getType(),
+ sync.getImage(),
+ participationManager.countParticipationBySyncId(sync.getId()),
+ sync.getMember_max(),
+ sync.getSyncName(),
+ sync.getLocation(),
+ sync.getDate()
+ )).toList();
+ }
+ public List friendSync(SyncInfoRequestDto syncInfoRequestDto){
+ List syncList = syncReader.findAllBySyncTypeAndType(FROM_FRIEND, getEnumTypeFromStringType(syncInfoRequestDto.type()));
+ List syncInfoResponseDtos = syncList.stream()
+ //음 이거보다 위에서 if문써서 하는게 더 가독성 있는듯
+// .filter(sync -> type == null || sync.getType().name().equals(type))
+ .map( sync -> SyncInfoResponseDto.of(
+ sync.getId(),
+ sync.getSyncType(),
+ sync.getType(),
+ sync.getImage(),
+ participationManager.countParticipationBySyncId(sync.getId()),
+ sync.getMember_max(),
+ sync.getSyncName(),
+ sync.getLocation(),
+ sync.getDate()
+ )).toList();
+ return listUtils.getListByTake(syncInfoResponseDtos, syncInfoRequestDto.take());
+ }
+ public List associateSync(SyncInfoRequestDto syncInfoRequestDto){
+ List syncList = syncReader.findAllByAssociateIsExist(getEnumFROMStringSyncType(syncInfoRequestDto.syncType()), getEnumTypeFromStringType(syncInfoRequestDto.type()));
+ List syncAssociateInfoResponseDtos = syncList.stream().map( sync -> SyncAssociateInfoResponseDto.of(
+ sync.getId(),
+ sync.getSyncType(),
+ sync.getType(),
+ sync.getImage(),
+ participationManager.countParticipationBySyncId(sync.getId()),
+ sync.getMember_max(),
+ sync.getSyncName(),
+ sync.getLocation(),
+ sync.getDate(),
+ sync.getAssociate()
+ )).toList();
+ return listUtils.getListByTake(syncAssociateInfoResponseDtos, syncInfoRequestDto.take());
+ }
+ public List searchSync(SyncInfoRequestDto syncInfoRequestDto){
+ List syncList = syncReader.findAllBySyncTypeAndType(getEnumFROMStringSyncType(syncInfoRequestDto.syncType()), getEnumTypeFromStringType(syncInfoRequestDto.type()));
+
+ List syncInfoResponseDtos = syncList.stream().map( sync -> SyncInfoResponseDto.of(
+ sync.getId(),
+ sync.getSyncType(),
+ sync.getType(),
+ sync.getImage(),
+ participationManager.countParticipationBySyncId(sync.getId()),
+ sync.getMember_max(),
+ sync.getSyncName(),
+ sync.getLocation(),
+ sync.getDate()
+ )).toList();
+ return listUtils.getListByTake(syncInfoResponseDtos, syncInfoRequestDto.take());
+ }
+
+ public SyncSaveResponseDto createSync(Long userId, MultipartFile file, SyncCreateRequestDto requestDto) {
+ User user = userReader.findByUserId(userId);
+
+ if(requestDto.getUserIntro().length() > 50) {
+ throw new NotAllowedException(USER_INTRO_NOT_ALLOWED);
+ }
+ if(requestDto.getSyncIntro().length() > 500) {
+ throw new NotAllowedException(SYNC_INTRO_NOT_ALLOWED);
+ }
+
+ SyncType enumSyncType = SyncType.getEnumFROMStringSyncType(requestDto.getSyncType());
+
+ if(requestDto.getSyncName().length() > 15) {
+ throw new NotAllowedException(SYNC_NAME_NOT_ALLOWED);
+ }
+
+ String image = awsS3Service.uploadImage(file);
+
+ LocalDateTime oneTimeLocalDateTime = null;
+ if(requestDto.getDate() != null && !requestDto.getDate().isEmpty()) {
+ oneTimeLocalDateTime= parseToLocalDateTime(requestDto.getDate()); //2023-04-13 15:30
+ }
+
+ String regularDay = null;
+ if(requestDto.getRegularDay() != null && !requestDto.getRegularDay().isEmpty()) {
+ regularDay = requestDto.getRegularDay();
+ }
+
+ LocalDateTime regularLocalDateTime = null;
+ if(requestDto.getRoutineDate() != null && !requestDto.getRoutineDate().isEmpty()) {
+ regularLocalDateTime = parseToLocalDateTime(requestDto.getRoutineDate()); //2023-04-13 15:30
+ }
+
+ LocalTime regularLocalTime = null;
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm");
+ if(requestDto.getRegularTime() != null && !requestDto.getRegularTime().isEmpty()) { //15:30
+ regularLocalTime = LocalTime.parse(requestDto.getRegularTime(), formatter);
+ }
+
+ if(requestDto.getMember_min() < 3) {
+ throw new NotAllowedException(SYNC_MIN_NOT_ALLOWED);
+ }
+ if(requestDto.getMember_max() > 30) {
+ throw new NotAllowedException(SYNC_MAX_NOT_ALLOWED);
+ }
+
+ Type enumType = Type.getEnumTypeFromStringType(requestDto.getType());
+
+ Category detailCategory = categoryReader.findByName(requestDto.getDetailType());
+ if(!detailCategory.getType().getStringType().equals(requestDto.getType())) {
+ throw new InvalidValueException(INVALID_PARENT_CHILD_CATEGORY);
+ }
+
+ Sync newSync = syncAppender.save(
+ Sync.createSync(
+ user,
+ requestDto.getUserIntro(),
+ requestDto.getSyncIntro(),
+ enumSyncType,
+ requestDto.getSyncName(),
+ image,
+ requestDto.getLocation(),
+ oneTimeLocalDateTime,
+ regularDay,
+ regularLocalTime,
+ regularLocalDateTime,
+ requestDto.getMember_min(),
+ requestDto.getMember_max(),
+ enumType,
+ requestDto.getDetailType())
+ );
+
+ return SyncSaveResponseDto.of(
+ newSync.getId(),
+ newSync.getUserIntro(),
+ newSync.getSyncIntro(),
+ newSync.getSyncType(),
+ newSync.getSyncName(),
+ newSync.getImage(),
+ newSync.getLocation(),
+ newSync.getDate(),
+ newSync.getRegularDay(),
+ newSync.getRegularTime(),
+ newSync.getRoutineDate(),
+ newSync.getMember_min(),
+ newSync.getMember_max(),
+ newSync.getType(),
+ newSync.getDetailType()
+ );
+ }
+
+ private LocalDateTime parseToLocalDateTime(String date) {
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
+ return LocalDateTime.parse(date, formatter);
+ }
+
+ public List getSeoulAddresses() {
+ List nameList = new ArrayList<>();
+ SeoulAddressResponse seoulAddressResponse = seoulAddressClient.calloutSeoulAddressAPI();
+
+ seoulAddressResponse.getRegcodes().forEach(result -> {
+ String address = result.getName().replace("특별", "");
+ nameList.add(address);
+ });
+
+ return nameList;
+ }
+}
+
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/sync/service/dto/request/SyncCreateRequestDto.java b/Main/src/main/java/com/kusitms29/backendH/api/sync/service/dto/request/SyncCreateRequestDto.java
new file mode 100644
index 0000000..4f78107
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/sync/service/dto/request/SyncCreateRequestDto.java
@@ -0,0 +1,29 @@
+package com.kusitms29.backendH.api.sync.service.dto.request;
+
+import lombok.AccessLevel;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@Getter
+public class SyncCreateRequestDto {
+ private String userIntro;
+ private String syncIntro;
+ private String syncType;
+ private String syncName;
+ private String location;
+ private String date; //일회성, 내친소
+
+ private String regularDay; //지속성
+ private String regularTime; //지속성
+ private String routineDate; //지속성
+
+ private int member_min;
+
+ private int member_max;
+
+ private String type; //언어교환, 엔터테인먼트, ...
+
+ private String detailType;
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/sync/service/dto/request/SyncInfoRequestDto.java b/Main/src/main/java/com/kusitms29/backendH/api/sync/service/dto/request/SyncInfoRequestDto.java
new file mode 100644
index 0000000..c44f875
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/sync/service/dto/request/SyncInfoRequestDto.java
@@ -0,0 +1,13 @@
+package com.kusitms29.backendH.api.sync.service.dto.request;
+
+public record SyncInfoRequestDto(
+ int take,
+ String syncType,
+ String type
+) {
+ public SyncInfoRequestDto {
+ if (take < 0) {
+ take = 0;
+ }
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/sync/service/dto/response/GraphElement.java b/Main/src/main/java/com/kusitms29/backendH/api/sync/service/dto/response/GraphElement.java
new file mode 100644
index 0000000..78dfba4
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/sync/service/dto/response/GraphElement.java
@@ -0,0 +1,17 @@
+package com.kusitms29.backendH.api.sync.service.dto.response;
+
+import lombok.Builder;
+import lombok.Getter;
+
+@Getter
+@Builder
+public class GraphElement {
+ private String name;
+ private int percent;
+ public static GraphElement of(String name, int percent){
+ return GraphElement.builder()
+ .name(name)
+ .percent(percent)
+ .build();
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/sync/service/dto/response/SeoulAddressResponse.java b/Main/src/main/java/com/kusitms29/backendH/api/sync/service/dto/response/SeoulAddressResponse.java
new file mode 100644
index 0000000..b22481f
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/sync/service/dto/response/SeoulAddressResponse.java
@@ -0,0 +1,16 @@
+package com.kusitms29.backendH.api.sync.service.dto.response;
+
+import lombok.Getter;
+
+import java.util.List;
+
+@Getter
+public class SeoulAddressResponse {
+ private List regcodes;
+
+ @Getter
+ public static class SeoulAddressResult {
+ private String code;
+ private String name;
+ }
+}
\ No newline at end of file
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/sync/service/dto/response/SyncAssociateInfoResponseDto.java b/Main/src/main/java/com/kusitms29/backendH/api/sync/service/dto/response/SyncAssociateInfoResponseDto.java
new file mode 100644
index 0000000..ba587e5
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/sync/service/dto/response/SyncAssociateInfoResponseDto.java
@@ -0,0 +1,36 @@
+package com.kusitms29.backendH.api.sync.service.dto.response;
+
+import com.kusitms29.backendH.domain.category.entity.Type;
+import com.kusitms29.backendH.domain.sync.entity.SyncType;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+
+public record SyncAssociateInfoResponseDto(
+ Long syncId,
+ String syncType,
+ String type,
+ String image,
+ int userCnt,
+ int totalCnt,
+ String syncName,
+ String location,
+ String date,
+ String associate
+) {
+ private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("M월 d일 (E) a h:mm");
+
+ public static SyncAssociateInfoResponseDto of(Long syncId,
+ SyncType syncType,
+ Type type,
+ String image,
+ int userCnt,
+ int totalCnt,
+ String syncName,
+ String location,
+ LocalDateTime date,
+ String associate){
+ String formattedDate = date.format(DATE_TIME_FORMATTER);
+ return new SyncAssociateInfoResponseDto(syncId, String.valueOf(syncType), String.valueOf(type), image, userCnt, totalCnt, syncName, location, formattedDate, associate);
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/sync/service/dto/response/SyncCreateResponseDto.java b/Main/src/main/java/com/kusitms29/backendH/api/sync/service/dto/response/SyncCreateResponseDto.java
new file mode 100644
index 0000000..5832351
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/sync/service/dto/response/SyncCreateResponseDto.java
@@ -0,0 +1,45 @@
+package com.kusitms29.backendH.api.sync.service.dto.response;
+
+import lombok.Builder;
+import lombok.Getter;
+
+@Builder
+@Getter
+public class SyncCreateResponseDto {
+ private Long syncId;
+ private String link;
+ private String syncType;
+ private String parentCategory;
+ private String childCategory;
+ private String name;
+ private String image;
+ private String comment;
+ private String location;
+ private String date;
+ private int meeting_cnt;
+ private int member_min;
+ private int member_max;
+
+ public static SyncCreateResponseDto of(Long syncId, String link, String syncType,
+ String parentCategory, String childCategory,
+ String name, String image, String comment,
+ String location, String date, int meeting_cnt,
+ int member_min, int member_max) {
+ return SyncCreateResponseDto.builder()
+ .syncId(syncId)
+ .link(link)
+ .syncType(syncType)
+ .parentCategory(parentCategory)
+ .childCategory(childCategory)
+ .name(name)
+ .image(image)
+ .comment(comment)
+ .location(location)
+ .date(date)
+ .meeting_cnt(meeting_cnt)
+ .member_min(member_min)
+ .member_max(member_max)
+ .build();
+ }
+
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/sync/service/dto/response/SyncDetailResponseDto.java b/Main/src/main/java/com/kusitms29/backendH/api/sync/service/dto/response/SyncDetailResponseDto.java
new file mode 100644
index 0000000..371a2ec
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/sync/service/dto/response/SyncDetailResponseDto.java
@@ -0,0 +1,66 @@
+package com.kusitms29.backendH.api.sync.service.dto.response;
+
+import com.kusitms29.backendH.domain.category.entity.Type;
+import com.kusitms29.backendH.domain.sync.entity.SyncType;
+
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+
+public record SyncDetailResponseDto(
+ String syncName,
+ String syncImage,
+ String syncType,
+ String type,
+ String syncIntro,
+ String regularDate,
+ String date,
+ String location,
+ int userCnt,
+ int totalCnt,
+ String userImage,
+ String userName,
+ String university,
+ String userIntro,
+ Boolean isFull
+) {
+ private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("M월 d일 (EE) a h:mm");
+ public static SyncDetailResponseDto oneTimeOf(String syncName,
+ String syncImage,
+ SyncType syncType,
+ Type type,
+ String syncIntro,
+ LocalDateTime date,
+ String location,
+ int userCnt,
+ int totalCnt,
+ String userImage,
+ String userName,
+ String university,
+ String userIntro,
+ Boolean isFull){
+ String formattedDate = date.format(DATE_TIME_FORMATTER);
+ return new SyncDetailResponseDto(syncName, syncImage, String.valueOf(syncType), String.valueOf(type), syncIntro, null, formattedDate, location, userCnt, totalCnt, userImage, userName, university, userIntro, isFull);
+ }
+ public static SyncDetailResponseDto longTimeOf(String syncName,
+ String syncImage,
+ SyncType syncType,
+ Type type,
+ String syncIntro,
+ String regularDay,
+ LocalTime regularTime,
+ LocalDateTime date,
+ String location,
+ int userCnt,
+ int totalCnt,
+ String userImage,
+ String userName,
+ String university,
+ String userIntro,
+ Boolean isFull){
+ String formattedDate = date.format(DATE_TIME_FORMATTER);
+ String formattedRegularTime = regularTime.format(DateTimeFormatter.ofPattern("a h:mm"));
+ String regularDate = "매주 " + regularDay + " " + formattedRegularTime;
+ return new SyncDetailResponseDto(syncName, syncImage, String.valueOf(syncType), String.valueOf(type), syncIntro, regularDate, formattedDate, location, userCnt, totalCnt, userImage, userName, university, userIntro, isFull);
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/sync/service/dto/response/SyncGraphResponseDto.java b/Main/src/main/java/com/kusitms29/backendH/api/sync/service/dto/response/SyncGraphResponseDto.java
new file mode 100644
index 0000000..ffe5829
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/sync/service/dto/response/SyncGraphResponseDto.java
@@ -0,0 +1,13 @@
+package com.kusitms29.backendH.api.sync.service.dto.response;
+
+import java.util.List;
+
+public record SyncGraphResponseDto(
+ List data,
+ String status
+
+) {
+ public static SyncGraphResponseDto of(List data, String status){
+ return new SyncGraphResponseDto(data, status);
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/sync/service/dto/response/SyncInfoResponseDto.java b/Main/src/main/java/com/kusitms29/backendH/api/sync/service/dto/response/SyncInfoResponseDto.java
new file mode 100644
index 0000000..664a34d
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/sync/service/dto/response/SyncInfoResponseDto.java
@@ -0,0 +1,34 @@
+package com.kusitms29.backendH.api.sync.service.dto.response;
+
+import com.kusitms29.backendH.domain.category.entity.Type;
+import com.kusitms29.backendH.domain.sync.entity.SyncType;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+
+public record SyncInfoResponseDto(
+ Long syncId,
+ String syncType,
+ String type,
+ String image,
+ int userCnt,
+ int totalCnt,
+ String syncName,
+ String location,
+ String date
+) {
+ private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("M월 d일 (EE) a h:mm");
+
+ public static SyncInfoResponseDto of(Long syncId,
+ SyncType syncType,
+ Type type,
+ String image,
+ int userCnt,
+ int totalCnt,
+ String syncName,
+ String location,
+ LocalDateTime date){
+ String formattedDate = date.format(DATE_TIME_FORMATTER);
+ return new SyncInfoResponseDto(syncId, String.valueOf(syncType), String.valueOf(type), image, userCnt, totalCnt, syncName, location, formattedDate);
+ }
+}
\ No newline at end of file
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/sync/service/dto/response/SyncReviewResponseDto.java b/Main/src/main/java/com/kusitms29/backendH/api/sync/service/dto/response/SyncReviewResponseDto.java
new file mode 100644
index 0000000..0fb687c
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/sync/service/dto/response/SyncReviewResponseDto.java
@@ -0,0 +1,25 @@
+package com.kusitms29.backendH.api.sync.service.dto.response;
+
+import java.time.Duration;
+import java.time.LocalDateTime;
+
+public record SyncReviewResponseDto(
+ String image,
+ String name,
+ String university,
+ String content,
+ String date
+) {
+ public static SyncReviewResponseDto of(String image, String name, String university, String content, LocalDateTime date){
+ return new SyncReviewResponseDto(image, name, university, content, calculateTimeDifference(date));
+ }
+ public static String calculateTimeDifference(LocalDateTime date) {
+ LocalDateTime now = LocalDateTime.now();
+ Duration duration = Duration.between(date, now);
+ long months = duration.toDays() / 30;
+ if (months > 0) {
+ return months + "달 전";
+ }
+ return "방금 전";
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/sync/service/dto/response/SyncSaveResponseDto.java b/Main/src/main/java/com/kusitms29/backendH/api/sync/service/dto/response/SyncSaveResponseDto.java
new file mode 100644
index 0000000..cc5e193
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/sync/service/dto/response/SyncSaveResponseDto.java
@@ -0,0 +1,61 @@
+package com.kusitms29.backendH.api.sync.service.dto.response;
+
+import com.kusitms29.backendH.domain.category.entity.Type;
+import com.kusitms29.backendH.domain.sync.entity.SyncType;
+import lombok.Builder;
+import lombok.Getter;
+
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+
+@Builder
+@Getter
+public class SyncSaveResponseDto {
+ private long syncId;
+ private String userIntro;
+ private String syncIntro;
+ private String syncType;
+ private String syncName;
+ private String image;
+ private String location;
+ private LocalDateTime date; //일회성, 내친소
+
+ private String regularDay; //지속성 요일
+ private LocalTime regularTime; //지속성 시간
+ private LocalDateTime routineDate; //지속성 첫모임
+
+ private int member_min;
+
+ private int member_max;
+
+ private String type; //외국어, 엔터테인먼트, ...
+
+ private String detailType;
+
+
+ public static SyncSaveResponseDto of(Long syncId, String userIntro, String syncIntro,
+ SyncType syncType, String syncName,
+ String image, String location,
+ LocalDateTime date,
+ String regularDay, LocalTime regularTime, LocalDateTime routineDate,
+ int member_min, int member_max,
+ Type type, String detailType) {
+ return SyncSaveResponseDto.builder()
+ .syncId(syncId)
+ .userIntro(userIntro)
+ .syncIntro(syncIntro)
+ .syncType(syncType.getStringSyncType())
+ .syncName(syncName)
+ .image(image)
+ .location(location)
+ .date(date)
+ .regularDay(regularDay)
+ .regularTime(regularTime)
+ .routineDate(routineDate)
+ .member_min(member_min)
+ .member_max(member_max)
+ .type(type.getStringType())
+ .detailType(detailType)
+ .build();
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/user/controller/AuthController.java b/Main/src/main/java/com/kusitms29/backendH/api/user/controller/AuthController.java
new file mode 100644
index 0000000..eebf638
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/user/controller/AuthController.java
@@ -0,0 +1,23 @@
+package com.kusitms29.backendH.api.user.controller;
+
+import com.kusitms29.backendH.api.user.service.AuthService;
+import com.kusitms29.backendH.api.user.service.dto.request.UserSignInRequestDto;
+import com.kusitms29.backendH.api.user.service.dto.response.UserAuthResponseDto;
+import com.kusitms29.backendH.global.common.SuccessResponse;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+@RequestMapping("/api/auth")
+@RequiredArgsConstructor
+@RestController
+public class AuthController {
+ private final AuthService authService;
+ @PostMapping("/signin")
+ public ResponseEntity> signIn(@RequestHeader("Authorization") final String authToken,
+ @RequestHeader String fcmToken,
+ @RequestBody final UserSignInRequestDto requestDto) {
+ final UserAuthResponseDto responseDto = authService.signIn(requestDto, authToken, fcmToken);
+ return SuccessResponse.ok(responseDto);
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/user/controller/MyPageController.java b/Main/src/main/java/com/kusitms29/backendH/api/user/controller/MyPageController.java
new file mode 100644
index 0000000..4e62b3d
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/user/controller/MyPageController.java
@@ -0,0 +1,55 @@
+package com.kusitms29.backendH.api.user.controller;
+
+import com.kusitms29.backendH.api.sync.service.dto.response.SyncInfoResponseDto;
+import com.kusitms29.backendH.api.user.service.MyPageService;
+import com.kusitms29.backendH.api.user.service.dto.request.CreateReviewRequest;
+import com.kusitms29.backendH.api.user.service.dto.request.EditProfileRequest;
+import com.kusitms29.backendH.api.user.service.dto.response.CreateReviewResponse;
+import com.kusitms29.backendH.api.user.service.dto.response.UserInfoResponseDto;
+import com.kusitms29.backendH.global.common.SuccessResponse;
+import com.kusitms29.backendH.infra.config.auth.UserId;
+import com.kusitms29.backendH.infra.utils.TranslateUtil;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/api/mypage")
+public class MyPageController {
+ private final MyPageService myPageService;
+ private final TranslateUtil translateUtil;
+ @GetMapping("/mysync")
+ public ResponseEntity> getMySyncList(@UserId Long userId,@RequestParam(name = "take",defaultValue = "0") int take) {
+ List< SyncInfoResponseDto> syncInfoResponseDtos = myPageService.getMySyncList(userId,take);
+ return SuccessResponse.ok(syncInfoResponseDtos);
+ }
+ @GetMapping("/join")
+ public ResponseEntity> getJoinSyncList(@UserId Long userId,@RequestParam(name = "take",defaultValue = "0") int take) {
+ List< SyncInfoResponseDto> syncInfoResponseDtos = myPageService.getJoinSyncList(userId,take);
+ return SuccessResponse.ok(syncInfoResponseDtos);
+ }
+ @GetMapping
+ public ResponseEntity> getMyInfo(@UserId Long userId, @RequestParam (name = "language", defaultValue = "한국어")String language) {
+ UserInfoResponseDto userInfoResponseDto = myPageService.getMyInfo(userId);
+ if (language.equals("영어"))userInfoResponseDto=translateUtil.translateObject(userInfoResponseDto);
+ return SuccessResponse.ok(userInfoResponseDto);
+ }
+ @PostMapping("/review")
+ public ResponseEntity> createReview(@UserId Long userId, @RequestBody CreateReviewRequest createReviewRequest) {
+ CreateReviewResponse createReviewResponse = myPageService.createReview(userId,createReviewRequest);
+ return SuccessResponse.created(createReviewResponse);
+ }
+ @GetMapping("/bookmark")
+ public ResponseEntity> getBookMarkSyncList(@UserId Long userId, @RequestParam(name = "take",defaultValue = "0") int take) {
+ List userInfoResponseDto = myPageService.getBookMarkSyncList(userId, take);
+ return SuccessResponse.ok(userInfoResponseDto);
+ }
+ @PatchMapping
+ public ResponseEntity> editBoard(@UserId Long userId, @ModelAttribute EditProfileRequest editProfileRequest) {
+ myPageService.editProfile(userId, editProfileRequest);
+ return SuccessResponse.ok("UPDATE");
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/user/controller/OnBoardingController.java b/Main/src/main/java/com/kusitms29/backendH/api/user/controller/OnBoardingController.java
new file mode 100644
index 0000000..c6905bf
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/user/controller/OnBoardingController.java
@@ -0,0 +1,69 @@
+package com.kusitms29.backendH.api.user.controller;
+
+import com.kusitms29.backendH.api.user.service.OnBoardingService;
+import com.kusitms29.backendH.api.user.service.dto.request.CountryCalloutRequestDto;
+import com.kusitms29.backendH.api.user.service.dto.request.OnBoardingRequestDto;
+import com.kusitms29.backendH.api.user.service.dto.request.UniversityRequestDto;
+import com.kusitms29.backendH.api.user.service.dto.request.schoolEmail.SchoolEmailRequestDto;
+import com.kusitms29.backendH.api.user.service.dto.request.schoolEmail.SchoolEmailVerificationRequestDto;
+import com.kusitms29.backendH.api.user.service.dto.response.OnBoardingResponseDto;
+import com.kusitms29.backendH.api.user.service.dto.response.schoolEmail.CalloutErrorResponse;
+import com.kusitms29.backendH.api.user.service.dto.response.schoolEmail.CalloutSchoolEmailVerificationResponseDto;
+import com.kusitms29.backendH.global.common.SuccessResponse;
+import com.kusitms29.backendH.infra.config.auth.UserId;
+import com.kusitms29.backendH.infra.external.CountryDataClient;
+import com.kusitms29.backendH.infra.external.SchoolEmailClient;
+import com.kusitms29.backendH.infra.external.UniversityClient;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.List;
+@RequestMapping("/api/user")
+@RequiredArgsConstructor
+@RestController
+public class OnBoardingController {
+ private final OnBoardingService onBoardingService;
+ private final UniversityClient universityClient;
+ private final CountryDataClient countryDataClient;
+ private final SchoolEmailClient schoolEmailClient;
+
+ @PostMapping("/onboarding")
+ public ResponseEntity> onboarding(@UserId Long userId,
+ @RequestPart("profileImage") MultipartFile profileImage,
+ @RequestPart("onBoardingRequest") OnBoardingRequestDto requestDto) {
+ onBoardingService.onBoardingUser(userId, profileImage, requestDto);
+ return SuccessResponse.created("success");
+ }
+ @PostMapping("/valid-university")
+ public ResponseEntity> isItValidUniversity(@RequestBody UniversityRequestDto requestDto) {
+ universityClient.isValidUniversity(requestDto.getUnivName());
+ return SuccessResponse.ok(true); //주석
+ }
+
+ @PostMapping("/countries")
+ public ResponseEntity> getCountries(@RequestBody CountryCalloutRequestDto requestDto) {
+ List countryNames = countryDataClient.listOfCountries(requestDto.getPage(), requestDto.getPerPage(), requestDto.getLanguage());
+ return SuccessResponse.ok(countryNames);
+ }
+
+
+ @PostMapping("/school-emails/verification-requests")
+ public ResponseEntity> sendMessageToSchool(@RequestBody SchoolEmailRequestDto requestDto) {
+ CalloutErrorResponse responseDto = schoolEmailClient.callOutSendSchoolEmail(requestDto);
+ return SuccessResponse.ok(responseDto.isSuccess());
+ }
+
+ @PostMapping("/school-emails/verifications")
+ public ResponseEntity> verificationSchoolEmail(@RequestBody SchoolEmailVerificationRequestDto requestDto) {
+ CalloutSchoolEmailVerificationResponseDto responseDto = schoolEmailClient.callOutAuthSchoolEmail(requestDto);
+ return SuccessResponse.ok(responseDto);
+ }
+
+ @PostMapping("/school-emails/reset")
+ public ResponseEntity> resetForTryEmailTest() {
+ CalloutErrorResponse responseDto = schoolEmailClient.clearAuthCode();
+ return SuccessResponse.ok(responseDto.isSuccess());
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/user/service/AuthService.java b/Main/src/main/java/com/kusitms29/backendH/api/user/service/AuthService.java
new file mode 100644
index 0000000..285f189
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/user/service/AuthService.java
@@ -0,0 +1,104 @@
+package com.kusitms29.backendH.api.user.service;
+
+import com.kusitms29.backendH.api.user.service.dto.request.UserSignInRequestDto;
+import com.kusitms29.backendH.api.user.service.dto.response.UserAuthResponseDto;
+import com.kusitms29.backendH.infra.external.fcm.service.PushNotificationService;
+import com.kusitms29.backendH.domain.user.auth.PlatformUserInfo;
+import com.kusitms29.backendH.domain.user.auth.RestTemplateProvider;
+import com.kusitms29.backendH.domain.user.entity.Platform;
+import com.kusitms29.backendH.domain.user.entity.User;
+import com.kusitms29.backendH.domain.user.repository.RefreshTokenRepository;
+import com.kusitms29.backendH.domain.user.service.UserModifier;
+import com.kusitms29.backendH.domain.user.service.UserReader;
+import com.kusitms29.backendH.global.error.exception.EntityNotFoundException;
+import com.kusitms29.backendH.infra.config.auth.JwtProvider;
+import com.kusitms29.backendH.infra.config.auth.TokenInfo;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Objects;
+import java.util.Optional;
+import java.util.UUID;
+
+import static com.kusitms29.backendH.domain.user.entity.Platform.getEnumPlatformFromStringPlatform;
+import static com.kusitms29.backendH.domain.user.entity.RefreshToken.createRefreshToken;
+import static com.kusitms29.backendH.global.error.ErrorCode.FCMTOKEN_NOT_FOUND;
+
+
+@Slf4j
+@RequiredArgsConstructor
+@Transactional
+@Service
+public class AuthService {
+ private final JwtProvider jwtProvider;
+ private final RestTemplateProvider restTemplateProvider;
+ private final RefreshTokenRepository refreshTokenRepository;
+ private final PushNotificationService pushNotificationService;
+ private final UserReader userReader;
+ private final UserModifier userModifier;
+
+ public UserAuthResponseDto signIn(UserSignInRequestDto userSignInRequestDto, String authToken, String fcmToken) {
+ if (fcmToken == null || fcmToken.isEmpty()) {
+ throw new EntityNotFoundException(FCMTOKEN_NOT_FOUND);
+ }
+ Platform platform = getEnumPlatformFromStringPlatform(userSignInRequestDto.getPlatform());
+ PlatformUserInfo platformUser = getPlatformUserInfoFromRestTemplate(platform, authToken);
+ User getUser = saveUser(platformUser, platform);
+ saveFcmToken(getUser, fcmToken);
+ Boolean isFirstLogin = Objects.isNull(getUser.getPlatform()) ? Boolean.TRUE : Boolean.FALSE;
+ TokenInfo tokenInfo = issueAccessTokenAndRefreshToken(getUser);
+ updateRefreshToken(tokenInfo.getRefreshToken(), getUser);
+ return UserAuthResponseDto.of(getUser, tokenInfo, isFirstLogin);
+ }
+
+ public void signOut(Long userId) {
+ User findUser = getUserFromUserId(userId);
+ deleteRefreshToken(findUser);
+ }
+
+ private void deleteRefreshToken(User user) {
+ user.updateRefreshToken(null);
+ refreshTokenRepository.deleteById(user.getId());
+ }
+
+ private User saveUser(PlatformUserInfo platformUserInfo, Platform platform) {
+ User createdUser = getUserByPlatformUserInfo(platformUserInfo, platform);
+ return userModifier.save(createdUser);
+ }
+
+ private void updateRefreshToken(String refreshToken, User user) {
+ user.updateRefreshToken(refreshToken);
+ refreshTokenRepository.save(createRefreshToken(user.getId(), refreshToken));
+ }
+
+ private TokenInfo issueAccessTokenAndRefreshToken(User user) {
+ return jwtProvider.issueToken(user.getId());
+ }
+
+ private User getUserFromUserId(Long userId) {
+ return userReader.findByUserId(userId);
+ }
+
+ private User getUserByPlatformUserInfo(PlatformUserInfo platformUserInfo, Platform platform) {
+ Optional optionalUser = userReader.findByPlatformId(platformUserInfo.getId());
+ return optionalUser.orElseGet(() -> User.createUser(platformUserInfo, platform, generateRandomUuid(platformUserInfo)));
+ }
+ private void saveFcmToken(User getUser, String fcmToken) {
+ pushNotificationService.saveToken(String.valueOf(getUser.getId()), fcmToken);
+ }
+
+ private PlatformUserInfo getPlatformUserInfoFromRestTemplate(Platform platform, String authToken) {
+ return restTemplateProvider.getUserInfoUsingRestTemplate(platform, authToken);
+ }
+
+ private String generateRandomUuid(PlatformUserInfo platformUserInfo) {
+ UUID randomUuid = UUID.randomUUID();
+ String uuidAsString = randomUuid.toString().replace("-", "");
+ return platformUserInfo.getId() + "_" + uuidAsString.substring(0, 6);
+ }
+
+}
+
+
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/user/service/MyPageService.java b/Main/src/main/java/com/kusitms29/backendH/api/user/service/MyPageService.java
new file mode 100644
index 0000000..a860f5f
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/user/service/MyPageService.java
@@ -0,0 +1,113 @@
+package com.kusitms29.backendH.api.user.service;
+
+import com.kusitms29.backendH.api.sync.service.dto.response.SyncInfoResponseDto;
+import com.kusitms29.backendH.api.user.service.dto.request.CreateReviewRequest;
+import com.kusitms29.backendH.api.user.service.dto.request.EditProfileRequest;
+import com.kusitms29.backendH.api.user.service.dto.response.CreateReviewResponse;
+import com.kusitms29.backendH.api.user.service.dto.response.UserInfoResponseDto;
+import com.kusitms29.backendH.domain.category.entity.Category;
+import com.kusitms29.backendH.domain.category.service.CategoryReader;
+import com.kusitms29.backendH.domain.category.service.UserCategoryModifier;
+import com.kusitms29.backendH.domain.category.service.UserCategoryReader;
+import com.kusitms29.backendH.domain.sync.entity.*;
+import com.kusitms29.backendH.domain.sync.service.*;
+import com.kusitms29.backendH.domain.user.entity.User;
+import com.kusitms29.backendH.domain.user.service.UserModifier;
+import com.kusitms29.backendH.domain.user.service.UserReader;
+import com.kusitms29.backendH.infra.config.AwsS3Service;
+import com.kusitms29.backendH.infra.utils.ListUtils;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+import static com.kusitms29.backendH.domain.category.entity.UserCategory.createUserCategory;
+import static com.kusitms29.backendH.domain.sync.entity.Gender.getEnumFROMStringGender;
+import static com.kusitms29.backendH.domain.sync.entity.SyncType.getEnumFROMStringSyncType;
+
+@Service
+@RequiredArgsConstructor
+public class MyPageService {
+ private final ParticipationManager participationManager;
+ private final ListUtils listUtils;
+ private final SyncReader syncReader;
+ private final ParticipationReader participationReader;
+ private final UserReader userReader;
+ private final SyncReviewAppender syncReviewAppender;
+ private final FavoriteSyncReader favoriteSyncReader;
+ private final UserCategoryModifier userCategoryModifier;
+ private final AwsS3Service awsS3Service;
+ private final CategoryReader categoryReader;
+ private final UserCategoryReader userCategoryReader;
+ public List getMySyncList(Long userId, int take){
+ List syncList = syncReader.findAllByUserId(userId);
+ List syncInfoResponseDtos = syncList.stream()
+ .map( sync -> SyncInfoResponseDto.of(
+ sync.getId(),
+ sync.getSyncType(),
+ sync.getType(),
+ sync.getImage(),
+ participationManager.countParticipationBySyncId(sync.getId()),
+ sync.getMember_max(),
+ sync.getSyncName(),
+ sync.getLocation(),
+ sync.getDate()
+ )).toList();
+ return listUtils.getListByTake(syncInfoResponseDtos, take);
+ }
+ public List getJoinSyncList(Long userId, int take){
+ List participations = participationReader.findAllByUserId(userId);
+ List syncList = participations.stream().map(participation -> syncReader.findById(participation.getSync().getId())).toList();
+ List syncInfoResponseDtos = syncList.stream()
+ .map( sync -> SyncInfoResponseDto.of(
+ sync.getId(),
+ sync.getSyncType(),
+ sync.getType(),
+ sync.getImage(),
+ participationManager.countParticipationBySyncId(sync.getId()),
+ sync.getMember_max(),
+ sync.getSyncName(),
+ sync.getLocation(),
+ sync.getDate()
+ )).toList();
+ return listUtils.getListByTake(syncInfoResponseDtos, take);
+ }
+ public UserInfoResponseDto getMyInfo(Long userId){
+ List detailTypes = userCategoryReader.findAllByUserId(userId).stream().map(userCategory -> userCategory.getCategory().getName()).toList();
+ return UserInfoResponseDto.of(userReader.findByUserId(userId),detailTypes);
+ }
+ public CreateReviewResponse createReview(Long userId, CreateReviewRequest createReviewRequest){
+ SyncReview syncReview = SyncReview.createReview(User.from(userId),Sync.from(createReviewRequest.syncId()), createReviewRequest.content() );
+ syncReview = syncReviewAppender.createReview(syncReview);
+ return CreateReviewResponse.of(syncReview);
+ }
+ public List getBookMarkSyncList(Long userId, int take){
+ List favoriteSyncs = favoriteSyncReader.findAllByUserId(userId);
+ List syncList = favoriteSyncs.stream().map(favoriteSync -> syncReader.findById(favoriteSync.getSync().getId())).toList();
+ List syncInfoResponseDtos = syncList.stream()
+ .map( sync -> SyncInfoResponseDto.of(
+ sync.getId(),
+ sync.getSyncType(),
+ sync.getType(),
+ sync.getImage(),
+ participationManager.countParticipationBySyncId(sync.getId()),
+ sync.getMember_max(),
+ sync.getSyncName(),
+ sync.getLocation(),
+ sync.getDate()
+ )).toList();
+ return listUtils.getListByTake(syncInfoResponseDtos, take);
+ }
+ @Transactional
+ public void editProfile(Long userId, EditProfileRequest editProfileRequest){
+ User user = userReader.findByUserId(userId);
+ String image = awsS3Service.uploadImage(editProfileRequest.image());
+ user.updateProfile(image,editProfileRequest.name(), getEnumFROMStringGender(editProfileRequest.gender()), getEnumFROMStringSyncType(editProfileRequest.syncType()));
+ userCategoryModifier.deleteAllByUserId(user.getId());
+ List categories = editProfileRequest.detailTypes().stream().map(
+ detailType -> categoryReader.findByName(detailType))
+ .toList();
+ userCategoryModifier.saveAll(categories.stream().map(category -> createUserCategory(user,category)).toList());
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/user/service/OnBoardingService.java b/Main/src/main/java/com/kusitms29/backendH/api/user/service/OnBoardingService.java
new file mode 100644
index 0000000..a3e891a
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/user/service/OnBoardingService.java
@@ -0,0 +1,76 @@
+package com.kusitms29.backendH.api.user.service;
+
+import com.kusitms29.backendH.api.user.service.dto.request.OnBoardingRequestDto;
+import com.kusitms29.backendH.api.user.service.dto.response.OnBoardingResponseDto;
+import com.kusitms29.backendH.domain.category.entity.Category;
+import com.kusitms29.backendH.domain.category.service.CategoryReader;
+import com.kusitms29.backendH.domain.category.service.UserCategoryModifier;
+import com.kusitms29.backendH.domain.sync.entity.Gender;
+import com.kusitms29.backendH.domain.sync.entity.Language;
+import com.kusitms29.backendH.domain.sync.entity.SyncType;
+import com.kusitms29.backendH.domain.user.entity.User;
+import com.kusitms29.backendH.domain.category.entity.UserCategory;
+import com.kusitms29.backendH.domain.user.service.UserReader;
+import com.kusitms29.backendH.infra.config.AwsS3Service;
+import com.kusitms29.backendH.infra.external.UniversityClient;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import static com.kusitms29.backendH.domain.category.entity.UserCategory.createUserCategory;
+
+@Slf4j
+@RequiredArgsConstructor
+@Transactional
+@Service
+public class OnBoardingService {
+ private final UniversityClient universityClient;
+ private final AwsS3Service awsS3Service;
+
+ private final UserReader userReader;
+ private final CategoryReader categoryReader;
+ private final UserCategoryModifier userCategoryModifier;
+
+ @Transactional
+ public void onBoardingUser(Long userId, MultipartFile profileImage, OnBoardingRequestDto requestDto) {
+ User user = userReader.findByUserId(userId);
+
+ Language lan = Language.getEnumLanguageFromStringLanguage(requestDto.getLanguage());
+ String imageUrl = awsS3Service.uploadImage(profileImage);
+ Gender gen = Gender.getEnumFROMStringGender(requestDto.getGender());
+ SyncType syncType = SyncType.getEnumFROMStringSyncType(requestDto.getSyncType());
+ universityClient.isValidUniversity(requestDto.getUniversity());
+
+ user.updateOnBoardingWithoutCategory(lan.name(), imageUrl, requestDto.getUserName(),
+ requestDto.getCountryName(), gen.name(), requestDto.getUniversity(), requestDto.getEmail(), syncType.name());
+
+ List categories = requestDto.getDetailTypes().stream().map(
+ detailType -> categoryReader.findByName(detailType))
+ .toList();
+ userCategoryModifier.saveAll(categories.stream().map(category -> createUserCategory(user,category)).toList());
+ }
+
+// private List createUserCategory(User user, Map categoryMap) {
+// List categoryNames = new ArrayList<>();
+// for (Map.Entry entry : categoryMap.entrySet()) {
+// if (entry.getValue()) {
+// Category category = categoryReader.findByName(entry.getKey());
+// UserCategory userCategory = UserCategory.builder()
+// .user(user)
+// .category(category)
+// .build();
+// userCategoryModifier.save(userCategory);
+// categoryNames.add(category.getName());
+// }
+// }
+// return categoryNames;
+// }
+
+}
+
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/user/service/UserService.java b/Main/src/main/java/com/kusitms29/backendH/api/user/service/UserService.java
new file mode 100644
index 0000000..9827bec
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/user/service/UserService.java
@@ -0,0 +1,23 @@
+package com.kusitms29.backendH.api.user.service;
+
+import com.kusitms29.backendH.api.community.service.dto.response.BannerImageResponseDto;
+import com.kusitms29.backendH.domain.user.entity.User;
+import com.kusitms29.backendH.domain.user.service.UserReader;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Slf4j
+@RequiredArgsConstructor
+@Transactional
+@Service
+public class UserService {
+ private final UserReader userReader;
+
+ public BannerImageResponseDto getLoginUserImage(Long userId) {
+ User user = userReader.findByUserId(userId);
+ String image = user.getProfile();
+ return BannerImageResponseDto.of(image);
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/CategoryRequestDto.java b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/CategoryRequestDto.java
new file mode 100644
index 0000000..b5b2341
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/CategoryRequestDto.java
@@ -0,0 +1,18 @@
+package com.kusitms29.backendH.api.user.service.dto.request;
+
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+import java.util.Map;
+
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@Getter
+public class CategoryRequestDto {
+ private Map foreignLanguage;
+ private Map cultureArt;
+ private Map travelCompanion;
+ private Map activity;
+ private Map foodAndDrink;
+ private Map etc;
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/CountryCalloutRequestDto.java b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/CountryCalloutRequestDto.java
new file mode 100644
index 0000000..cb5ecbb
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/CountryCalloutRequestDto.java
@@ -0,0 +1,16 @@
+package com.kusitms29.backendH.api.user.service.dto.request;
+
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@Getter
+@Setter
+public class CountryCalloutRequestDto {
+ private Integer page;
+ private Integer perPage;
+ private String language;
+}
+
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/CreateReviewRequest.java b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/CreateReviewRequest.java
new file mode 100644
index 0000000..827b011
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/CreateReviewRequest.java
@@ -0,0 +1,7 @@
+package com.kusitms29.backendH.api.user.service.dto.request;
+
+public record CreateReviewRequest(
+ Long syncId,
+ String content
+) {
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/EditProfileRequest.java b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/EditProfileRequest.java
new file mode 100644
index 0000000..b069deb
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/EditProfileRequest.java
@@ -0,0 +1,14 @@
+package com.kusitms29.backendH.api.user.service.dto.request;
+
+import lombok.Setter;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.List;
+public record EditProfileRequest(
+ MultipartFile image,
+ String name,
+ String gender,
+ String syncType,
+ List detailTypes
+) {
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/EmailVerificationRequestDto.java b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/EmailVerificationRequestDto.java
new file mode 100644
index 0000000..842c15d
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/EmailVerificationRequestDto.java
@@ -0,0 +1,12 @@
+package com.kusitms29.backendH.api.user.service.dto.request;
+
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@Getter
+public class EmailVerificationRequestDto {
+ private String email;
+ private String code;
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/OnBoardingRequestDto.java b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/OnBoardingRequestDto.java
new file mode 100644
index 0000000..4770a32
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/OnBoardingRequestDto.java
@@ -0,0 +1,20 @@
+package com.kusitms29.backendH.api.user.service.dto.request;
+
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@Getter
+public class OnBoardingRequestDto {
+ private String language;
+ private String userName;
+ private String countryName;
+ private String gender;
+ private String university;
+ private String email;
+ private String syncType;
+ private List detailTypes;
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/ReceiverInfoRequestDto.java b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/ReceiverInfoRequestDto.java
new file mode 100644
index 0000000..99fe648
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/ReceiverInfoRequestDto.java
@@ -0,0 +1,11 @@
+package com.kusitms29.backendH.api.user.service.dto.request;
+
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@Getter
+public class ReceiverInfoRequestDto {
+ private String toEmail;
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/UniversityRequestDto.java b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/UniversityRequestDto.java
new file mode 100644
index 0000000..53d3f8c
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/UniversityRequestDto.java
@@ -0,0 +1,11 @@
+package com.kusitms29.backendH.api.user.service.dto.request;
+
+import lombok.*;
+
+@AllArgsConstructor
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@Getter
+@Setter
+public class UniversityRequestDto {
+ String univName;
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/UserSignInRequestDto.java b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/UserSignInRequestDto.java
new file mode 100644
index 0000000..c4e02b6
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/UserSignInRequestDto.java
@@ -0,0 +1,11 @@
+package com.kusitms29.backendH.api.user.service.dto.request;
+
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@Getter
+public class UserSignInRequestDto {
+ private String platform;
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/schoolEmail/CalloutSchoolEmailRequestDto.java b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/schoolEmail/CalloutSchoolEmailRequestDto.java
new file mode 100644
index 0000000..2e66e7d
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/schoolEmail/CalloutSchoolEmailRequestDto.java
@@ -0,0 +1,14 @@
+package com.kusitms29.backendH.api.user.service.dto.request.schoolEmail;
+
+import lombok.*;
+
+@AllArgsConstructor
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@Getter
+@Setter
+public class CalloutSchoolEmailRequestDto {
+ private String key;
+ private String email;
+ private String univName;
+ private Boolean univ_check;
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/schoolEmail/CalloutSchoolEmailVerificationRequestDto.java b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/schoolEmail/CalloutSchoolEmailVerificationRequestDto.java
new file mode 100644
index 0000000..83a771d
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/schoolEmail/CalloutSchoolEmailVerificationRequestDto.java
@@ -0,0 +1,14 @@
+package com.kusitms29.backendH.api.user.service.dto.request.schoolEmail;
+
+import lombok.*;
+
+@AllArgsConstructor
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@Getter
+@Setter
+public class CalloutSchoolEmailVerificationRequestDto {
+ private String key;
+ private String email;
+ private String univName;
+ private int code;
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/schoolEmail/SchoolEmailRequestDto.java b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/schoolEmail/SchoolEmailRequestDto.java
new file mode 100644
index 0000000..e296d4f
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/schoolEmail/SchoolEmailRequestDto.java
@@ -0,0 +1,12 @@
+package com.kusitms29.backendH.api.user.service.dto.request.schoolEmail;
+
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@Getter
+public class SchoolEmailRequestDto {
+ private String email;
+ private String univName;
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/schoolEmail/SchoolEmailVerificationRequestDto.java b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/schoolEmail/SchoolEmailVerificationRequestDto.java
new file mode 100644
index 0000000..8524b0a
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/request/schoolEmail/SchoolEmailVerificationRequestDto.java
@@ -0,0 +1,13 @@
+package com.kusitms29.backendH.api.user.service.dto.request.schoolEmail;
+
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@Getter
+public class SchoolEmailVerificationRequestDto {
+ private String univName;
+ private String email;
+ private int code;
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/response/CountryDataDto.java b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/response/CountryDataDto.java
new file mode 100644
index 0000000..f65728a
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/response/CountryDataDto.java
@@ -0,0 +1,17 @@
+package com.kusitms29.backendH.api.user.service.dto.response;
+
+import lombok.Builder;
+import lombok.Getter;
+
+@Builder
+@Getter
+public class CountryDataDto {
+ private String ISO_alpha2;
+ private String ISO_alpha3;
+ private Integer ISO_numeric;
+ private String 대륙명_공통_대륙코드;
+ private String 대륙명_행정표준코드;
+ private String 대륙명_외교부_직제;
+ private String 영문명;
+ private String 한글명;
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/response/CountryResponseDto.java b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/response/CountryResponseDto.java
new file mode 100644
index 0000000..b669a5d
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/response/CountryResponseDto.java
@@ -0,0 +1,17 @@
+package com.kusitms29.backendH.api.user.service.dto.response;
+
+import lombok.Builder;
+import lombok.Getter;
+
+import java.util.List;
+
+@Builder
+@Getter
+public class CountryResponseDto {
+ private Integer currentCount;
+ private List data;
+ private Integer matchCount;
+ private Integer page;
+ private Integer perPage;
+ private Integer totalCount;
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/response/CreateReviewResponse.java b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/response/CreateReviewResponse.java
new file mode 100644
index 0000000..c1671f0
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/response/CreateReviewResponse.java
@@ -0,0 +1,12 @@
+package com.kusitms29.backendH.api.user.service.dto.response;
+
+import com.kusitms29.backendH.domain.sync.entity.SyncReview;
+
+public record CreateReviewResponse(
+ Long syncId,
+ Long userId
+) {
+ public static CreateReviewResponse of(SyncReview syncReview){
+ return new CreateReviewResponse(syncReview.getSync().getId(), syncReview.getUser().getId());
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/response/EmailVerificationResponseDto.java b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/response/EmailVerificationResponseDto.java
new file mode 100644
index 0000000..c2a44ea
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/response/EmailVerificationResponseDto.java
@@ -0,0 +1,17 @@
+package com.kusitms29.backendH.api.user.service.dto.response;
+
+import lombok.Builder;
+import lombok.Getter;
+
+@Builder
+@Getter
+public class EmailVerificationResponseDto {
+
+ private boolean authResult;
+
+ public static EmailVerificationResponseDto of(Boolean authResult) {
+ return EmailVerificationResponseDto.builder()
+ .authResult(authResult)
+ .build();
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/response/OnBoardingResponseDto.java b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/response/OnBoardingResponseDto.java
new file mode 100644
index 0000000..ca319e4
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/response/OnBoardingResponseDto.java
@@ -0,0 +1,35 @@
+package com.kusitms29.backendH.api.user.service.dto.response;
+
+import lombok.Builder;
+import lombok.Getter;
+
+import java.util.List;
+
+@Builder
+@Getter
+public class OnBoardingResponseDto {
+ private String language;
+ private String profileImage;
+ private String userName;
+ private String countryName;
+ private String gender;
+ private String university;
+ private String email;
+ private String syncType;
+ private List detailTypes;
+
+ public static OnBoardingResponseDto of(String language, String profileImage, String userName, String countryName, String gender,
+ String university, String email, String syncType, List detailTypes) {
+ return OnBoardingResponseDto.builder()
+ .language(language)
+ .profileImage(profileImage)
+ .userName(userName)
+ .countryName(countryName)
+ .gender(gender)
+ .university(university)
+ .email(email)
+ .syncType(syncType)
+ .detailTypes(detailTypes)
+ .build();
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/response/UserAuthResponseDto.java b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/response/UserAuthResponseDto.java
new file mode 100644
index 0000000..a51bd4a
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/response/UserAuthResponseDto.java
@@ -0,0 +1,32 @@
+package com.kusitms29.backendH.api.user.service.dto.response;
+
+import com.kusitms29.backendH.domain.user.entity.User;
+import com.kusitms29.backendH.infra.config.auth.TokenInfo;
+import lombok.Builder;
+import lombok.Getter;
+
+@Builder
+@Getter
+public class UserAuthResponseDto {
+ private Long userId;
+ private String email;
+ private String name;
+ private String picture;
+ private String accessToken;
+ private String refreshToken;
+ private Boolean isFirst;
+ private String sessionId;
+
+ public static UserAuthResponseDto of(User user, TokenInfo token, Boolean isFirst) {
+ return UserAuthResponseDto.builder()
+ .userId(user.getId())
+ .email(user.getEmail())
+ .name(user.getUserName())
+ .picture(user.getProfile())
+ .isFirst(isFirst)
+ .accessToken(token.getAccessToken())
+ .refreshToken(token.getRefreshToken())
+ .sessionId(user.getSessionId())
+ .build();
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/response/UserInfoResponseDto.java b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/response/UserInfoResponseDto.java
new file mode 100644
index 0000000..24290bc
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/response/UserInfoResponseDto.java
@@ -0,0 +1,39 @@
+package com.kusitms29.backendH.api.user.service.dto.response;
+
+import com.kusitms29.backendH.domain.user.entity.User;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+
+import java.util.List;
+
+@Getter
+@Builder
+public class UserInfoResponseDto {
+ private Long userId;
+ private String image;
+ private String name;
+ private String university;
+ private String syncType;
+ private List detailTypes;
+ private String gender;
+
+ public UserInfoResponseDto() {
+ // 기본 생성자
+ }
+
+ public UserInfoResponseDto(Long userId, String image, String name, String university, String syncType, List detailTypes, String gender) {
+ this.userId = userId;
+ this.image = image;
+ this.name = name;
+ this.university = university;
+ this.syncType = syncType;
+ this.detailTypes = detailTypes;
+ this.gender = gender;
+ }
+
+ public static UserInfoResponseDto of(User user, List detailTypes) {
+ return new UserInfoResponseDto(user.getId(), user.getProfile(), user.getUserName(), user.getUniversity(), String.valueOf(user.getSyncType()), detailTypes, String.valueOf(user.getGender()));
+ }
+
+}
\ No newline at end of file
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/response/UserSignUpResponseDto.java b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/response/UserSignUpResponseDto.java
new file mode 100644
index 0000000..29177e2
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/response/UserSignUpResponseDto.java
@@ -0,0 +1,16 @@
+package com.kusitms29.backendH.api.user.service.dto.response;
+
+import lombok.Builder;
+import lombok.Getter;
+
+@Builder
+@Getter
+public class UserSignUpResponseDto {
+ private String name;
+
+ public static UserSignUpResponseDto of(String name) {
+ return UserSignUpResponseDto.builder()
+ .name(name)
+ .build();
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/response/schoolEmail/CalloutErrorResponse.java b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/response/schoolEmail/CalloutErrorResponse.java
new file mode 100644
index 0000000..7e03d6c
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/response/schoolEmail/CalloutErrorResponse.java
@@ -0,0 +1,14 @@
+package com.kusitms29.backendH.api.user.service.dto.response.schoolEmail;
+
+import lombok.*;
+
+@Builder
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+public class CalloutErrorResponse {
+ private String status;
+ private boolean success;
+ private String message;
+}
\ No newline at end of file
diff --git a/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/response/schoolEmail/CalloutSchoolEmailVerificationResponseDto.java b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/response/schoolEmail/CalloutSchoolEmailVerificationResponseDto.java
new file mode 100644
index 0000000..5da2007
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/api/user/service/dto/response/schoolEmail/CalloutSchoolEmailVerificationResponseDto.java
@@ -0,0 +1,13 @@
+package com.kusitms29.backendH.api.user.service.dto.response.schoolEmail;
+
+import lombok.Builder;
+import lombok.Getter;
+
+@Builder
+@Getter
+public class CalloutSchoolEmailVerificationResponseDto {
+ private boolean success;
+ private String univName;
+ private String certified_email;
+ private String certified_date;
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/category/entity/Category.java b/Main/src/main/java/com/kusitms29/backendH/domain/category/entity/Category.java
new file mode 100644
index 0000000..74788c5
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/category/entity/Category.java
@@ -0,0 +1,22 @@
+package com.kusitms29.backendH.domain.category.entity;
+
+import jakarta.persistence.*;
+import lombok.*;
+
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@AllArgsConstructor
+@Builder
+@Getter
+@Table(name = "category")
+@Entity
+public class Category {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "category_id")
+ private Long id;
+
+ private String name;
+ @Enumerated(EnumType.STRING)
+ private Type type;
+
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/category/entity/Type.java b/Main/src/main/java/com/kusitms29/backendH/domain/category/entity/Type.java
new file mode 100644
index 0000000..366be8b
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/category/entity/Type.java
@@ -0,0 +1,37 @@
+package com.kusitms29.backendH.domain.category.entity;
+
+import com.kusitms29.backendH.global.error.exception.InvalidValueException;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Arrays;
+
+import static com.kusitms29.backendH.global.error.ErrorCode.INVALID_TYPE;
+
+@RequiredArgsConstructor
+@Getter
+public enum Type {
+ //외국어 : 언어 교환, 튜터링, 스터디, 기타
+ //문화/예술 : 문화/예술, 영화, 드라마, 미술/디자인, 공연/전시, 음악, 기타
+ //여행/동행 : 관광지, 자연, 휴양, 기타
+ //액티비티 : 러닝/산책, 등산, 클라이밍, 자전거, 축구, 서핑, 테니스, 볼링, 탁구, 기타
+ //푸드드링크 : 맛집, 카페, 술, 기타
+ //기타
+ LANGUAGE("외국어"),
+ ENTERTAINMENT("문화/예술"),
+ TRAVEL("여행/동행"),
+ ACTIVITY("액티비티"),
+ FOOD("푸드드링크"),
+ ETC("기타");
+
+ private final String stringType;
+ public static Type getEnumTypeFromStringType(String stringType) {
+ if (stringType == null) {
+ return null;
+ }
+ return Arrays.stream(values())
+ .filter(type -> type.stringType.equals(stringType))
+ .findFirst()
+ .orElseThrow(() -> new InvalidValueException(INVALID_TYPE));
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/category/entity/UserCategory.java b/Main/src/main/java/com/kusitms29/backendH/domain/category/entity/UserCategory.java
new file mode 100644
index 0000000..d4dd2e5
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/category/entity/UserCategory.java
@@ -0,0 +1,34 @@
+package com.kusitms29.backendH.domain.category.entity;
+
+import com.kusitms29.backendH.domain.user.entity.User;
+import jakarta.persistence.*;
+import lombok.*;
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@AllArgsConstructor
+@Builder
+@Getter
+@Table(name = "user_category")
+@Entity
+public class UserCategory {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "user_category_id")
+ private Long id;
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "user_id")
+ private User user;
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "category_id")
+ private Category category;
+
+ public void updateUserCategory(User user, Category category){
+ this.user = user;
+ this.category = category;
+ }
+ public static UserCategory createUserCategory(User user, Category category){
+ return UserCategory.builder()
+ .user(user)
+ .category(category)
+ .build();
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/category/repository/CategoryRepository.java b/Main/src/main/java/com/kusitms29/backendH/domain/category/repository/CategoryRepository.java
new file mode 100644
index 0000000..4de176d
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/category/repository/CategoryRepository.java
@@ -0,0 +1,9 @@
+package com.kusitms29.backendH.domain.category.repository;
+import org.springframework.data.jpa.repository.JpaRepository;
+import com.kusitms29.backendH.domain.category.entity.Category;
+
+import java.util.Optional;
+
+public interface CategoryRepository extends JpaRepository {
+ Optional findByName(String name);
+}
\ No newline at end of file
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/category/repository/UserCategoryRepository.java b/Main/src/main/java/com/kusitms29/backendH/domain/category/repository/UserCategoryRepository.java
new file mode 100644
index 0000000..4a628a2
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/category/repository/UserCategoryRepository.java
@@ -0,0 +1,11 @@
+package com.kusitms29.backendH.domain.category.repository;
+
+import com.kusitms29.backendH.domain.category.entity.UserCategory;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.util.List;
+
+public interface UserCategoryRepository extends JpaRepository {
+ List findAllByUserId(Long userId);
+ void deleteAllByUserId(Long userId);
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/category/service/CategoryReader.java b/Main/src/main/java/com/kusitms29/backendH/domain/category/service/CategoryReader.java
new file mode 100644
index 0000000..7c7739e
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/category/service/CategoryReader.java
@@ -0,0 +1,24 @@
+package com.kusitms29.backendH.domain.category.service;
+
+import com.kusitms29.backendH.domain.category.entity.Category;
+import com.kusitms29.backendH.domain.category.repository.CategoryRepository;
+import com.kusitms29.backendH.global.error.exception.EntityNotFoundException;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import static com.kusitms29.backendH.global.error.ErrorCode.CATEGORY_NOT_FOUND;
+
+@Slf4j
+@RequiredArgsConstructor
+@Transactional
+@Service
+public class CategoryReader {
+ private final CategoryRepository categoryRepository;
+
+ public Category findByName(String name) {
+ return categoryRepository.findByName(name)
+ .orElseThrow(() -> new EntityNotFoundException(CATEGORY_NOT_FOUND));
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/category/service/UserCategoryManager.java b/Main/src/main/java/com/kusitms29/backendH/domain/category/service/UserCategoryManager.java
new file mode 100644
index 0000000..30ff267
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/category/service/UserCategoryManager.java
@@ -0,0 +1,16 @@
+package com.kusitms29.backendH.domain.category.service;
+
+import com.kusitms29.backendH.domain.category.entity.Type;
+import com.kusitms29.backendH.domain.category.entity.UserCategory;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+@RequiredArgsConstructor
+public class UserCategoryManager {
+ public List getTypeByUserCategories(List userCategories){
+ return userCategories.stream().map(userCategory -> userCategory.getCategory().getType()).toList();
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/category/service/UserCategoryModifier.java b/Main/src/main/java/com/kusitms29/backendH/domain/category/service/UserCategoryModifier.java
new file mode 100644
index 0000000..b411128
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/category/service/UserCategoryModifier.java
@@ -0,0 +1,26 @@
+package com.kusitms29.backendH.domain.category.service;
+
+import com.kusitms29.backendH.domain.category.entity.UserCategory;
+import com.kusitms29.backendH.domain.category.repository.CategoryRepository;
+import com.kusitms29.backendH.domain.category.repository.UserCategoryRepository;
+import com.kusitms29.backendH.domain.user.entity.User;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+@Slf4j
+@RequiredArgsConstructor
+@Transactional
+@Service
+public class UserCategoryModifier {
+ private final UserCategoryRepository userCategoryRepository;
+
+ public void save(UserCategory userCategory) {
+ userCategoryRepository.save(userCategory);
+ }
+ public void deleteAllByUserId(Long userId){ userCategoryRepository.deleteAllByUserId(userId);}
+ public void saveAll(List userCategories){ userCategoryRepository.saveAll(userCategories);}
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/category/service/UserCategoryReader.java b/Main/src/main/java/com/kusitms29/backendH/domain/category/service/UserCategoryReader.java
new file mode 100644
index 0000000..6751355
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/category/service/UserCategoryReader.java
@@ -0,0 +1,17 @@
+package com.kusitms29.backendH.domain.category.service;
+
+import com.kusitms29.backendH.domain.category.entity.UserCategory;
+import com.kusitms29.backendH.domain.category.repository.UserCategoryRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+@RequiredArgsConstructor
+public class UserCategoryReader {
+ private final UserCategoryRepository userCategoryRepository;
+ public List findAllByUserId(Long userId){
+ return userCategoryRepository.findAllByUserId(userId);
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/chat/entity/ChatContent.java b/Main/src/main/java/com/kusitms29/backendH/domain/chat/entity/ChatContent.java
new file mode 100644
index 0000000..080ce0a
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/chat/entity/ChatContent.java
@@ -0,0 +1,24 @@
+package com.kusitms29.backendH.domain.chat.entity;
+
+import lombok.Builder;
+import lombok.Getter;
+
+import java.time.LocalDateTime;
+
+@Builder
+@Getter
+public class ChatContent {
+ private String userName;
+ private String content;
+ private LocalDateTime time;
+
+ public static ChatContent createChatContent(String userName, String content, Room room) {
+ ChatContent chatContent = ChatContent.builder()
+ .userName(userName)
+ .content(content)
+ .time(LocalDateTime.now())
+ .build();
+ room.addChatContent(chatContent);
+ return chatContent;
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/chat/entity/ChatUser.java b/Main/src/main/java/com/kusitms29/backendH/domain/chat/entity/ChatUser.java
new file mode 100644
index 0000000..16e222c
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/chat/entity/ChatUser.java
@@ -0,0 +1,21 @@
+package com.kusitms29.backendH.domain.chat.entity;
+
+import com.kusitms29.backendH.domain.user.entity.User;
+import lombok.Builder;
+import lombok.Getter;
+
+@Getter
+@Builder
+public class ChatUser {
+ private String sessionId;
+ private String name;
+ private String profile;
+
+ public static ChatUser createChatUser(User user) {
+ return ChatUser.builder()
+ .sessionId(user.getSessionId())
+ .name(user.getUserName())
+ .profile(user.getProfile())
+ .build();
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/chat/entity/Room.java b/Main/src/main/java/com/kusitms29/backendH/domain/chat/entity/Room.java
new file mode 100644
index 0000000..c2241b6
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/chat/entity/Room.java
@@ -0,0 +1,56 @@
+package com.kusitms29.backendH.domain.chat.entity;
+
+import lombok.Builder;
+import lombok.Getter;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Getter
+@Builder
+@Document(collection = "room")
+public class Room {
+ @Id
+ private String roomId;
+ private String roomName;
+ private String roomSession;
+ private String syncName;
+
+ @Builder.Default
+ private List chatUserList = new ArrayList<>();
+ @Builder.Default
+ private List chatContentList = new ArrayList<>();
+
+ public static Room createRoom(List users,String roomName) {
+ Room room = Room.builder().
+ roomName(roomName).
+ build();
+ for(ChatUser chatUser : users){
+ room.addChatRoom(chatUser);
+ }
+ return room;
+ }
+ public static Room createNewRoom(String roomName) {
+ Room room = Room.builder()
+ .roomName(roomName)
+ .build();
+ return room;
+ }
+ public void addChatContent(ChatContent content) {
+ this.chatContentList.add(content);
+ }
+
+ public void addChatRoom(ChatUser chatUser) {
+ this.chatUserList.add(chatUser);
+ }
+ public Room(String roomId, String roomName, String roomSession, String syncName, List chatUserList, List chatContentList) {
+ this.roomId = roomId;
+ this.roomName = roomName;
+ this.roomSession = roomSession;
+ this.syncName = syncName;
+ this.chatUserList = chatUserList != null ? chatUserList : new ArrayList<>();
+ this.chatContentList = chatContentList != null ? chatContentList : new ArrayList<>();
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/chat/repository/RoomRepository.java b/Main/src/main/java/com/kusitms29/backendH/domain/chat/repository/RoomRepository.java
new file mode 100644
index 0000000..8f1731f
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/chat/repository/RoomRepository.java
@@ -0,0 +1,7 @@
+package com.kusitms29.backendH.domain.chat.repository;
+
+import com.kusitms29.backendH.domain.chat.entity.Room;
+import org.springframework.data.mongodb.repository.MongoRepository;
+
+public interface RoomRepository extends MongoRepository {
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/chat/service/RoomAppender.java b/Main/src/main/java/com/kusitms29/backendH/domain/chat/service/RoomAppender.java
new file mode 100644
index 0000000..87c28b4
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/chat/service/RoomAppender.java
@@ -0,0 +1,40 @@
+package com.kusitms29.backendH.domain.chat.service;
+
+import com.kusitms29.backendH.domain.chat.entity.ChatUser;
+import com.kusitms29.backendH.domain.chat.entity.Room;
+import com.kusitms29.backendH.domain.chat.repository.RoomRepository;
+import com.kusitms29.backendH.domain.user.entity.User;
+import com.kusitms29.backendH.infra.external.fcm.service.PushNotificationService;
+import jakarta.transaction.Transactional;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.UUID;
+
+@Service
+@RequiredArgsConstructor
+public class RoomAppender {
+ private final RoomRepository roomRepository;
+ private final PushNotificationService pushNotificationService;
+ @Transactional
+ public void createRoom(List userList, Boolean isPossible, Long syncId){
+ if (isPossible) {
+ Room room = roomRepository.save(
+ Room.createRoom(userList.stream().map(
+ user -> ChatUser.createChatUser(user) )
+ .toList(),
+ generateRandomUuid(syncId)
+ )
+ );
+
+ //채팅방 개설 알림
+ pushNotificationService.sendChatRoomNotice(userList, syncId, room.getRoomSession());
+ }
+ }
+ private String generateRandomUuid(Long syncId) {
+ UUID randomUuid = UUID.randomUUID();
+ String uuidAsString = randomUuid.toString().replace("-", "");
+ return syncId + "_" + uuidAsString.substring(0, 6);
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/comment/entity/Comment.java b/Main/src/main/java/com/kusitms29/backendH/domain/comment/entity/Comment.java
new file mode 100644
index 0000000..02884c3
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/comment/entity/Comment.java
@@ -0,0 +1,35 @@
+package com.kusitms29.backendH.domain.comment.entity;
+
+import com.kusitms29.backendH.global.common.BaseEntity;
+import com.kusitms29.backendH.domain.post.entity.Post;
+import com.kusitms29.backendH.domain.user.entity.User;
+import jakarta.persistence.*;
+import lombok.*;
+import org.hibernate.annotations.ColumnDefault;
+
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@AllArgsConstructor
+@Builder
+@Getter
+@Table(name = "comment")
+@Entity
+public class Comment extends BaseEntity {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "comment_id")
+ private Long id;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "user_id")
+ private User user;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "post_id")
+ private Post post;
+
+ private String content;
+
+ @ColumnDefault("0")
+ @Builder.Default()
+ private int reported = 0;
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/comment/entity/CommentLike.java b/Main/src/main/java/com/kusitms29/backendH/domain/comment/entity/CommentLike.java
new file mode 100644
index 0000000..5a6c9b1
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/comment/entity/CommentLike.java
@@ -0,0 +1,27 @@
+package com.kusitms29.backendH.domain.comment.entity;
+
+import com.kusitms29.backendH.global.common.BaseEntity;
+import com.kusitms29.backendH.domain.user.entity.User;
+import jakarta.persistence.*;
+import lombok.*;
+
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@AllArgsConstructor
+@Builder
+@Getter
+@Table(name = "commentLike")
+@Entity
+public class CommentLike extends BaseEntity {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "comment_like_id")
+ private Long id;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "user_id")
+ private User user;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "comment_id")
+ private Comment comment;
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/comment/entity/Reply.java b/Main/src/main/java/com/kusitms29/backendH/domain/comment/entity/Reply.java
new file mode 100644
index 0000000..5c16168
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/comment/entity/Reply.java
@@ -0,0 +1,34 @@
+package com.kusitms29.backendH.domain.comment.entity;
+
+import com.kusitms29.backendH.global.common.BaseEntity;
+import com.kusitms29.backendH.domain.user.entity.User;
+import jakarta.persistence.*;
+import lombok.*;
+import org.hibernate.annotations.ColumnDefault;
+
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@AllArgsConstructor
+@Builder
+@Getter
+@Table(name = "reply")
+@Entity
+public class Reply extends BaseEntity {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "reply_id")
+ private Long id;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "user_id")
+ private User user;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "comment_id")
+ private Comment comment;
+
+ private String content;
+
+ @ColumnDefault("0")
+ @Builder.Default()
+ private int reported = 0;
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/comment/entity/ReplyLike.java b/Main/src/main/java/com/kusitms29/backendH/domain/comment/entity/ReplyLike.java
new file mode 100644
index 0000000..5df53ba
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/comment/entity/ReplyLike.java
@@ -0,0 +1,26 @@
+package com.kusitms29.backendH.domain.comment.entity;
+
+import com.kusitms29.backendH.domain.user.entity.User;
+import jakarta.persistence.*;
+import lombok.*;
+
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@AllArgsConstructor
+@Builder
+@Getter
+@Table(name = "reply_like")
+@Entity
+public class ReplyLike {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "reply_like_id")
+ private Long id;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "user_id")
+ private User user;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "reply_id")
+ private Reply reply;
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/comment/repository/CommentLikeRepository.java b/Main/src/main/java/com/kusitms29/backendH/domain/comment/repository/CommentLikeRepository.java
new file mode 100644
index 0000000..ed0ed7f
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/comment/repository/CommentLikeRepository.java
@@ -0,0 +1,21 @@
+package com.kusitms29.backendH.domain.comment.repository;
+
+import com.kusitms29.backendH.domain.comment.entity.CommentLike;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+import java.util.Optional;
+
+@Repository
+public interface CommentLikeRepository extends JpaRepository {
+ int countByCommentId(Long commentId);
+
+ boolean existsByCommentIdAndUserId(Long commentId, Long userId);
+
+ Optional findByCommentIdAndUserId(Long commentId, Long userId);
+
+ List findByCommentId(Long commentId);
+
+ void deleteAllByCommentId(Long commentId);
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/comment/repository/CommentRepository.java b/Main/src/main/java/com/kusitms29/backendH/domain/comment/repository/CommentRepository.java
new file mode 100644
index 0000000..733dc29
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/comment/repository/CommentRepository.java
@@ -0,0 +1,19 @@
+package com.kusitms29.backendH.domain.comment.repository;
+
+import com.kusitms29.backendH.domain.comment.entity.Comment;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+public interface CommentRepository extends JpaRepository {
+ int countByPostId(Long postId);
+ List findByPostId(Long postId);
+
+ @Modifying
+ @Transactional
+ @Query("UPDATE Comment c SET c.reported = c.reported + 1 WHERE c.id = :commentId")
+ void increaseReportedCount(Long commentId);
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/comment/repository/ReplyLikeRepository.java b/Main/src/main/java/com/kusitms29/backendH/domain/comment/repository/ReplyLikeRepository.java
new file mode 100644
index 0000000..3585c02
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/comment/repository/ReplyLikeRepository.java
@@ -0,0 +1,20 @@
+package com.kusitms29.backendH.domain.comment.repository;
+
+import com.kusitms29.backendH.domain.comment.entity.ReplyLike;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+import java.util.Optional;
+
+@Repository
+public interface ReplyLikeRepository extends JpaRepository {
+ int countByReplyId(Long replyId);
+ boolean existsByReplyIdAndUserId(Long replyId, Long userId);
+
+ Optional findByReplyIdAndUserId(Long replyId, Long userId);
+
+ List findByReplyId(Long replyId);
+
+ void deleteAllByReplyId(Long replyId);
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/comment/repository/ReplyRepository.java b/Main/src/main/java/com/kusitms29/backendH/domain/comment/repository/ReplyRepository.java
new file mode 100644
index 0000000..37c4e1b
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/comment/repository/ReplyRepository.java
@@ -0,0 +1,23 @@
+package com.kusitms29.backendH.domain.comment.repository;
+
+import com.kusitms29.backendH.domain.comment.entity.Reply;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+public interface ReplyRepository extends JpaRepository {
+ List findByCommentId(Long commentId);
+
+ int countByCommentId(Long commentId);
+
+ @Modifying
+ @Transactional
+ @Query("UPDATE Reply r SET r.reported = r.reported + 1 WHERE r.id = :replyId")
+ void increaseReportedCount(Long replyId);
+
+ void deleteAllByCommentId(Long commentId);
+
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/comment/service/CommentLikeManager.java b/Main/src/main/java/com/kusitms29/backendH/domain/comment/service/CommentLikeManager.java
new file mode 100644
index 0000000..928d63d
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/comment/service/CommentLikeManager.java
@@ -0,0 +1,18 @@
+package com.kusitms29.backendH.domain.comment.service;
+
+import com.kusitms29.backendH.domain.comment.repository.CommentLikeRepository;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Slf4j
+@RequiredArgsConstructor
+@Transactional
+@Service
+public class CommentLikeManager {
+ private final CommentLikeRepository commentLikeRepository;
+ public int countByCommentId(Long commentId) {
+ return commentLikeRepository.countByCommentId(commentId);
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/comment/service/CommentLikeModifier.java b/Main/src/main/java/com/kusitms29/backendH/domain/comment/service/CommentLikeModifier.java
new file mode 100644
index 0000000..2de0353
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/comment/service/CommentLikeModifier.java
@@ -0,0 +1,28 @@
+package com.kusitms29.backendH.domain.comment.service;
+
+import com.kusitms29.backendH.domain.comment.entity.CommentLike;
+import com.kusitms29.backendH.domain.comment.repository.CommentLikeRepository;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Slf4j
+@RequiredArgsConstructor
+@Transactional
+@Service
+public class CommentLikeModifier {
+ private final CommentLikeRepository commentLikeRepository;
+
+ public void save(CommentLike commentLike) {
+ commentLikeRepository.save(commentLike);
+ }
+
+ public void delete(CommentLike commentLike) {
+ commentLikeRepository.delete(commentLike);
+ }
+
+ public void deleteAllByCommentId(Long commentId) {
+ commentLikeRepository.deleteAllByCommentId(commentId);
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/comment/service/CommentLikeReader.java b/Main/src/main/java/com/kusitms29/backendH/domain/comment/service/CommentLikeReader.java
new file mode 100644
index 0000000..773cd9e
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/comment/service/CommentLikeReader.java
@@ -0,0 +1,35 @@
+package com.kusitms29.backendH.domain.comment.service;
+
+import com.kusitms29.backendH.domain.comment.entity.CommentLike;
+import com.kusitms29.backendH.domain.comment.repository.CommentLikeRepository;
+import com.kusitms29.backendH.global.error.exception.EntityNotFoundException;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+import java.util.Optional;
+
+import static com.kusitms29.backendH.global.error.ErrorCode.COMMENT_LIKE_NOT_FOUND;
+
+@Slf4j
+@RequiredArgsConstructor
+@Transactional
+@Service
+public class CommentLikeReader {
+ private final CommentLikeRepository commentLikeRepository;
+
+ public boolean existsByCommentIdAndUserId(Long commentId, Long userId) {
+ return commentLikeRepository.existsByCommentIdAndUserId(commentId, userId);
+ }
+ public CommentLike findByCommentIdAndUserId(Long commentId, Long userId) {
+ return commentLikeRepository.findByCommentIdAndUserId(commentId, userId)
+ .orElseThrow(() -> new EntityNotFoundException(COMMENT_LIKE_NOT_FOUND));
+ }
+
+ public List findByCommentId(Long commentId) {
+ return commentLikeRepository.findByCommentId(commentId);
+ }
+
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/comment/service/CommentManager.java b/Main/src/main/java/com/kusitms29/backendH/domain/comment/service/CommentManager.java
new file mode 100644
index 0000000..392ff99
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/comment/service/CommentManager.java
@@ -0,0 +1,18 @@
+package com.kusitms29.backendH.domain.comment.service;
+
+import com.kusitms29.backendH.domain.comment.repository.CommentRepository;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Slf4j
+@RequiredArgsConstructor
+@Transactional
+@Service
+public class CommentManager {
+ private final CommentRepository commentRepository;
+ public int countByPostId(Long postId) {
+ return commentRepository.countByPostId(postId);
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/comment/service/CommentModifier.java b/Main/src/main/java/com/kusitms29/backendH/domain/comment/service/CommentModifier.java
new file mode 100644
index 0000000..3b2cd52
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/comment/service/CommentModifier.java
@@ -0,0 +1,28 @@
+package com.kusitms29.backendH.domain.comment.service;
+
+import com.kusitms29.backendH.domain.comment.entity.Comment;
+import com.kusitms29.backendH.domain.comment.repository.CommentRepository;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Slf4j
+@RequiredArgsConstructor
+@Transactional
+@Service
+public class CommentModifier {
+ private final CommentRepository commentRepository;
+
+ public Comment save(Comment comment) {
+ return commentRepository.save(comment);
+ }
+
+ public void increaseReportedCount(Long commentId) {
+ commentRepository.increaseReportedCount(commentId);
+ }
+
+ public void delete(Comment comment) {
+ commentRepository.delete(comment);
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/comment/service/CommentReader.java b/Main/src/main/java/com/kusitms29/backendH/domain/comment/service/CommentReader.java
new file mode 100644
index 0000000..0b56824
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/comment/service/CommentReader.java
@@ -0,0 +1,29 @@
+package com.kusitms29.backendH.domain.comment.service;
+
+import com.kusitms29.backendH.domain.comment.entity.Comment;
+import com.kusitms29.backendH.domain.comment.repository.CommentRepository;
+import com.kusitms29.backendH.global.error.exception.EntityNotFoundException;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+import static com.kusitms29.backendH.global.error.ErrorCode.COMMENT_NOT_FOUND;
+
+@Slf4j
+@RequiredArgsConstructor
+@Transactional
+@Service
+public class CommentReader {
+ private final CommentRepository commentRepository;
+ public List findByPostId(Long postId) {
+ return commentRepository.findByPostId(postId);
+ }
+
+ public Comment findById(Long commentId) {
+ return commentRepository.findById(commentId)
+ .orElseThrow(() -> new EntityNotFoundException(COMMENT_NOT_FOUND));
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/comment/service/ReplyLikeManager.java b/Main/src/main/java/com/kusitms29/backendH/domain/comment/service/ReplyLikeManager.java
new file mode 100644
index 0000000..8f5fcb4
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/comment/service/ReplyLikeManager.java
@@ -0,0 +1,18 @@
+package com.kusitms29.backendH.domain.comment.service;
+
+import com.kusitms29.backendH.domain.comment.repository.ReplyLikeRepository;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Slf4j
+@RequiredArgsConstructor
+@Transactional
+@Service
+public class ReplyLikeManager {
+ private final ReplyLikeRepository replyLikeRepository;
+ public int countByReplyId(Long replyId) {
+ return replyLikeRepository.countByReplyId(replyId);
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/comment/service/ReplyLikeModifier.java b/Main/src/main/java/com/kusitms29/backendH/domain/comment/service/ReplyLikeModifier.java
new file mode 100644
index 0000000..176723a
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/comment/service/ReplyLikeModifier.java
@@ -0,0 +1,28 @@
+package com.kusitms29.backendH.domain.comment.service;
+
+import com.kusitms29.backendH.domain.comment.entity.Comment;
+import com.kusitms29.backendH.domain.comment.entity.ReplyLike;
+import com.kusitms29.backendH.domain.comment.repository.ReplyLikeRepository;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Slf4j
+@RequiredArgsConstructor
+@Transactional
+@Service
+public class ReplyLikeModifier {
+ private final ReplyLikeRepository replyLikeRepository;
+ public void save(ReplyLike replyLike) {
+ replyLikeRepository.save(replyLike);
+ }
+ public void delete(ReplyLike replyLike) {
+ replyLikeRepository.delete(replyLike);
+ }
+
+ public void deleteAllByReplyId(Long replyId) {
+ replyLikeRepository.deleteAllByReplyId(replyId);
+ }
+
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/comment/service/ReplyLikeReader.java b/Main/src/main/java/com/kusitms29/backendH/domain/comment/service/ReplyLikeReader.java
new file mode 100644
index 0000000..d3b11a2
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/comment/service/ReplyLikeReader.java
@@ -0,0 +1,34 @@
+package com.kusitms29.backendH.domain.comment.service;
+
+import com.kusitms29.backendH.domain.comment.entity.ReplyLike;
+import com.kusitms29.backendH.domain.comment.repository.ReplyLikeRepository;
+import com.kusitms29.backendH.global.error.exception.EntityNotFoundException;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+import static com.kusitms29.backendH.global.error.ErrorCode.REPLY_LIKE_NOT_FOUND;
+
+@Slf4j
+@RequiredArgsConstructor
+@Transactional
+@Service
+public class ReplyLikeReader {
+ private final ReplyLikeRepository replyLikeRepository;
+
+ public List findByReplyId(Long replyId) {
+ return replyLikeRepository.findByReplyId(replyId);
+ }
+
+ public boolean existsByReplyIdAndUserId(Long replyId, Long userId) {
+ return replyLikeRepository.existsByReplyIdAndUserId(replyId, userId);
+ }
+
+ public ReplyLike findByReplyIdAndUserId(Long replyId, Long userId) {
+ return replyLikeRepository.findByReplyIdAndUserId(replyId, userId)
+ .orElseThrow(() -> new EntityNotFoundException(REPLY_LIKE_NOT_FOUND));
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/comment/service/ReplyManager.java b/Main/src/main/java/com/kusitms29/backendH/domain/comment/service/ReplyManager.java
new file mode 100644
index 0000000..6b31967
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/comment/service/ReplyManager.java
@@ -0,0 +1,19 @@
+package com.kusitms29.backendH.domain.comment.service;
+
+import com.kusitms29.backendH.domain.comment.repository.ReplyRepository;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Slf4j
+@RequiredArgsConstructor
+@Transactional
+@Service
+public class ReplyManager {
+ private final ReplyRepository replyRepository;
+
+ public int countByCommentId(Long commentId) {
+ return replyRepository.countByCommentId(commentId);
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/comment/service/ReplyModifier.java b/Main/src/main/java/com/kusitms29/backendH/domain/comment/service/ReplyModifier.java
new file mode 100644
index 0000000..30b02da
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/comment/service/ReplyModifier.java
@@ -0,0 +1,32 @@
+package com.kusitms29.backendH.domain.comment.service;
+
+import com.kusitms29.backendH.domain.comment.entity.Reply;
+import com.kusitms29.backendH.domain.comment.repository.ReplyRepository;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Slf4j
+@RequiredArgsConstructor
+@Transactional
+@Service
+public class ReplyModifier {
+ private final ReplyRepository replyRepository;
+
+ public Reply save(Reply reply) {
+ return replyRepository.save(reply);
+ }
+
+ public void increaseReportedCount(Long replyId) {
+ replyRepository.increaseReportedCount(replyId);
+ }
+
+ public void delete(Reply reply) {
+ replyRepository.delete(reply);
+ }
+
+ public void deleteAllByCommentId(Long commentId) {
+ replyRepository.deleteAllByCommentId(commentId);
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/comment/service/ReplyReader.java b/Main/src/main/java/com/kusitms29/backendH/domain/comment/service/ReplyReader.java
new file mode 100644
index 0000000..56c88c6
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/comment/service/ReplyReader.java
@@ -0,0 +1,29 @@
+package com.kusitms29.backendH.domain.comment.service;
+
+import com.kusitms29.backendH.domain.comment.entity.Reply;
+import com.kusitms29.backendH.domain.comment.repository.ReplyRepository;
+import com.kusitms29.backendH.global.error.exception.EntityNotFoundException;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+import static com.kusitms29.backendH.global.error.ErrorCode.REPLY_NOT_FOUND;
+
+@Slf4j
+@RequiredArgsConstructor
+@Transactional
+@Service
+public class ReplyReader {
+ private final ReplyRepository replyRepository;
+ public Reply findById(Long replyId) {
+ return replyRepository.findById(replyId)
+ .orElseThrow(() -> new EntityNotFoundException(REPLY_NOT_FOUND));
+ }
+
+ public List findByCommentId(Long commentId) {
+ return replyRepository.findByCommentId(commentId);
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/notification/entity/NotificationHistory.java b/Main/src/main/java/com/kusitms29/backendH/domain/notification/entity/NotificationHistory.java
new file mode 100644
index 0000000..35b1d42
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/notification/entity/NotificationHistory.java
@@ -0,0 +1,56 @@
+package com.kusitms29.backendH.domain.notification.entity;
+
+import com.kusitms29.backendH.domain.user.entity.User;
+import jakarta.persistence.*;
+import lombok.*;
+
+import java.time.LocalDateTime;
+
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@AllArgsConstructor
+@Builder
+@Getter
+@Table(name = "notification_history")
+@Entity
+public class NotificationHistory {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "notification_history_id")
+ private Long id;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "user_id")
+ private User user;
+
+ private String title;
+
+ private String body;
+
+ private String receiverToken;
+
+ private LocalDateTime sentAt;
+
+ private NotificationType notificationType;
+
+ private TopCategory topCategory;
+
+ private String infoId;
+ private String infoId2;
+
+ public static NotificationHistory createHistory(User user, String title, String body,
+ String receiverToken, LocalDateTime sentAt,
+ NotificationType notificationType, TopCategory topCategory,
+ String infoId, String infoId2) {
+ return NotificationHistory.builder()
+ .user(user)
+ .title(title)
+ .body(body)
+ .receiverToken(receiverToken)
+ .sentAt(sentAt)
+ .notificationType(notificationType)
+ .topCategory(topCategory)
+ .infoId(infoId)
+ .infoId2(infoId2)
+ .build();
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/notification/entity/NotificationSetting.java b/Main/src/main/java/com/kusitms29/backendH/domain/notification/entity/NotificationSetting.java
new file mode 100644
index 0000000..36e47ad
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/notification/entity/NotificationSetting.java
@@ -0,0 +1,37 @@
+package com.kusitms29.backendH.domain.notification.entity;
+
+import com.kusitms29.backendH.domain.user.entity.User;
+import com.kusitms29.backendH.global.common.BaseEntity;
+import jakarta.persistence.*;
+import lombok.*;
+
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@AllArgsConstructor
+@Builder
+@Getter
+@Table(name = "notification")
+@Entity
+public class NotificationSetting extends BaseEntity {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "notification_id")
+ private Long id;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "user_id")
+ private User user;
+
+ @Enumerated(EnumType.STRING)
+ private NotificationType notificationType;
+
+ @Enumerated(EnumType.STRING)
+ private Status status = Status.ACTIVE;
+
+ public enum Status {
+ ACTIVE, INACTIVE;
+ }
+
+ public void setStatus(Status status) {
+ this.status = Status.ACTIVE;
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/notification/entity/NotificationType.java b/Main/src/main/java/com/kusitms29/backendH/domain/notification/entity/NotificationType.java
new file mode 100644
index 0000000..f4ade7d
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/notification/entity/NotificationType.java
@@ -0,0 +1,9 @@
+package com.kusitms29.backendH.domain.notification.entity;
+
+public enum NotificationType {
+ CHAT,
+ CHAT_ROOM_NOTICE,
+ SYNC_REMINDER,
+ COMMENT,
+ REVIEW
+}
\ No newline at end of file
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/notification/entity/TopCategory.java b/Main/src/main/java/com/kusitms29/backendH/domain/notification/entity/TopCategory.java
new file mode 100644
index 0000000..62dd136
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/notification/entity/TopCategory.java
@@ -0,0 +1,25 @@
+package com.kusitms29.backendH.domain.notification.entity;
+
+import com.kusitms29.backendH.global.error.exception.InvalidValueException;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Arrays;
+
+import static com.kusitms29.backendH.global.error.ErrorCode.INVALID_NOTIFICATION_TOP_CATEGORY;
+
+@RequiredArgsConstructor
+@Getter
+public enum TopCategory {
+ ACTIVITY("활동"),
+ MY_SYNC("내싱크");
+
+ private final String stringTopCategory;
+
+ public static TopCategory getEnumTopCategoryFromStringTopCategory(String strTopCategory) {
+ return Arrays.stream(values())
+ .filter(topCategory -> topCategory.stringTopCategory.equals(strTopCategory))
+ .findFirst()
+ .orElseThrow(() -> new InvalidValueException(INVALID_NOTIFICATION_TOP_CATEGORY));
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/notification/repository/NotificationHistoryRepository.java b/Main/src/main/java/com/kusitms29/backendH/domain/notification/repository/NotificationHistoryRepository.java
new file mode 100644
index 0000000..6aca084
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/notification/repository/NotificationHistoryRepository.java
@@ -0,0 +1,13 @@
+package com.kusitms29.backendH.domain.notification.repository;
+
+import com.kusitms29.backendH.domain.notification.entity.NotificationHistory;
+import com.kusitms29.backendH.domain.notification.entity.TopCategory;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository
+public interface NotificationHistoryRepository extends JpaRepository {
+ List findByTopCategoryAndUserId(TopCategory topCategory, Long userId);
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/notification/repository/NotificationRepository.java b/Main/src/main/java/com/kusitms29/backendH/domain/notification/repository/NotificationRepository.java
new file mode 100644
index 0000000..4c9eaf2
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/notification/repository/NotificationRepository.java
@@ -0,0 +1,12 @@
+package com.kusitms29.backendH.domain.notification.repository;
+
+import com.kusitms29.backendH.domain.notification.entity.NotificationSetting;
+import com.kusitms29.backendH.domain.notification.entity.NotificationType;
+import com.kusitms29.backendH.domain.user.entity.User;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.util.Optional;
+
+public interface NotificationRepository extends JpaRepository {
+ Optional findByUserAndNotificationType(User user, NotificationType type);
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/notification/service/NotificationHistoryReader.java b/Main/src/main/java/com/kusitms29/backendH/domain/notification/service/NotificationHistoryReader.java
new file mode 100644
index 0000000..c016f55
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/notification/service/NotificationHistoryReader.java
@@ -0,0 +1,20 @@
+package com.kusitms29.backendH.domain.notification.service;
+
+import com.kusitms29.backendH.domain.notification.entity.NotificationHistory;
+import com.kusitms29.backendH.domain.notification.entity.TopCategory;
+import com.kusitms29.backendH.domain.notification.repository.NotificationHistoryRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+@RequiredArgsConstructor
+public class NotificationHistoryReader {
+ private final NotificationHistoryRepository notificationHistoryRepository;
+
+ public List findByTopCategoryAndUserId(TopCategory topCategory, Long userId) {
+ return notificationHistoryRepository.findByTopCategoryAndUserId(topCategory, userId);
+ }
+
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/post/entity/Post.java b/Main/src/main/java/com/kusitms29/backendH/domain/post/entity/Post.java
new file mode 100644
index 0000000..284240e
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/post/entity/Post.java
@@ -0,0 +1,28 @@
+package com.kusitms29.backendH.domain.post.entity;
+
+import com.kusitms29.backendH.global.common.BaseEntity;
+import com.kusitms29.backendH.domain.user.entity.User;
+import jakarta.persistence.*;
+import lombok.*;
+
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@AllArgsConstructor
+@Builder
+@Getter
+@Table(name = "post")
+@Entity
+public class Post extends BaseEntity {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "post_id")
+ private Long id;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "user_id")
+ private User user;
+ private String title;
+
+ private String content;
+ @Enumerated(EnumType.STRING)
+ private PostType postType;
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/post/entity/PostImage.java b/Main/src/main/java/com/kusitms29/backendH/domain/post/entity/PostImage.java
new file mode 100644
index 0000000..5788c3d
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/post/entity/PostImage.java
@@ -0,0 +1,26 @@
+package com.kusitms29.backendH.domain.post.entity;
+
+import com.kusitms29.backendH.global.common.BaseEntity;
+import jakarta.persistence.*;
+import lombok.*;
+
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@AllArgsConstructor
+@Builder
+@Getter
+@Table(name = "post_image")
+@Entity
+public class PostImage extends BaseEntity {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "image_id")
+ private Long id;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "post_id")
+ private Post post;
+
+ private String image_url;
+
+ private boolean isRepresentative;
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/post/entity/PostLike.java b/Main/src/main/java/com/kusitms29/backendH/domain/post/entity/PostLike.java
new file mode 100644
index 0000000..40bb97d
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/post/entity/PostLike.java
@@ -0,0 +1,28 @@
+package com.kusitms29.backendH.domain.post.entity;
+
+import com.kusitms29.backendH.global.common.BaseEntity;
+import com.kusitms29.backendH.domain.user.entity.User;
+import jakarta.persistence.*;
+import lombok.*;
+
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@AllArgsConstructor
+@Builder
+@Getter
+@Table(name = "postLike")
+@Entity
+public class PostLike extends BaseEntity {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "post_like_id")
+ private Long id;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "user_id")
+ private User user;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "post_id")
+ private Post post;
+}
+
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/post/entity/PostType.java b/Main/src/main/java/com/kusitms29/backendH/domain/post/entity/PostType.java
new file mode 100644
index 0000000..3fc0e92
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/post/entity/PostType.java
@@ -0,0 +1,23 @@
+package com.kusitms29.backendH.domain.post.entity;
+
+import com.kusitms29.backendH.global.error.exception.InvalidValueException;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Arrays;
+
+import static com.kusitms29.backendH.global.error.ErrorCode.INVALID_POST_TYPE;
+
+@RequiredArgsConstructor
+@Getter
+public enum PostType {
+ C("생활"),
+ Q("질문");
+ private final String stringPostType;
+ public static PostType getEnumPostTypeFromStringPostType(String stringPostType) {
+ return Arrays.stream(values())
+ .filter(postType -> postType.stringPostType.equals(stringPostType))
+ .findFirst()
+ .orElseThrow(() -> new InvalidValueException(INVALID_POST_TYPE));
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/post/repository/PostImageRepository.java b/Main/src/main/java/com/kusitms29/backendH/domain/post/repository/PostImageRepository.java
new file mode 100644
index 0000000..7d8321d
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/post/repository/PostImageRepository.java
@@ -0,0 +1,13 @@
+package com.kusitms29.backendH.domain.post.repository;
+
+import com.kusitms29.backendH.domain.post.entity.PostImage;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.util.List;
+
+public interface PostImageRepository extends JpaRepository {
+
+ List findByPostId(Long postId);
+
+ PostImage findByPostIdAndIsRepresentative(Long postId, boolean representative);
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/post/repository/PostLikeRepository.java b/Main/src/main/java/com/kusitms29/backendH/domain/post/repository/PostLikeRepository.java
new file mode 100644
index 0000000..bb57059
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/post/repository/PostLikeRepository.java
@@ -0,0 +1,16 @@
+package com.kusitms29.backendH.domain.post.repository;
+
+import com.kusitms29.backendH.domain.post.entity.PostLike;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.Optional;
+
+@Repository
+public interface PostLikeRepository extends JpaRepository {
+ int countByPostId(Long postId);
+
+ boolean existsByPostIdAndUserId(Long postId, Long userId);
+
+ Optional findByPostIdAndUserId(Long postId, Long userId);
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/post/repository/PostRepository.java b/Main/src/main/java/com/kusitms29/backendH/domain/post/repository/PostRepository.java
new file mode 100644
index 0000000..0440a49
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/post/repository/PostRepository.java
@@ -0,0 +1,19 @@
+package com.kusitms29.backendH.domain.post.repository;
+
+import com.kusitms29.backendH.domain.post.entity.Post;
+import com.kusitms29.backendH.domain.post.entity.PostType;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository
+public interface PostRepository extends JpaRepository {
+ List findByPostType(PostType postType);
+
+ @Query("SELECT p FROM Post p WHERE p.title LIKE %:keyword% OR p.content LIKE %:keyword%")
+ List searchByTitleOrContent(@Param("keyword") String keyword);
+
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/post/service/PostAppender.java b/Main/src/main/java/com/kusitms29/backendH/domain/post/service/PostAppender.java
new file mode 100644
index 0000000..05078d0
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/post/service/PostAppender.java
@@ -0,0 +1,22 @@
+package com.kusitms29.backendH.domain.post.service;
+
+import com.kusitms29.backendH.domain.post.entity.Post;
+import com.kusitms29.backendH.domain.post.repository.PostRepository;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Slf4j
+@RequiredArgsConstructor
+@Transactional
+@Service
+public class PostAppender {
+ private final PostRepository postRepository;
+
+ public Post save(Post post) {
+ return postRepository.save(post);
+ }
+
+
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/post/service/PostImageAppender.java b/Main/src/main/java/com/kusitms29/backendH/domain/post/service/PostImageAppender.java
new file mode 100644
index 0000000..1ba3dfb
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/post/service/PostImageAppender.java
@@ -0,0 +1,21 @@
+package com.kusitms29.backendH.domain.post.service;
+
+import com.kusitms29.backendH.domain.post.entity.PostImage;
+import com.kusitms29.backendH.domain.post.repository.PostImageRepository;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Slf4j
+@RequiredArgsConstructor
+@Transactional
+@Service
+public class PostImageAppender {
+ private final PostImageRepository postImageRepository;
+
+ public PostImage save(PostImage postImage) {
+ return postImageRepository.save(postImage);
+ }
+
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/post/service/PostImageReader.java b/Main/src/main/java/com/kusitms29/backendH/domain/post/service/PostImageReader.java
new file mode 100644
index 0000000..3378f3e
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/post/service/PostImageReader.java
@@ -0,0 +1,27 @@
+package com.kusitms29.backendH.domain.post.service;
+
+import com.kusitms29.backendH.domain.post.entity.PostImage;
+import com.kusitms29.backendH.domain.post.repository.PostImageRepository;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+@Slf4j
+@RequiredArgsConstructor
+@Transactional
+@Service
+public class PostImageReader {
+ private final PostImageRepository postImageRepository;
+
+ public PostImage findByPostIdAndIsRepresentative(Long postId, boolean representative) {
+ return postImageRepository.findByPostIdAndIsRepresentative(postId, representative);
+ }
+
+ public List findByPostId(Long postId) {
+ return postImageRepository.findByPostId(postId);
+ }
+
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/post/service/PostLikeAppender.java b/Main/src/main/java/com/kusitms29/backendH/domain/post/service/PostLikeAppender.java
new file mode 100644
index 0000000..cafd1e3
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/post/service/PostLikeAppender.java
@@ -0,0 +1,22 @@
+package com.kusitms29.backendH.domain.post.service;
+
+
+import com.kusitms29.backendH.domain.post.entity.PostLike;
+import com.kusitms29.backendH.domain.post.repository.PostLikeRepository;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Slf4j
+@RequiredArgsConstructor
+@Transactional
+@Service
+public class PostLikeAppender {
+ private final PostLikeRepository postLikeRepository;
+
+ public PostLike save(PostLike postLike) {
+ return postLikeRepository.save(postLike);
+ }
+
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/post/service/PostLikeManager.java b/Main/src/main/java/com/kusitms29/backendH/domain/post/service/PostLikeManager.java
new file mode 100644
index 0000000..b7240ff
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/post/service/PostLikeManager.java
@@ -0,0 +1,22 @@
+package com.kusitms29.backendH.domain.post.service;
+
+import com.kusitms29.backendH.domain.post.repository.PostLikeRepository;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Slf4j
+@RequiredArgsConstructor
+@Transactional
+@Service
+public class PostLikeManager {
+ private final PostLikeRepository postLikeRepository;
+ public int countByPostId(Long postId) {
+ return postLikeRepository.countByPostId(postId);
+ }
+
+ public boolean existsByPostIdAndUserId(Long postId, Long userId) {
+ return postLikeRepository.existsByPostIdAndUserId(postId, userId);
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/post/service/PostLikeModifier.java b/Main/src/main/java/com/kusitms29/backendH/domain/post/service/PostLikeModifier.java
new file mode 100644
index 0000000..4b3d7f6
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/post/service/PostLikeModifier.java
@@ -0,0 +1,20 @@
+package com.kusitms29.backendH.domain.post.service;
+
+import com.kusitms29.backendH.domain.post.entity.PostLike;
+import com.kusitms29.backendH.domain.post.repository.PostLikeRepository;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Slf4j
+@RequiredArgsConstructor
+@Transactional
+@Service
+public class PostLikeModifier {
+ private final PostLikeRepository postLikeRepository;
+
+ public void delete(PostLike postLike) {
+ postLikeRepository.delete(postLike);
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/post/service/PostLikeReader.java b/Main/src/main/java/com/kusitms29/backendH/domain/post/service/PostLikeReader.java
new file mode 100644
index 0000000..f46a440
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/post/service/PostLikeReader.java
@@ -0,0 +1,24 @@
+package com.kusitms29.backendH.domain.post.service;
+
+import com.kusitms29.backendH.domain.post.entity.PostLike;
+import com.kusitms29.backendH.domain.post.repository.PostLikeRepository;
+import com.kusitms29.backendH.global.error.exception.EntityNotFoundException;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import static com.kusitms29.backendH.global.error.ErrorCode.POST_LIKE_NOT_FOUND;
+
+@Slf4j
+@RequiredArgsConstructor
+@Transactional
+@Service
+public class PostLikeReader {
+ private final PostLikeRepository postLikeRepository;
+
+ public PostLike findByPostIdAndUserId(Long postId, Long userId) {
+ return postLikeRepository.findByPostIdAndUserId(postId, userId)
+ .orElseThrow(() -> new EntityNotFoundException(POST_LIKE_NOT_FOUND));
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/post/service/PostReader.java b/Main/src/main/java/com/kusitms29/backendH/domain/post/service/PostReader.java
new file mode 100644
index 0000000..249795a
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/post/service/PostReader.java
@@ -0,0 +1,37 @@
+package com.kusitms29.backendH.domain.post.service;
+
+import com.kusitms29.backendH.domain.post.entity.Post;
+import com.kusitms29.backendH.domain.post.entity.PostType;
+import com.kusitms29.backendH.domain.post.repository.PostRepository;
+import com.kusitms29.backendH.global.error.exception.EntityNotFoundException;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+
+import static com.kusitms29.backendH.global.error.ErrorCode.POST_NOT_FOUND;
+
+@Slf4j
+@RequiredArgsConstructor
+@Transactional
+@Service
+public class PostReader {
+
+ public final PostRepository postRepository;
+
+ public List findByPostType(PostType enumPostType) {
+ return postRepository.findByPostType(enumPostType);
+ }
+
+ public Post findById(Long postId) {
+ return postRepository.findById(postId)
+ .orElseThrow(()-> new EntityNotFoundException(POST_NOT_FOUND));
+ }
+
+ public List searchByTitleOrContent(String keyword) {
+ return postRepository.searchByTitleOrContent(keyword);
+ }
+
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/sync/entity/FavoriteSync.java b/Main/src/main/java/com/kusitms29/backendH/domain/sync/entity/FavoriteSync.java
new file mode 100644
index 0000000..9ae44eb
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/sync/entity/FavoriteSync.java
@@ -0,0 +1,27 @@
+package com.kusitms29.backendH.domain.sync.entity;
+
+import com.kusitms29.backendH.domain.user.entity.User;
+import com.kusitms29.backendH.global.common.BaseEntity;
+import jakarta.persistence.*;
+import lombok.*;
+
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@AllArgsConstructor
+@Builder
+@Getter
+@Table(name = "favoriteSync")
+@Entity
+public class FavoriteSync extends BaseEntity {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "favorite_sync_id")
+ private Long id;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "user_id")
+ private User user;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "sync_id")
+ private Sync sync;
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/sync/entity/Gender.java b/Main/src/main/java/com/kusitms29/backendH/domain/sync/entity/Gender.java
new file mode 100644
index 0000000..69cacaa
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/sync/entity/Gender.java
@@ -0,0 +1,28 @@
+package com.kusitms29.backendH.domain.sync.entity;
+
+import com.kusitms29.backendH.global.error.exception.InvalidValueException;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Arrays;
+
+import static com.kusitms29.backendH.global.error.ErrorCode.INVALID_GENDER_TYPE;
+
+@RequiredArgsConstructor
+@Getter
+public enum Gender {
+
+ MAN("남성"),
+ WOMAN("여성"),
+ SECRET("비공개");
+
+ private final String stringGender;
+
+ public static Gender getEnumFROMStringGender(String stringGender) {
+ return Arrays.stream(values())
+ .filter(gender -> gender.stringGender.equals(stringGender))
+ .findFirst()
+ .orElseThrow(() -> new InvalidValueException(INVALID_GENDER_TYPE));
+ }
+
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/sync/entity/Language.java b/Main/src/main/java/com/kusitms29/backendH/domain/sync/entity/Language.java
new file mode 100644
index 0000000..8a75118
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/sync/entity/Language.java
@@ -0,0 +1,26 @@
+package com.kusitms29.backendH.domain.sync.entity;
+
+import com.kusitms29.backendH.global.error.exception.InvalidValueException;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Arrays;
+
+import static com.kusitms29.backendH.global.error.ErrorCode.INVALID_LANGUAGE_TYPE;
+
+@RequiredArgsConstructor
+@Getter
+public enum Language {
+ KOREAN("korean"),
+ ENGLISH("english");
+
+ private final String stringLanguage;
+
+ public static Language getEnumLanguageFromStringLanguage(String stringLanguage) {
+ return Arrays.stream(values())
+ .filter(language -> language.stringLanguage.equals(stringLanguage))
+ .findFirst()
+ .orElseThrow(() -> new InvalidValueException(INVALID_LANGUAGE_TYPE));
+ }
+
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/sync/entity/Participation.java b/Main/src/main/java/com/kusitms29/backendH/domain/sync/entity/Participation.java
new file mode 100644
index 0000000..0de007c
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/sync/entity/Participation.java
@@ -0,0 +1,34 @@
+package com.kusitms29.backendH.domain.sync.entity;
+
+import com.kusitms29.backendH.global.common.BaseEntity;
+import com.kusitms29.backendH.domain.user.entity.User;
+import jakarta.persistence.*;
+import lombok.*;
+
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@AllArgsConstructor
+@Builder
+@Getter
+@Table(name = "participation")
+@Entity
+public class Participation extends BaseEntity {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "participation_id")
+ private Long id;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "user_id")
+ private User user;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "sync_id")
+ private Sync sync;
+
+ public static Participation createParticipation(User user, Sync sync) {
+ return Participation.builder()
+ .user(user)
+ .sync(sync)
+ .build();
+ }
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/sync/entity/Sync.java b/Main/src/main/java/com/kusitms29/backendH/domain/sync/entity/Sync.java
new file mode 100644
index 0000000..81669be
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/sync/entity/Sync.java
@@ -0,0 +1,99 @@
+package com.kusitms29.backendH.domain.sync.entity;
+
+import com.kusitms29.backendH.domain.category.entity.Type;
+import com.kusitms29.backendH.global.common.BaseEntity;
+import com.kusitms29.backendH.domain.user.entity.User;
+import jakarta.persistence.*;
+import lombok.*;
+import org.hibernate.annotations.ColumnDefault;
+
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@AllArgsConstructor
+@Builder
+@Getter
+@Table(name = "sync")
+@Entity
+public class Sync extends BaseEntity {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "sync_id")
+ private Long id;
+
+ @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
+ @JoinColumn(name = "user_id")
+ private User user;
+ //모임장소개
+ private String userIntro;
+ //싱크소개
+ private String syncIntro;
+ private String link;
+
+ @Enumerated(EnumType.STRING)
+ private SyncType syncType;
+
+ private String syncName;
+ private String image;
+ private String content;
+ private String location;
+ private LocalDateTime date;
+ //지속성에서 정기모임
+ private String regularDay;
+ private LocalTime regularTime;
+ private LocalDateTime routineDate;
+
+ //지속성 모임 : 모임 횟수
+ @ColumnDefault("1")
+ @Builder.Default()
+ private int member_min = 1;
+ @ColumnDefault("2")
+ @Builder.Default()
+ private int member_max = 2;
+
+ @Enumerated(EnumType.STRING)
+ protected Sync.Status status;
+ @Enumerated(EnumType.STRING)
+ private Type type;
+ private String detailType;
+ //일단 제휴가 뭐 없어서 일단 이렇게 함
+ private String associate;
+
+ public enum Status {
+ RECRUITING, COMPLETED, DELETED;
+ }
+
+ public static Sync from(Long syncId) {
+ return new Sync(syncId,null,null,null,null,null,null,null,null,null,null,null,null,null,0,0,null,null,null,null);
+ }
+
+ public static Sync createSync(User user, String userIntro, String syncIntro, SyncType syncType,
+ String syncName, String image, String location, LocalDateTime date,
+ String regularDay, LocalTime regularTime, LocalDateTime routineDate,
+ int member_min, int member_max,
+ Type type, String detailType){
+ return Sync.builder()
+ .user(user)
+ .userIntro(userIntro)
+ .syncIntro(syncIntro)
+ .syncType(syncType)
+ .syncName(syncName)
+ .image(image)
+ .location(location)
+ .date(date)
+ .regularDay(regularDay)
+ .regularTime(regularTime)
+ .routineDate(routineDate)
+ .member_min(member_min)
+ .member_max(member_max)
+ .type(type)
+ .detailType(detailType)
+ .build();
+ }
+
+ public void updateNextDate(LocalDateTime routineDate) {
+ this.routineDate = routineDate;
+ }
+
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/sync/entity/SyncReview.java b/Main/src/main/java/com/kusitms29/backendH/domain/sync/entity/SyncReview.java
new file mode 100644
index 0000000..9652477
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/sync/entity/SyncReview.java
@@ -0,0 +1,39 @@
+package com.kusitms29.backendH.domain.sync.entity;
+
+import com.kusitms29.backendH.global.common.BaseEntity;
+import com.kusitms29.backendH.domain.user.entity.User;
+import jakarta.persistence.*;
+import lombok.*;
+
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@AllArgsConstructor
+@Getter
+@Table(name = "syncReview")
+@Entity
+public class SyncReview extends BaseEntity {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "sync_review_id")
+ private Long id;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "user_id")
+ private User user;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "sync_id")
+ private Sync sync;
+
+ private String content;
+
+ public SyncReview(User user, Sync sync, String content) {
+ this.user = user;
+ this.sync = sync;
+ this.content = content;
+ }
+
+ public static SyncReview createReview(User user, Sync sync, String content){
+ return new SyncReview(user, sync, content);
+ }
+
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/sync/entity/SyncStatus.java b/Main/src/main/java/com/kusitms29/backendH/domain/sync/entity/SyncStatus.java
new file mode 100644
index 0000000..2fe9075
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/sync/entity/SyncStatus.java
@@ -0,0 +1,15 @@
+package com.kusitms29.backendH.domain.sync.entity;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+@Getter
+public enum SyncStatus {
+
+ RECRUITING("모집중"),
+ COMPLETED("모집완료"),
+ DELETED("삭제된모임");
+
+ private final String syncStatus;
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/sync/entity/SyncType.java b/Main/src/main/java/com/kusitms29/backendH/domain/sync/entity/SyncType.java
new file mode 100644
index 0000000..69e299d
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/sync/entity/SyncType.java
@@ -0,0 +1,32 @@
+package com.kusitms29.backendH.domain.sync.entity;
+
+import com.kusitms29.backendH.global.error.exception.InvalidValueException;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Arrays;
+
+import static com.kusitms29.backendH.global.error.ErrorCode.INVALID_SYNC_TYPE;
+
+@RequiredArgsConstructor
+@Getter
+public enum SyncType {
+
+ //일회성, 지속성, 내친소
+ ONETIME("일회성"),
+ LONGTIME("지속성"),
+ FROM_FRIEND("내친소");
+
+ private final String stringSyncType;
+
+ public static SyncType getEnumFROMStringSyncType(String stringSyncType) {
+ if (stringSyncType == null) {
+ return null;
+ }
+ return Arrays.stream(values())
+ .filter(syncType -> syncType.stringSyncType.equals(stringSyncType))
+ .findFirst()
+ .orElseThrow(() -> new InvalidValueException(INVALID_SYNC_TYPE));
+ }
+
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/sync/repository/FavoriteSyncRepository.java b/Main/src/main/java/com/kusitms29/backendH/domain/sync/repository/FavoriteSyncRepository.java
new file mode 100644
index 0000000..1d5b90c
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/sync/repository/FavoriteSyncRepository.java
@@ -0,0 +1,10 @@
+package com.kusitms29.backendH.domain.sync.repository;
+
+import com.kusitms29.backendH.domain.sync.entity.FavoriteSync;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.util.List;
+
+public interface FavoriteSyncRepository extends JpaRepository {
+ List findAllByUserId(Long userId);
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/sync/repository/ParticipationRepository.java b/Main/src/main/java/com/kusitms29/backendH/domain/sync/repository/ParticipationRepository.java
new file mode 100644
index 0000000..3b13a99
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/sync/repository/ParticipationRepository.java
@@ -0,0 +1,20 @@
+package com.kusitms29.backendH.domain.sync.repository;
+
+import com.kusitms29.backendH.domain.sync.entity.Participation;
+import com.kusitms29.backendH.domain.sync.entity.Sync;
+import com.kusitms29.backendH.domain.user.entity.User;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+
+import java.util.List;
+import java.util.Optional;
+
+public interface ParticipationRepository extends JpaRepository {
+ Optional findByUserAndSync(User user, Sync sync);
+ List findBySync(Sync sync);
+ @Query("SELECT COUNT(p) FROM Participation p WHERE p.sync.id = :syncId")
+ int countBySyncId(@Param("syncId") Long syncId);
+ List findAllBySyncId(Long syncId);
+ List findAllByUserId(Long userId);
+}
diff --git a/Main/src/main/java/com/kusitms29/backendH/domain/sync/repository/SyncRepository.java b/Main/src/main/java/com/kusitms29/backendH/domain/sync/repository/SyncRepository.java
new file mode 100644
index 0000000..2dacb54
--- /dev/null
+++ b/Main/src/main/java/com/kusitms29/backendH/domain/sync/repository/SyncRepository.java
@@ -0,0 +1,56 @@
+package com.kusitms29.backendH.domain.sync.repository;
+
+import com.kusitms29.backendH.domain.category.entity.Type;
+import com.kusitms29.backendH.domain.sync.entity.Sync;
+import com.kusitms29.backendH.domain.sync.entity.SyncType;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Map;
+
+public interface SyncRepository extends JpaRepository {
+ //모임이 하루 안으로 임박한 Sync의 정보 가져오기
+ @Query(value = "SELECT u.user_id, u.user_name, s.sync_name, s.sync_id, s.sync_type, s.regular_day, s.regular_time, " +
+ "CASE WHEN s.sync_type = 'LONGTIME' THEN s.routine_date ELSE s.date END AS effective_date " +
+ "FROM sync s " +
+ "INNER JOIN participation p ON s.sync_id = p.sync_id " +
+ "INNER JOIN user u ON p.user_id = u.user_id " +
+ "WHERE s.status != 'DELETED' " +
+ "AND (CASE WHEN s.sync_type = 'LONGTIME' THEN s.routine_date ELSE s.date END) IS NOT NULL " +
+ "AND DATE_SUB((CASE WHEN s.sync_type = 'LONGTIME' THEN s.routine_date ELSE s.date END), INTERVAL 1 DAY) <= :currentDate " +
+ "AND (CASE WHEN s.sync_type = 'LONGTIME' THEN s.routine_date ELSE s.date END) >= :currentDate ",
+ nativeQuery = true)
+ List