Skip to content

[20기_이한슬, 최서지] spring-vote 미션 제출합니다. #8

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 61 commits into
base: angel-bridge
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
069c1d3
feat: 기본 엔티티 작성
choiseoji Dec 23, 2024
6060bea
feat: vote count 0으로 초기화
choiseoji Dec 23, 2024
596c9c3
feat: vote 했는지 안 했는지 체크
choiseoji Dec 23, 2024
c0006ce
chore: build.gradle mysql 추가
sseuldev Dec 26, 2024
30009a1
chore: gitignore에 yml 추가
sseuldev Dec 26, 2024
14a3611
chore: BaseEntity 추가
sseuldev Dec 26, 2024
38e253a
chore: 엔티티 추가 설정
sseuldev Dec 26, 2024
2d5da8b
feat: 성공 응답 코드 구현
sseuldev Dec 26, 2024
04ab8bf
feat: 오류 응답 코드 구현
sseuldev Dec 26, 2024
c5f568f
refactor: enum 타입에 description 추가
sseuldev Dec 26, 2024
f006d1a
chore: swagger 환경 설정
sseuldev Dec 26, 2024
4b79dd0
chore: cors 환경 설정
sseuldev Dec 26, 2024
09b5b85
feat: JWTUtil 구현
sseuldev Dec 26, 2024
0042ab2
feat: Refresh 엔티티 구현
sseuldev Dec 26, 2024
33284f8
feat: LoginRequestDto 구현
sseuldev Dec 26, 2024
0fcd5a3
feat: LoginFilter 구현
sseuldev Dec 26, 2024
7e855d3
feat: CustomUserDetails dto 구현
sseuldev Dec 26, 2024
a337730
feat: JWTFilter 구현
sseuldev Dec 26, 2024
56d9c17
feat: CustomUserDetailsService 구현
sseuldev Dec 26, 2024
1f8af7d
feat: SignupRequestDto 구현
sseuldev Dec 26, 2024
12774e8
feat: MemberResponseDto 구현
sseuldev Dec 26, 2024
12b2b39
feat: 회원가입 및 토큰 재발급 로직 구현
sseuldev Dec 26, 2024
47a5540
feat: AuthController 구현
sseuldev Dec 26, 2024
11eb4f9
fix: deleteByUserId 추가 및 반영
sseuldev Dec 26, 2024
12b4ba3
feat: SecurityConfig 구현
sseuldev Dec 26, 2024
17ef40a
feat: [GET] 회원 기본 정보 조회 API 구현
sseuldev Dec 26, 2024
aea0599
Merge pull request #1 from Netflix-Clone-CEOS/feat/member
choiseoji Dec 27, 2024
01b2138
delete: vote 엔티티 삭제
choiseoji Dec 28, 2024
973337a
feat: member에 team 객체를 넣어주도록
choiseoji Dec 28, 2024
e775f71
feat: 예외 코드 추가
choiseoji Dec 28, 2024
a48da71
feat: 멤버 엔티티 관련 작업
choiseoji Dec 28, 2024
178bf7b
feat: 허용 경로 추가
choiseoji Dec 28, 2024
66166c3
feat: team 객체를 주입하도록
choiseoji Dec 28, 2024
be24d40
feat: 필요한 dto 생성
choiseoji Dec 28, 2024
936c465
feat: 로그인 어노테이션 사용
choiseoji Dec 28, 2024
ba3ccaf
feat: Team 엔티티 생성
choiseoji Dec 28, 2024
c8bbc4e
feat: vote 작업 추가
choiseoji Dec 28, 2024
9b9cff4
Merge pull request #2 from Netflix-Clone-CEOS/feat/vote
choiseoji Dec 29, 2024
19b33f4
feat: developer 엔티티 추가로 관련 작업 수행
choiseoji Dec 29, 2024
3c1ee46
feat: team 저장 메서드 서비스 코드로 분류
choiseoji Dec 29, 2024
e72cf74
feat: teamController에서 서비스 코드 호출
choiseoji Dec 29, 2024
e73e74b
feat: 투표받을 엔티티를 developer로 변경
choiseoji Dec 29, 2024
b88a8a5
feat: api로 통일 + team, developer 생성 permit all
choiseoji Dec 30, 2024
cdfdae0
Merge pull request #3 from Netflix-Clone-CEOS/fix/vote
choiseoji Dec 30, 2024
62da593
fix : 파트장 조회하는 부분 teamName 가져오도록 수정
choiseoji Dec 30, 2024
03546b2
fix: @Login 어노테이션 MemberController에 적용
sseuldev Jan 2, 2025
2b055b8
fix: email 삭제
sseuldev Jan 2, 2025
4e0fb8d
fix: AuthenticationPrincipal 어노테이션으로 변경
sseuldev Jan 2, 2025
bb94895
Merge pull request #4 from Netflix-Clone-CEOS/feat/member
sseuldev Jan 2, 2025
2a98404
feat: 파트장 투표 결과에 teamName 반환하도록 추가
choiseoji Jan 4, 2025
43871e0
feat: 개발자 자기소개 반환하는 dto 추가
choiseoji Jan 4, 2025
7248eef
feat: 자기소개 추가
choiseoji Jan 4, 2025
b760a71
feat: 자기소개 추가
choiseoji Jan 4, 2025
2ffe005
feat: 자기소개 조회하는 api 추가
choiseoji Jan 4, 2025
80a0a07
feat: 자기소개 조회하는 api도 permit all 설정
choiseoji Jan 4, 2025
9741fa7
feat: 자기소개 조회하는 api도 permit all 설정
choiseoji Jan 4, 2025
dd4b6ac
feat: 자기소개 조회하는 api도 permit all 설정
choiseoji Jan 4, 2025
848fcec
feat: developer 생성할때 introduction 추가
choiseoji Jan 4, 2025
da94105
feat: 프론트 배포 주소 추가
choiseoji Jan 5, 2025
be54a1e
Merge pull request #5 from Netflix-Clone-CEOS/feat/https
choiseoji Jan 5, 2025
4e86872
Update README.md
choiseoji Jan 5, 2025
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
46 changes: 46 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
*#
*.iml
*.ipr
*.iws
*.jar
*.sw?
*~
.#*
.*.md.html
.DS_Store
.attach_pid*
.classpath
.factorypath
.gradle
.metadata
.project
.recommenders
.settings
.springBeans
.vscode
/code
MANIFEST.MF
_site/
activemq-data
bin
build
!/**/src/**/bin
!/**/src/**/build
build.log
dependency-reduced-pom.xml
dump.rdb
interpolated*.xml
lib/
manifest.yml
out
overridedb.*
target
.flattened-pom.xml
secrets.yml
.gradletasknamecache
.sts4-cache

.idea
.env
src/test/resources/application.yml
src/main/resources/application.yml
28 changes: 28 additions & 0 deletions HELP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Getting Started

### Reference Documentation
For further reference, please consider the following sections:

* [Official Gradle documentation](https://docs.gradle.org)
* [Spring Boot Gradle Plugin Reference Guide](https://docs.spring.io/spring-boot/3.3.7/gradle-plugin)
* [Create an OCI image](https://docs.spring.io/spring-boot/3.3.7/gradle-plugin/packaging-oci-image.html)
* [Spring Web](https://docs.spring.io/spring-boot/3.3.7/reference/web/servlet.html)
* [Spring Data JPA](https://docs.spring.io/spring-boot/3.3.7/reference/data/sql.html#data.sql.jpa-and-spring-data)
* [Spring Security](https://docs.spring.io/spring-boot/3.3.7/reference/web/spring-security.html)

### Guides
The following guides illustrate how to use some features concretely:

* [Building a RESTful Web Service](https://spring.io/guides/gs/rest-service/)
* [Serving Web Content with Spring MVC](https://spring.io/guides/gs/serving-web-content/)
* [Building REST services with Spring](https://spring.io/guides/tutorials/rest/)
* [Accessing Data with JPA](https://spring.io/guides/gs/accessing-data-jpa/)
* [Securing a Web Application](https://spring.io/guides/gs/securing-web/)
* [Spring Boot and OAuth2](https://spring.io/guides/tutorials/spring-boot-oauth2/)
* [Authenticating a User with LDAP](https://spring.io/guides/gs/authenticating-ldap/)

### Additional Links
These additional references should also help you:

* [Gradle Build Scans – insights for your project's build](https://scans.gradle.com#gradle)

114 changes: 113 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,113 @@
# spring_vote_20th
# spring_vote_20th

## 💡 구현 기능

**ERD**

![vote (1) (1)](https://github.com/user-attachments/assets/97c8d1d2-0247-48b3-845d-d1a0ec284b9a)

1. **Member**
- 로그인한 사용자(멤버)를 의미한다.
- 투표 권한이 있으며, 아래의 투표에 각각 최대 **1회 참여**할 수 있다.
- **vote_back, vote_front**: 개발자 투표
- **vote_team**: 팀 투표
2. **Team**과 **Developer**
- 투표 가능한 **후보**를 의미한다.
- 각 객체는 자신의 투표수를 나타내는 **count** 필드를 가진다.

<img width="586" alt="스크린샷 2025-01-06 오전 12 18 48" src="https://github.com/user-attachments/assets/a190ea29-7616-458d-9652-fd8407afac06" />

**Auth**

- JWT 방식 로그인을 사용합니다.
- **Access Token**은 헤더에 발급하고, **Refresh Token**은 쿠키로 발급합니다.
- **Refresh Token**은 별도의 `Refresh` 엔티티에 저장하여 검증합니다.
- 로그아웃 시 **Refresh Token**을 삭제하여 재사용을 방지합니다.

**Vote**

- 에러 처리
1. 같은 팀에 투표: `BAD_REQUEST_TEAM`
2. 다른 파트에 투표: `BAD_REQUEST_DEVELOPER`
3. 중복 투표
- 개발자 투표: `ALREADY_VOTE_DEVELOPER`
- 팀 투표: `ALREADY_VOTE_TEAM`

## 🧩 배포

### 가장 간단한 배포 방법

1. 스프링부트에서 BootJar을 실행해주면 build/libs 폴더 안에 jar 파일이 생성됨
2. 아래 명령어를 통해 jar 파일을 내 인스턴스에 옮겨줌

```java
scp -i "{my-key}.pem" ./build/libs/{jar-file-name}.jar ubuntu@{퍼블릭 IP}:/home/ubuntu
```

- **scp (Secure Copy Protocol)**
- SSH를 이용해 파일을 안전하게 복사하는 명령어이다. 로컬 시스템과 원격 시스템 간, 또는 원격 시스템들 간에 파일을 전송할 때 사용한다.
3. 인스턴스 터미널에 접속해 아래 명령어를 통해 jar 파일을 백그라운드에서 실행시켜주면 끝!

```java
nohup java -jar backend-0.0.1-SNAPSHOT.jar &
```

- **nohup (no hang up)**
- 터미널이 종료되어도 명령어 실행이 중단되지 않도록 보장하는 명령어이다.
- **&**
- 명령을 백그라운드에서 실행하는 쉘 연산자이다.

## 🚨 트러블 슈팅

프론트까지 배포를 하고 백엔드에 api 요청을 했는데 다음과 같은 에러가 발생했다.

<img width="1029" alt="KakaoTalk_Photo_2025-01-05-20-33-15 (1)" src="https://github.com/user-attachments/assets/19a42380-1cda-408d-be4d-538adfe8765c" />

### Mixed Content 란?

브라우저에서 HTTPS로 제공되는 웹 페이지가 보안되지 않은 HTTP 리소스를 로드하거나 요청할 때 발생하는 상황을 말한다.

HTTPS는 데이터가 암호화 되어 안전하게 전송됨을 보장하는데 HTTP는 암호화되지 않은 연결을 사용하여 HTTPS 페이지에서 HTTP 리소스를 로드하면 보안 문제가 발생한다고 한다.

→ 우리 프론트가 Https로 배포를 했는데, 백엔드에서 http로 배포를 해서 발생한 문제였다. 우리 백엔드 서버에 Https 를 적용해주기로 했다.

### https 적용하기

일단 도메인이 없던 상황이라, 도메인 없이 https를 적용할 수 있는 방법을 찾던 중 caddy를 알게되었습니다.

**caddy의 주요 역할**

1. 자동으로 tls 인증서를 발급해준다
2. nginx.conf와 같은 Caddyfile이 존재해, 리버스 프록시 설정이 가능하다.

**CaddyFile**

```java
{
admin 0.0.0.0:2020
}

[ec2 PUBLIC IP주소].nip.io {

tls [이메일 주소]
reverse_proxy localhost:8080

}
```

- `[ec2 PUBLIC IP주소]`: EC2 인스턴스의 퍼블릭 IP 주소를 포함합니다.
- **`.nip.io`**: **동적 DNS 서비스**로, 특정 IP 주소를 포함하는 임시 도메인 이름을 생성해 줍니다.
- 예: `123.45.67.89.nip.io`로 접속하면 `123.45.67.89`로 연결됩니다.
- → 이를 통해 도메인이 없어도 HTTPS를 사용할 수 있습니다.
- `tls [이메일 주소]` : Let's Encrypt를 사용해 인증서를 자동으로 발급받도록 이메일 설정을 해줍니다.
- 만약 **tls internal** 을 적는다면 외부 인증서 발급 없이 caddy 자체 인증서를 생성하여 발급합니다. → 주의할 점은 로컬에서만 사용 가능하다는 점..ㅎㅎ

**동작 흐름**

`https://123.45.67.89.nip.io/api/data`

1. 클라이언트가 도메인(`123.45.67.89.nip.io`)로 HTTPS 요청.
2. Caddy가 요청 수신 → 인증서 확인 및 암호화된 연결 설정.
3. Caddy는 요청을 분석 후, `/api/data`를 `localhost:8080`으로 전달.
4. 내부 애플리케이션(Spring Boot 서버)이 요청을 처리하고 응답 반환.
5. Caddy가 응답을 받아 클라이언트에게 전달.
49 changes: 49 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
plugins {
id 'java'
id 'org.springframework.boot' version '3.3.7'
id 'io.spring.dependency-management' version '1.1.7'
}

group = 'ceos'
version = '0.0.1-SNAPSHOT'

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

configurations {
compileOnly {
extendsFrom annotationProcessor
}
}

repositories {
mavenCentral()
}

dependencies {
runtimeOnly 'com.mysql:mysql-connector-j'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

// Swagger
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0'

// jwt
implementation "org.springframework.boot:spring-boot-starter-security"
implementation 'io.jsonwebtoken:jjwt-api:0.12.3'
implementation 'io.jsonwebtoken:jjwt-impl:0.12.3'
implementation 'io.jsonwebtoken:jjwt-jackson:0.12.3'
}

tasks.named('test') {
useJUnitPlatform()
}
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