Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
c78a59f
commit
gooinsung Nov 25, 2024
bb380c8
test commit message
gooinsung Nov 26, 2024
98fe998
ExceptionHandling 세팅
gooinsung Nov 26, 2024
c1b8ddc
Update README.md
gooinsung Nov 26, 2024
85045da
디렉토리 구조 변경 및 createSurvey 메서드 추가
gooinsung Nov 26, 2024
233beee
Merge remote-tracking branch 'origin/main'
gooinsung Nov 26, 2024
cdbccc8
SurveyRepositoryTest 코드 작성(test...)
gooinsung Nov 26, 2024
8ea1832
createSurvey API 생성
gooinsung Nov 26, 2024
2124e88
modifySurvey 작업 중
gooinsung Nov 26, 2024
cfee278
@OneToMany 양방향 연관관계 제거
gooinsung Nov 27, 2024
bbab1ed
엎고 다시...
gooinsung Nov 27, 2024
d783c5f
엔티티 저장하는거 다시 보기
gooinsung Nov 27, 2024
6bd3e61
setter 제거. dto 까지도 보호
gooinsung Nov 27, 2024
33750a0
updateSurvey 완성
gooinsung Nov 27, 2024
cdfa7f8
updateSurvey 완성
gooinsung Nov 27, 2024
106cba9
리뷰 내용들.
gooinsung Nov 28, 2024
aa90e56
패턴 변경. request -> dto -> entity,
gooinsung Nov 28, 2024
67ed40b
엔티티 이름 변경(response 라는 네이밍이 혼란을 야기할 수도 있음.) ItemResponse -> ItemAnswer
gooinsung Nov 28, 2024
f666578
설문조사 제출 api 작업 중
gooinsung Nov 29, 2024
0bcac7a
다중 선택 항목 save만 하면 됨
gooinsung Nov 29, 2024
3bf3e53
submit survey 메서드 1차 완성
gooinsung Nov 30, 2024
f5c1f46
submit survey 메서드 완료(추후 검수 필요)
gooinsung Nov 30, 2024
7e6dd15
Runtime, Exception 핸들러 처리
gooinsung Nov 30, 2024
ccfa3cf
조회 api 작업 중
gooinsung Nov 30, 2024
85795dd
querydsl 설정 추가
gooinsung Dec 2, 2024
d420307
querydsl 작업... 에러 어떻게잡냐
gooinsung Dec 2, 2024
7db6812
update 쿼리 수정
gooinsung Dec 2, 2024
0deae74
조회 api 각 조회로 수정해야함
gooinsung Dec 2, 2024
b5bcfe8
조회 api 각 조회로 수정
gooinsung Dec 2, 2024
71ab6b8
validated 추가 및 survey orElseThrow 메서드로 처리
gooinsung Dec 3, 2024
6853ba2
repository 테스트 코드 작성
gooinsung Dec 4, 2024
ee251d9
ActionBusiness 테스트 코드 작성 중
gooinsung Dec 4, 2024
fb078c6
설문조사 항목 리스트 저장 메서드 테스트 코드 작성
gooinsung Dec 4, 2024
dbc4176
최종 수정
gooinsung Dec 4, 2024
ef9d75e
toString 제거
gooinsung Dec 4, 2024
4588e0c
Update README.md
gooinsung Dec 5, 2024
9e16717
jar 링크 추가
gooinsung Dec 5, 2024
45eab2c
api 명세서 링크 추가
gooinsung Dec 5, 2024
28c6239
api 명세서 링크 추가`
gooinsung Dec 5, 2024
facfe54
embeded 사용해봄
gooinsung Dec 5, 2024
2e62cd6
테스트 코드 수정
gooinsung Dec 5, 2024
57067a7
Update README.md
gooinsung Dec 5, 2024
3eb8326
itemanswer dto set 수정
gooinsung Dec 5, 2024
2339bfc
Merge remote-tracking branch 'origin/main'
gooinsung Dec 5, 2024
c0df444
버그 코드 수정
gooinsung Dec 7, 2024
c4466ca
Update README.md
gooinsung Dec 7, 2024
073c7a2
controller 의 request(dto), service 의 command(record) 작업 진행 중. 추가 수정 필요
gooinsung Dec 7, 2024
a4070b2
Merge remote-tracking branch 'origin/main'
gooinsung Dec 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/gradlew text eol=lf
*.bat text eol=crlf
*.jar binary
39 changes: 39 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
HELP.md
.gradle
build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/

/$buildDir

### 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/
156 changes: 41 additions & 115 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,115 +1,41 @@
# 이너써클 BE 온보딩 프로젝트

## 온보딩 프로젝트의 목적

- 공통된 내용과 기술스택을 이용한 기술 경험 수준 평가
- 최대한 과거에 경험 해보시지 못한 주제를 선정하여 기술적으로 챌린지 하실 수 있게끔 구성
- 점수를 매기거나 합격과 불합격을 구분하는 목적은 아님.
- 서로가 서로에게 도움 줄 수 있는 각자의 강점을 파악하기 위하여 진행
- 꼼꼼한 요구사항 분석과 문서화
- 새로운 기술적 접근 방식
- 안정적인 아키텍처 구성

## Introduction

- “설문조사 서비스"를 구현하려고 합니다.
- “온보딩 프로젝트 기능 요구사항"을 구현해 주시기 바랍니다.
- 온보딩 프로젝트 기능 요구 사항 및 기술 요구사항이 충족되지 않은 결과물은 코드레벨 평가를 진행하지 않습니다.
- 아래의 “코드레벨 평가항목"으로 코드를 평가합니다.
- “설문조사 서비스"의 API 명세를 함께 제출해주세요.
- 우대사항은 직접 구현하지 않더라도 README에 적용 방법 등을 구체적으로 명시해주시는 것으로 대체 할 수 있습니다.

## 온보딩 프로젝트 기능 요구사항

### 개요

- “설문조사 서비스”는 설문조사 양식을 만들고, 만들어진 양식을 기반으로 응답을 받을 수 있는 서비스입니다. (e.g. Google Forms, Tally, Typeform)
- 설문조사 양식은 [설문조사 이름], [설문조사 설명], [설문 받을 항목]의 구성으로 이루어져있습니다.
- [설문 받을 항목]은 [항목 이름], [항목 설명], [항목 입력 형태], [항목 필수 여부]의 구성으로 이루어져있습니다.
- [항목 입력 형태]는 [단답형], [장문형], [단일 선택 리스트], [다중 선택 리스트]의 구성으로 이루어져있습니다.


### 1. 설문조사 생성 API

- 요청 값에는 [설문조사 이름], [설문조사 설명], [설문 받을 항목]이 포함됩니다.
- [설문 받을 항목]은 [항목 이름], [항목 설명], [항목 입력 형태], [항목 필수 여부]의 구성으로 이루어져있습니다.
- [항목 입력 형태]는 [단답형], [장문형], [단일 선택 리스트], [다중 선택 리스트]의 구성으로 이루어져있습니다.
- [단일 선택 리스트], [다중 선택 리스트]의 경우 선택 할 수 있는 후보를 요청 값에 포함하여야 합니다.
- [설문 받을 항목]은 1개 ~ 10개까지 포함 할 수 있습니다.


### 2. 설문조사 수정 API

- 요청 값에는 [설문조사 이름], [설문조사 설명], [설문 받을 항목]이 포함됩니다.
- [설문 받을 항목]은 [항목 이름], [항목 설명], [항목 입력 형태], [항목 필수 여부]의 구성으로 이루어져있습니다.
- [항목 입력 형태]는 [단답형], [장문형], [단일 선택 리스트], [다중 선택 리스트]의 구성으로 이루어져있습니다.
- [단일 선택 리스트], [다중 선택 리스트]의 경우 선택 할 수 있는 후보를 요청 값에 포함하여야 합니다.
- [설문 받을 항목]이 추가/변경/삭제 되더라도 기존 응답은 유지되어야 합니다.


### 3. 설문조사 응답 제출 API

- 요청 값에는 [설문 받을 항목]에 대응되는 응답 값이 포함됩니다.
- 응답 값은 설문조사의 [설문 받을 항목]과 일치해야만 응답 할 수 있습니다.


### 4. 설문조사 응답 조회 API

- 요청 값에는 [설문조사 식별자]가 포함됩니다.
- 해당 설문조사의 전체 응답을 조회합니다.
- **(Advanced)** 설문 응답 항목의 이름과 응답 값을 기반으로 검색 할 수 있습니다.

<br/>

> 💡 주어진 요구사항 이외의 추가 기능 구현에 대한 제약은 없으며, 새롭게 구현한 기능이 있을 경우 README 파일에 기재 해주세요.

<br/>

## 기술 요구 사항

- JAVA 11 이상 또는 Kotlin 사용
- Spring Boot 사용
- Gradle 기반의 프로젝트
- 온보딩 프로젝트 기능 요구사항은 서버(백엔드)에서 구현/처리
- 구현을 보여줄 수 있는 화면(프론트엔드)은 구현 금지
- DB는 인메모리 RDBMS(예: h2)를 사용하며 DB 컨트롤은 JPA로 구현. (NoSQL 사용 X)
- API의 HTTP Method는 자유롭게 선택해주세요.
- 에러 응답, 에러 코드는 자유롭게 정의해주세요.
- 외부 라이브러리 및 오픈소스 사용 가능 (단, README 파일에 사용한 오픈 소스와 사용 목적을 명확히 명시해 주세요.)

## 코드레벨 평가 항목

온보딩 프로젝트는 다음 내용을 고려하여 평가 하게 됩니다.

- 프로젝트 구성 방법 및 관련된 시스템 아키텍처 설계 방법이 적절한가?
- 작성한 애플리케이션 코드의 가독성이 좋고 의도가 명확한가?
- e.g. 불필요한(사용되지) 않는 코드의 존재 여부, 일정한 코드 컨벤션 등
- 작성한 테스트 코드는 적절한 범위의 테스트를 수행하고 있는가?
- e.g. 유닛/통합 테스트 등
- Spring Boot의 기능을 적절히 사용하고 있는가?
- 예외 처리(Exception Handling)은 적절히 수행하고 있는가?

## 우대사항

- 프로젝트 구성 추가 요건: 멀티 모듈 구성 및 모듈간 의존성 제약
- Back-end 추가 요건
- 트래픽이 많고, 저장되어 있는 데이터가 많음을 염두에 둔 구현
- 다수의 서버, 인스턴스에서 동작할 수 있음을 염두에 둔 구현
- 동시성 이슈가 발생할 수 있는 부분을 염두에 둔 구현

## 온보딩 프로젝트 제출 방식

### 소스코드

- 본 Repository에 main 브랜치를 포크하여 작업을 시작합니다.
- SpringBoot 프로젝트를 신규로 설정하고, 개인별로 main 브랜치에 PR을 공개적으로 먼저 작성한 후에 작업을 시작합니다.
- 이때 PR에는 WIP 레이블을 붙여서 작업 중임을 알게 해주세요.
- 코드를 마무리해서 리뷰받을 준비가 되면 WIP 레이블을 제거하고, Needs Review 레이블을 추가해주세요.
- 피드백을 받은 후 추가 작업을 진행할 때는 WIP 레이블을 다시 추가하고 Needs Review 레이블을 제거해주세요.
- 최소 기능 단위로 완성할 때 마다 커밋합니다.

### 기능 점검을 위한 빌드 결과물

빌드 결과물을 Executable jar 형태로 만들어 위 Branch에 함께 업로드 하시고, README에 다운로드 링크 정보를 넣어주시기 바랍니다. GitHub의 용량 문제로 업로드가 안되는 경우 다른 곳(개인 구글 드라이브 등)에 업로드 한 후 해당 다운로드 링크 정보를 README에 넣어주셔도 됩니다.

해당 파일을 다운로드 및 실행(e.g. java -jar project.jar)하여 요구 사항 기능 검증을 진행하게 됩니다. 해당 파일을 다운로드할 수 없거나 실행 시 에러가 발생하는 경우에는 기능 점검을 진행하지 않습니다. 온보딩 프로젝트 제출 전 해당 실행 파일 다운로드 및 정상 동작 여부를 체크해 주시기 바랍니다.
## About Project

### 엔티티 설계
- 설문조사의 개념 'Survey', 설문조사 항목의 개념 'SurveyItem', 선택형 항목의 경우 사용자 정의 option의 개념 'ItemAnswerOption', 설문조사 항목 응답의 개념 'ItemAnswer' 로 설계하였습니다.
- @OneToMany 의 연관관계를 사용하였습니다. 물리적으로 생각해 보았을 때 설문조사가 설문조사 항목의 리스트 를 가지고있고, 설문조사 항목이 옵션의 리스트를 가지고있다고 생각하였습니다.
- 저는 설문조사 응답(ItemAnswer) 를 Survey 에 종속시키지 않고 SurveyItem 에 종속시켰습니다.
- '설문조사와 항목들이 수정되어도 기존의 응답은 모두 유지해야 한다' 라고 적어주신 요구사항에 대해서는, Survey 수정 시 기존의 모든 항목들을 disabled 처리하고 요청에 포함된 모든 항목들을 save 하였습니다.
응답자를 위해 설문조사 테이블을 조회해야 할 경우에는 'isDisabled = false' 조건으로 조회하게 되고, 생성자를 위한 설문조사 응답 조회 에서는 disabled 에 조건을 걸지 않고 기존에 작성된 모든 항목들과 응답들을 불러오도록 구성하였습니다.
- 수정(disabled) 된 항목들을 삭제처리하고, 새로운 테이블(DisabledSurveyItem) 을 생성해서 관리하는 방법도 생각했었으나, 설문조사 생성자 입장에서는 '단순 수정' 만 진행했는데 disabled 된 리스트가 따로 저장된다는 부분이 바람직 하지 않다고
판단하여 이런 방식을 선택하였습니다.
- ItemAnswer
1. 단답형, 서술형 응답을 저장하는 String 타입의 answer,
2. 해당 응답이 선택형 항목인지에 대한 정보를 저장하는 Boolean 타입의 isOptioanlAnswer,
3. 선택형 항목의 id 를 참조하기 위한 Long 타입의 optionSeq,
4. 그리고 선택형 항목에 대한 응답의 경우, option 값을 같이 저장하기 위한 String 타입의 optionAnswer
가 포함되어 있습니다.

### 프로젝트 설계
- 디렉토리 구조를 동작으로 먼저 구분하고, 그 내에서 도메인 별로 나누도록 선택하였습니다.(도메인이 많아질 수록 이런 방식이 유리하다고 생각했습니다)
- Controller, service, business, repository, dto, entity, enums 등으로 레이어를 구분하였습니다.
- 응답 처리의 경우, Http Method 별 API 의 근본적인 목적에 대해 생각해보았을 때, GET 을 제외한 메서드들은 모두 '동작' 에 목적이 있다고 생각하고 이에 집중하고자
return type 을 void 로 처리하였습니다. 응답 성공과 실패를 HttpStatus Status 로 구분하고, 자세한 예외 상황에 대한 내용은 ExceptionResponseType.code 를 정의함으로 처리하였습니다.
- 예외의 경우 ApiException 객체를 구현하고 미리 정의해둔 ExceptionResponseType 으로 예외 상황을 구분하여 처리하였습니다.
- 사용자의 IP 주소를 '계정' 의 개념으로 사용하였습니다. IP 당 같은 설문조사 이름을 등록할 수 없도록 처리하였습니다.

### 그 외 참고사항들...
<b>다양한 프로젝트 경험이 없고, 누군가와 코드를 공유하며 작업을 해 본 적이 없기에 지금껏 '동작' 위주의 코딩을 하였습니다. setter 의 남용, 한 메서드에 너무 많은 역할을 주어 코드 재사용성 감소 등...
이번 프로젝트는 가능한 깔끔하게 코드를 작성하기 위해 노력해보았습니다.</b>

- 도메인 모델 패턴 방식으로 코드를 작성해 보았습니다.
- entity 를 생성하는 방식을 dto 를 통하는 방식 만으로 제한을 두어 무결성을 높이고자 하였습니다.
- service 와 business(query, action) 레이어를 구분하여 메서드의 역할을 구분하고 재사용성을 높여보았습니다.
- emun에는 실제 db에 저장 될 code(Integer type)와 개발자, 클라이언트 에서 구분을 편리하게 하기 위한 typString(String type) 으로 구성하였습니다.
- 깔끔한 코드를 작성하는데 집중하다보니, 12.04 단체 리뷰에서 말씀해주신 확장성을 고려한 설계에 대한 고민을 깊게 해보지 못하였습니다.



jar 파일 링크 : https://drive.google.com/file/d/1SCufHPUNIf-4xXv1hmgy170YHd1phlnK/view?usp=drive_link


api 명세서 및 postman : https://www.postman.com/aviation-geoscientist-88362321/my-workspace/documentation/xbmrsoc/survey?workspaceId=9ec3ee6f-dc14-444d-8807-b812eba77e74
60 changes: 60 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
plugins {
id 'java'
id 'org.springframework.boot' version '3.4.0'
id 'io.spring.dependency-management' version '1.1.6'
}

group = 'com.icd'
version = '0.0.1-SNAPSHOT'

java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}

configurations {
compileOnly {
extendsFrom annotationProcessor
}
}

repositories {
mavenCentral()
}

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'

compileOnly 'org.projectlombok:lombok'

runtimeOnly 'com.h2database:h2'

annotationProcessor 'org.projectlombok:lombok'

testImplementation 'org.assertj:assertj-core:3.22.0'
testImplementation 'org.springframework.boot:spring-boot-starter-test'

testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta"
annotationProcessor "jakarta.annotation:jakarta.annotation-api"
annotationProcessor "jakarta.persistence:jakarta.persistence-api"
}

def querydslSrcDir = '$buildDir/generated/querydsl'

clean {
delete file(querydslSrcDir)
}

tasks.withType(JavaCompile) {
options.generatedSourceOutputDirectory = file(querydslSrcDir)
}

tasks.named('test') {
useJUnitPlatform()
}
Binary file added gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
7 changes: 7 additions & 0 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Loading