Skip to content
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

[Feature/#2] 소셜 로그인 구현 #4

Merged
merged 18 commits into from
Aug 12, 2023
Merged

[Feature/#2] 소셜 로그인 구현 #4

merged 18 commits into from
Aug 12, 2023

Conversation

Mingyum-Kim
Copy link
Collaborator

@Mingyum-Kim Mingyum-Kim commented Aug 10, 2023

1️⃣ 작업 내용 (Contents)

image

OAuthClient를 인터페이스로 두고 Kakao와 Apple을 분리하는 걸 구현하는 과정에서 애를 좀 먹었다는 .. 😢
일단 서비스 테스트만 작성했는데, 실제로 인증 서버에서 승인 가능한 accessToken을 받아올 수가 없는지라 mockito를 사용해서 그 부분만 처리하였습니다!
작업 내용이 너무 많아서 검토하기 힘들 것 같은데, 천천히 내일까지 리뷰해주시면 감사하겠습니다 ❗❗❗

2️⃣ 링크 (Links)

#2

3️⃣ 희망 리뷰 완료 일 (Expected due date)

8월 11-12일

global/entity 폴더에 created_at, updated_at 필드를 넣는 BaseEntity 클래스를 작성하였습니다.
DB에 매핑될 User 객체를 생성하였습니다. Kakao, Apple 두 개의 소셜 타입을 구분할 SocialType 필드를 enum Type으로 추가하였습니다.
1. 클라이언트가 AccessToken을 전달할 때 접근하는 'POST /auth' 콜백 주소를 연결할 메서드를 생성하였습니다.
2. 컨트롤러 메서드의 request, response dto를 record 클래스로 정의하였습니다.
1. 팩토리 메서드 패턴을 적용하여 OAuthClient 인터페이스를 provider에 따라 구현체를 매핑하도록 설정하였습니다.
2. OAuthClient에서 소셜 사용자의 정보를 불러오고 User 객체로 변환하였습니다.
3. User가 기 가입한 회원이라면 바로 반환, 그렇지 않다면 DB에 등록 후 반환하기 위해 UserService에서 로직을 구현하였습니다.
4. 마지막으로 회원에 대한 JWT 를 발급하여 반환하였습니다.
@Mingyum-Kim Mingyum-Kim self-assigned this Aug 11, 2023
@Mingyum-Kim Mingyum-Kim added the feature New feature or request label Aug 11, 2023
KakaoClient 구현체에서 WebClient 라이브러리를 사용해 kapi.kakao.com 서버에 접근하여 사용자 정보 (KakaoUserInfo)를 추출하는 코드입니다.
1. createToken 메서드
2. validateToken 메서드
@Mingyum-Kim Mingyum-Kim marked this pull request as ready for review August 11, 2023 10:44
@@ -0,0 +1,7 @@
package com.backend.auth.presentation.dto;

public record LoginResponse (
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • 저희 프로젝트 위키에 적혀있는 디렉토리 구조에 따르면 auth 밑에 dto라는 디렉토리가 있어야 하는데, 민겸님께서는 application과 presentation 디렉토리 하단에 각각 dto라는 디렉토리를 만드셨네요! 🧐 저도 사실 민겸님처럼 구성하는 편이긴 한데, 민겸님 방식으로 진행할까요?! 참고로 저는 dto 디렉토리 밑에 request, response로 한번 더 나누긴 합니다~
  • 그때 카페에서 이야기 나눴던 방식은 access token과 refresh token을 함께 발급하는 방식이었는데 혹시 refresh token은 차후에 개발할 예정일까요??

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • 말씀하셨던대로 Controller와 Service 등 계층 별로 dto를 다르게 가져갈 예정이라면 제 방법대로 하는 게 좋을 것 같아요 ! request와 response 폴더 한 번 더 나누는 것으로 수정하겠습니다~
  • 우선적으로 access token 만 구현하였습니다! refresh token 과 기타 인증 로직과 함께 다른 PR에 반영하도록 할게요 👍

public abstract class BaseEntity {
@CreatedDate
@Column(name="created_at", nullable=false, updatable=false)
private LocalDateTime createdAt = LocalDateTime.now();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

baseEntity의 경우 민겸님이 따로 LocalDateTime.now()로 초기화 하지 않아도 자동으로 현재 시간이 기록됩니다~

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

userRepository.save() 함수 호출 시 created_at, updated_at이 NULL이 될 수 없다는 에러가 터져서 초기화를 해놓은 건데, 원래 아무런 설정을 하지 않아도 now()로 설정이 되어야하는건가요 ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

혹시 메인 springbootapplication 클래스 위해 EnableJpaAuditing 어노테이션 붙이셨을까요?!

})
@PostMapping("/auth")
public ResponseEntity<LoginResponse> generateAccessToken(@RequestBody LoginRequest loginRequest) throws Exception {
return ResponseEntity.ok(oauthService.login(loginRequest));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저희가 IOS 분들이랑 한번 더 회의를 해야 결정이 될 것 같긴 한데, 차후에 공통 응답 스펙으로 한번 더 감싸면 좋을 것 같습니다~~!!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

공통 응답 스펙으로 한번 더 감싼다는게 정확히 어떤 방식인지 사실 이해가 안가서요 .. ! 일단 제 방식대로 코딩했는데 나중에 한번더 얘기해보면 좋을 것 같아요 ~

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ApiResponse<T> {

    private int code;
    private String message;
    private T data;


    public ApiResponse(final int code, final String message) {
        this.code = code;
        this.message = message;
    }

    public static <T> ResponseEntity<ApiResponse> success(final SuccessCode successCode, final T data) {
        return ResponseEntity.status(successCode.getStatus())
                .body(new ApiResponse<>(successCode.getStatus(), successCode.getMessage(), data));
    }

    public static <T> ResponseEntity<ApiResponse> success(final SuccessCode successCode) {
        return ResponseEntity.status(successCode.getStatus())
                .body(new ApiResponse<>(successCode.getStatus(), successCode.getMessage(), null));
    }
}

이런 공통 응답 클래스 만들어서

    // OAuth2를 사용한 소셜 인증
    @PostMapping("/social")
    public ResponseEntity<ApiResponse> socialLogin(@Valid @RequestBody OAuthLoginRequest oAuthLoginRequest) {

        OAuthResponseDto oAuthResponseDto = oAuthService.login(oAuthLoginRequest.toDto());
        return ApiResponse.success(SuccessCode.INSERT_SUCCESS, oAuthResponseDto);
    }

이런 식으로 클라이언트에서 같은 양식의 응답을 받을 수 있도록 하는거에요~

this.userStatus = userStatus;
}

public static User from(OAuthUserInfo userInfo, String provider) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍👍 이런 팩토리 메서드 쓰면 깔끔해지고 좋은 것 같아요~

@Override
public OAuthUserInfo getUserInfo(String accessToken) {
return kakaoOauthLoginClient.get()
.uri(KAKAO_API_URL)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

혹시 getUserInfo 메서드에 uri로 KAKAO_API_URL을 넣고, kakaoOauthLoginClient() 메서드에 다시 한번 KAKAO_API_URL을 넣은 이유가 있을까요?!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

기본 세팅 시 baseUrl에는 'kapi.kakao.com'을, API 호출 시 uri에 'v2/user/me'를 넣는 구조라서 저렇게 작성했습니다! 주소는 다시 수정하도록 할게요 :)

return appleOauthLoginClient.get()
.uri(APPLE_API_URL)
.headers(h -> h.setBearerAuth(accessToken))
.retrieve()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

엇 혹시 애플 로그인이 KAKAO와 동일한 과정으로 유저 정보가 들어오나요?! 아마 토큰을 받아와서 복호화를 거치는 등의 복잡한 과정이 포함되있었던것 같아서 궁금해서 말씀드려요~~!!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

네 그렇네요 .. ㅜㅜ 확인해보니 복호화하는 과정이 있는 것 같습니다 이것도 다시 수정할게요!
참고 : https://hello-gg.tistory.com/m/65


public User findUserOrRegister(User uncheckedUser) {
Optional<User> user = userRepository.findBySocialIdAndSocialType(
uncheckedUser.getSocialId(),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

socialId는 모든 유저가 고유하게 가지고 있는 식별자인데, 혹시 provider와 함께 조회를 하는 이유가 있을까요?!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

카카오와 애플이 소셜 로그인시 각각의 id를 발급하기 때문에 provider와 id를 함께 조회해야한다고 생각했는데, id로만 조회하는 게 더 낫다고 생각하시나요?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 socialID 자체가 중복될 수 없는 값이고, 카카오와 애플도 socialID 형식이 달라서 socialID 컬럼 하나만으로 모든 유저를 식별할 수 있다고 생각했습니다! socialID만으로 필터링하나, socialID + Provider로 필터링하나 응답 결과가 똑같을꺼에요!

public abstract class BaseEntity {
@CreatedDate
@Column(name="created_at", nullable=false, updatable=false)
private LocalDateTime createdAt = LocalDateTime.now();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

혹시 메인 springbootapplication 클래스 위해 EnableJpaAuditing 어노테이션 붙이셨을까요?!

})
@PostMapping("/auth")
public ResponseEntity<LoginResponse> generateAccessToken(@RequestBody LoginRequest loginRequest) throws Exception {
return ResponseEntity.ok(oauthService.login(loginRequest));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ApiResponse<T> {

    private int code;
    private String message;
    private T data;


    public ApiResponse(final int code, final String message) {
        this.code = code;
        this.message = message;
    }

    public static <T> ResponseEntity<ApiResponse> success(final SuccessCode successCode, final T data) {
        return ResponseEntity.status(successCode.getStatus())
                .body(new ApiResponse<>(successCode.getStatus(), successCode.getMessage(), data));
    }

    public static <T> ResponseEntity<ApiResponse> success(final SuccessCode successCode) {
        return ResponseEntity.status(successCode.getStatus())
                .body(new ApiResponse<>(successCode.getStatus(), successCode.getMessage(), null));
    }
}

이런 공통 응답 클래스 만들어서

    // OAuth2를 사용한 소셜 인증
    @PostMapping("/social")
    public ResponseEntity<ApiResponse> socialLogin(@Valid @RequestBody OAuthLoginRequest oAuthLoginRequest) {

        OAuthResponseDto oAuthResponseDto = oAuthService.login(oAuthLoginRequest.toDto());
        return ApiResponse.success(SuccessCode.INSERT_SUCCESS, oAuthResponseDto);
    }

이런 식으로 클라이언트에서 같은 양식의 응답을 받을 수 있도록 하는거에요~


public User findUserOrRegister(User uncheckedUser) {
Optional<User> user = userRepository.findBySocialIdAndSocialType(
uncheckedUser.getSocialId(),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 socialID 자체가 중복될 수 없는 값이고, 카카오와 애플도 socialID 형식이 달라서 socialID 컬럼 하나만으로 모든 유저를 식별할 수 있다고 생각했습니다! socialID만으로 필터링하나, socialID + Provider로 필터링하나 응답 결과가 똑같을꺼에요!

@Mingyum-Kim Mingyum-Kim merged commit f1d9af7 into dev Aug 12, 2023
0 of 2 checks passed
Mingyum-Kim added a commit that referenced this pull request Sep 17, 2023
* 상위 목표 엔티티 구현 (#5)

* chore: Lombok, JPA 의존성 추가

* feat: plan 엔티티 내 유효성 검사 구현

* feat: PlanRepository 생성

* test: plan 엔티티 테스트 작성

- 상위 목표 제목 길이 validation 테스트
- 상위 목표 시작, 달성 날짜 validation 테스트
- 상위 목표 제목 길이 Figma 참고해서 15자 제한

* feat: 상위 목표 기간 LocalDate 타입으로 변경 (#3)

기간을 설정할때 연월일 까지만 데이터를 받기에 시,분까지 데이터를 받는 LocalDateTime은 불필요하다고 판단했음.

* [Feature/#2] 소셜 로그인 구현 (#4)

* feat: BaseEntity 작성

global/entity 폴더에 created_at, updated_at 필드를 넣는 BaseEntity 클래스를 작성하였습니다.

* feat: User Entity 생성 (#2)

DB에 매핑될 User 객체를 생성하였습니다. Kakao, Apple 두 개의 소셜 타입을 구분할 SocialType 필드를 enum Type으로 추가하였습니다.

* chore: Swagger, Logging 클래스 global 폴더로 이동

* feat: OAuthController 생성 및 콜백 메서드 생성

1. 클라이언트가 AccessToken을 전달할 때 접근하는 'POST /auth' 콜백 주소를 연결할 메서드를 생성하였습니다.
2. 컨트롤러 메서드의 request, response dto를 record 클래스로 정의하였습니다.

* feat: login 로직을 구현한 OAuthService 생성

1. 팩토리 메서드 패턴을 적용하여 OAuthClient 인터페이스를 provider에 따라 구현체를 매핑하도록 설정하였습니다.
2. OAuthClient에서 소셜 사용자의 정보를 불러오고 User 객체로 변환하였습니다.
3. User가 기 가입한 회원이라면 바로 반환, 그렇지 않다면 DB에 등록 후 반환하기 위해 UserService에서 로직을 구현하였습니다.
4. 마지막으로 회원에 대한 JWT 를 발급하여 반환하였습니다.

* build: syntax error 수정

* build: syntax error 수정

* build: Junit Test 관련 권한 추가

* feat: WebClient를 이용해 카카오 인증서버에서 사용자 추출 (#2)

KakaoClient 구현체에서 WebClient 라이브러리를 사용해 kapi.kakao.com 서버에 접근하여 사용자 정보 (KakaoUserInfo)를 추출하는 코드입니다.

* feat: JwtProvider 클래스 생성

1. createToken 메서드
2. validateToken 메서드

* chore: .gitignore 수정

* feat: 애플 로그인 구현

* refactor: OAuthHandler에서 Provider별 클래스 분리 구현

* test: OAuthServiceTest 로그인 성공 테스트 생성(#2)

* feat: KakaoClient BASE_URL과 URI 분리

* style: dto 폴더구조 request, response 나눠서 변경

* refactor: SocialId만 이용해서 사용자 조회하도록 변경

* refactor: BaseEntity에 자동으로 날짜를 주입하도록 설정

---------

Co-authored-by: MingyeomKim <[email protected]>

* [Feature/#7] 설정 파일 submodule로 관리 (#8)

* build: db 정보 암호화를 위한 submodules 설정(#7)

* build: github Secrets 설정 수정

* fix: build.yml의 들여쓰기 오류 수정

* feat: 빌드 시 submodule 설정 파일 불러올 수 있도록 build.gradle 수정

* build: deploy.yml ACTION_TOKEN 추가

* build: build.gradle 라이브러리 중복 제거

* "build: build.gradle에 active profile 설정 추가 (#7) "

* feat: dev 환경 데이터베이스 설정 추가

* build: dev 환경에서 빌드되도록 수정

* fix: build.yml의 test 명령어 수정

* fix: build.yml의 Publish unit test r구문 수정

* fix: build.yml test 파일 경로 수정"

* "build: test 시 h2 database에서 작동하도록 application-tets.yml 추가

* chore: .gitignore 수정

* build: test profile을 test로 변경

* test: config 설정 수정

* build: build.yml의 Publish Unit Test Results에 토큰 추가

* build: test-results files 경로 수정

* build: github actions permissions를 write 권한으로 변경

* build: build.yml에 issues: write 권한 추가

* refactor: User 명칭을 Member로 변경

---------

Co-authored-by: MingyeomKim <[email protected]>

* [Feature/#6] 공통 응답 추가 및 상위 목표 단건 조회 기능 구현 (#9)

* feat: 상위 목표 d-day 기능 구현, 테스트 작성 (#6)

- 상위 목표 종료 일자 필수 입력으로 확정 후, d-day 계산 로직 plan 엔티티내 생성 후 테스트
- planService에 상위 목표 단건 조회 로직 추가

* feat: 공통 응답 스펙 추가

* feat: 상위 목표 삭제 기능 추가

- Service에 삭제 기능 추가, 차후 테스트 필요
- 상위 목표 생성 Controller DTO 추가

* chore: application.yml 수정

* test: CI 테스트

* refactor: controller내 pathVariable 제거

* chore: build.yml을 테스트 환경에서 동작하도록 수정

* refactor: 소셜 로그인 시 input을 userId로 맞추어 수정 (#11) (#12)

Co-authored-by: MingyeomKim <[email protected]>

* [Feature/#13] TokenProvider 클래스 생성 및 Refresh Token 반환 (#14)

* feat: Refresh token을 생성하도록 TokenProvider 클래스 추가

* test: TokenProvider 단위 테스트 생성

* test: TokenProviderTest 오류 수정

---------

Co-authored-by: MingyeomKim <[email protected]>

* [Feature/#10] 상위 목표 리스트 조회 기능 구현 (#15)

* feat: 상위 목표 d-day 기능 구현, 테스트 작성 (#6)

- 상위 목표 종료 일자 필수 입력으로 확정 후, d-day 계산 로직 plan 엔티티내 생성 후 테스트
- planService에 상위 목표 단건 조회 로직 추가

* chore: git 캐시 초기화

* feat: 상위 목표 생성, 수정 기능 구현 (#10)

* refactor: 상위 목표 도메인 명을 Plan에서 Goal로 변경

- Goal이라는 단어가 목표라는 의미를 더 잘 표현하는 것 같아서 변경하게 되었습니다

* refactor: 공통 응답 스펙명 CustomResponse로 변경

- Swagger에 있는 ApiResponse와 네이밍이 같아서 패키지 명 전체를 명시해야 함. 따라서 customResponse로 명칭 변경함

* feat: 공통 예외 스펙 추가

- 공통 예외 스펙과 exceptionHandler 추가

* chore: QueryDSL 세팅

* feat: 상위 목표 페이징 조회 기능 개발

- 커서 기반 페이지네이션을 사용
- Service 통합 테스트 후 Controller 개발 예정

* test: 상위 목표 페이징 조회 기능 테스트

- 테스트 데이터간 독립성을 위해 databaseCleaner 추가

* test: 페이징 기능 응답 스펙 변경

- 기존의 Slice의 반환 형식이 no offset 기반 페이징에서는 불필요하다고 판단되어 필요한 데이터만 파싱 처리함

* refactor: 상위 목표 통계 기능 삭제 및 테스트 수정

* feat: 상위 목표 상태별 개수 조회 기능 추가

- 기능 추가 및 테스트 진행 완료

* feat: 상위 목표 리스트에 dDay 컬럼 추가

- Swagger 어노테이션 수정

* feat: ErrorCode에 상위 목표 예외 추가

* test: GoalStatus 변경

* refactor: CustomResponse 오타 수정

* refactor: Swagger ApiResponse 제거

ApiResponse로 응답값을 제대로 표현할 수 없다고 판단되어 우선은 배제하기로 결정

* refactor: GlobalExceptionHandler 수정

* refactor: 클래스 내 빈공간 제거

* refactor: Tag와 Operation 재배치

* [Feature/#17] refresh token 발급 시 Redis에 저장하도록 설정 (#18)

* feat: Redis 저장소 추가 및 세팅 (#17)

* docs: @parameter 어노테이션으로  OAuthController 파라미터 설명 추가

* refactor: 소문자 provider를 대문자로 변경하는 함수 작성

* feat: OAuthController에 issue 메서드 추가 (#17)

* refactor: socialId를 uid로, socialType을 provider로 명칭 변경

socialId가 사실상 사용자 식별 필드로 사용된다. 그러나 문자열인 socialId를 PK로 두는 것은 한계가 있기 때문에 uid로 명칭을 변경한다. 또한, Provider와 SocialType 명칭도 겹치기 때문에 provider라는 단어로 통일한다

* feat: RefreshToken, RefreshTokenRepository 작성 (#17)

* feat: 액세스 토큰 만료 시 재발급 요청하는 reissue 서비스 코드 작성 (#17)

* feat: 로그인 시 refresh token을 redis에 저장하는 기능 추가 (#17)

* refactor: Auth 비즈니스 로직 Exception 처리

* feat: Redis 설정 수정

* refactor: login 호출 시 잘못된 provider가 입력되는 경우 예외처리

* test: reissue, login fail 테스트 케이스 추가 (#17)

* refactor: CustomResponse를 사용하여 Controller 반환

* feat: @Valid 어노테이션 추가

* ci: 배포 시 테스트되지 않도록 deploy.yml 수정

* build: build.yml에 Redis 설정 추가

* build: redis port 입력 방식 수정

* refactor: 풀 리퀘스트 리뷰 반영

---------

Co-authored-by: MingyeomKim <[email protected]>

* [Feature/#16] 하위 목표 기능 구현 (#20)

* feat: 상위 목표 d-day 기능 구현, 테스트 작성 (#6)

- 상위 목표 종료 일자 필수 입력으로 확정 후, d-day 계산 로직 plan 엔티티내 생성 후 테스트
- planService에 상위 목표 단건 조회 로직 추가

* feat: detail_goal 엔티티 설계 (#16)

* feat: detailGoal 엔티티 설계 (#16)

* feat: detailGoal 전체 조회 기능 구현 (#16)

* feat: detailGoal 전체 조회 Controller 구현

* feat: detailGoal 저장 기능 구현 (#16)

* refactor: 에러 코드 수정

- Goal 에러 코드 수정
- Detail Goal 에러 코드 추가

* feat: detail goal 상세 조회 응답값 변경 (#16)

- 요일 정보를 EnumSet으로 관리하는걸 생각했으나 엔티티에는 적용이 되지 않아 List로 관리하기로 결정

* refactor: detail goal 요청 시 요일 정보 string으로 변경

* feat: detail goal 추가 시 goal 내부 카운트 증가 로직 추가 (#16)

* feat: detail goal 수정, 삭제 기능 추가 (#16)

* feat: detail goal 달성, 달성 해제 기능 구현 (#16)

* test: detail goal 서비스 테스트 작성 (#16)

* refactor: application-prod.yml 임시 파일 삭제

* feat: detail goal, goal 조회 쿼리에 isDeleted 판별 조건 추가 (#16)

기본적으로 soft delete를 사용하기 때문에 isDeleted에 대한 판별 조건을 포함해야 한다

* feat: goal 삭제 시 연관 detail goal 삭제 로직 추가 (#16)

* feat: 전체 detail goal과 달성 detail goal 계산 및 조회 로직 추가 (#16)

* [Feature/#21] 보관함 복구 기능, 회고 개수 조회 기능 구현 (#22)

* feat: 상위 목표 d-day 기능 구현, 테스트 작성 (#6)

- 상위 목표 종료 일자 필수 입력으로 확정 후, d-day 계산 로직 plan 엔티티내 생성 후 테스트
- planService에 상위 목표 단건 조회 로직 추가

* 간격 수정

* feat: 상위 목표 복구 기능 구현 (#21)

* refactor: transactional 어노테이션 추가

* feat: LocalTime 요청 응답 값 오전/오후 반영하도록 변경 (#21)

* feat: 상위 목표 제약 조건 수정 (#21)

- 현재 보다 이전 날짜를 시작일로 선택 불가능하다는 조건이 없기에 조건 제거
- 보관함에서 복구 시 시작, 종료 날짜를 초기화 예정이기에 nullable을 true로 변경

* feat: 상위 목표 복구 기능 수정 (#21)

- 복구 시 새로운 데이터로 초기화해야 복구가 완료 되도록 설정

* feat: 회고 작성 가능한 완료 목표 개수 조회 (#21)

* feat: goal 생성시, goalstatus 생성자 주입으로 변경

- goalstatus 값을 변경해서 테스트 해야 할 경우들이 있다고 판단되어, 테스트 코드 편의성과 changeGoalStatus라는 setter 메서드를 제거하기 위해 작업을 진행함

* test: 테스트 작성 완료

* refactor: GoalController내 위치 변경

* application.yml 제거

* refactor: goalController 공통 URI 통일

* [Feature/#23] 하위 목표 모두 성공시 보상 제공 및 팝업 기능 구현 (#25)

* feat: 상위 목표 d-day 기능 구현, 테스트 작성 (#6)

- 상위 목표 종료 일자 필수 입력으로 확정 후, d-day 계산 로직 plan 엔티티내 생성 후 테스트
- planService에 상위 목표 단건 조회 로직 추가

* 간격 수정

* feat: 보상 제공 기능 구현 (#23)

* feat: 상위 목표 달성 시 팝업 기능 구현 (#23)

- 랜덤으로 보석 지급 기능 구현
- 상위 목표 리스트 조회 시 보석 enum도 조회 추가
- 보석 지급과 함께 complete 상태의 상위 목표 개수 조회

* test: 상위 목표 성공 시 기능 테스트 작성 (#23)

* refactor: 상위 목표 개수 반환값 및 주석 수정

* [Feature/#24] 채움함 내 상위 목표의 종료 기간 경과 시 보관함으로 이동하는 스케쥴러 구현 (#26)

* feat: 상위 목표 d-day 기능 구현, 테스트 작성 (#6)

- 상위 목표 종료 일자 필수 입력으로 확정 후, d-day 계산 로직 plan 엔티티내 생성 후 테스트
- planService에 상위 목표 단건 조회 로직 추가

* 간격 수정

* feat: 0시 0분에 호출되는 스케쥴러 구현 (#24)

* .gitignore 초기화

* test: 스케쥴러 테스트 작성

* test: 스케쥴러 테스트 작성 (#24)

* feat: cron 수정 (#24)

* Cicd test (#27)

* feat: 상위 목표 d-day 기능 구현, 테스트 작성 (#6)

- 상위 목표 종료 일자 필수 입력으로 확정 후, d-day 계산 로직 plan 엔티티내 생성 후 테스트
- planService에 상위 목표 단건 조회 로직 추가

* 간격 수정

* 서브 모듈 수정

* ci: redis container 설정 추가

* ci: SuperCharge의 Redis Server를 사용하도록 수정

* ci : build시 submodule을 가져오도록 설정

* ci: deploy 대상을 dev 브랜치로만 변경

* ci: deploy.yml의 submodule를 recursive로 설정

* ci: submodule 업데이트

* ci: dev profile로 빌드하도록 수정 및 submodule update 구문 추가

* [Feature/#19] 로그아웃, 회원 탈퇴 구현 및 Custom Filter 생성 후 Spring Security 적용 (#29)

* feat: 로그아웃 기능 추가 (#19)

* feat: Redis에 블랙 리스트 기능 추가 (#19)

* refactor: BlackList 도메인에서 status 제외

* feat: 회원 탈퇴 기능 구현 (#19)

* feat: reissue 시 refresh token도 새로 발급하도록 수정

* feat: Security Config 생성 및 OAuthController URI 통일

* feat: JwtFilter 구현 및 TokenProvider의 getAuthentication 작성

* feat: 인증, 인가 로직 실패 시 Exception Handler 작성

* feat: Q클래스 생성

* chore: SecurityConfig 작성

* feat: SecurityConfig 설정 추가

* test: TokenProviderTest의 멤버 호출 구문 Mocking

* ci: build.yml, deploy.yml에서 submodule 자동 업데이트하도록 수정

* refactor: 토큰 유효성 검사 중복 제거

* feat: 회원 탈퇴 시 블랙 리스트에 추가

* feat: jwtFilter에서 블랙리스트 조회하는 로직 추가

* refactor: OAuthController의 함수 명칭을 일관되게 변경

* build: 라이브러리 꼬임 해결

* ci: java 실행 시 sudo 권한 추가

* docs: swagger cors에러 수정

* chore: 모든 URL 접근 가능하도록 설정

* refactor: jwtFilter에서 예외 던지지 않도록 수정

* chore: 모든 경로 접근 허용

* chore: 모든 경로 접근 허용

* refactor: JwtFilter에서 모든 Exception을 제외

* refactor: CORS 에러 해결

* chore: swagger에 authorization 인증 받을 수 있도록 수정

* chore: SwaggerConfig 수정

* build: run_new_was.sh 스크립트 들여쓰기 수정

* chore: run_new_was.sh가 동작 확인을 위한 로그 출력

* build: run_new_was.sh 에서 구동할 포트를 죽이는 명령어 수정

* feat: 회원 탈퇴 컨트롤러 URL추가

* [Feature/#31] 유저 로그인 시 fcm token을 저장하는 로직 구현 (#32)

* feat: 로그인 시 fcm token을 함께 전달받도록 수정

* feat: Fcm Token 저장 및 조회 로직 추가

* [Feature/#28] 알림 요일과 시간에 따라 FCM 알림을 전송하는 기능 구현 (#35)

* feat: 상위 목표 d-day 기능 구현, 테스트 작성 (#6)

- 상위 목표 종료 일자 필수 입력으로 확정 후, d-day 계산 로직 plan 엔티티내 생성 후 테스트
- planService에 상위 목표 단건 조회 로직 추가

* 간격 수정

* 최신 사항 머지

* git cache 초기화

* feat: 푸시 알람 스케쥴러 구현 (#28)

- 매일 30분 간격으로 작동하는 스케쥴러 구현
- FCM 서비스를 호출하는 event 구현

* feat: 요일, 시간별 알림 전송 스케쥴러 구현 (#28)

* test: detailGoalQueryRepository 테스트 추가 (#28)

* refactor: 공통 응답 스펙 수정

* docs: swagger 문서 수정

* docs: 코드,메세지 설명 추가

* feat: 응답 Response에 Schema 추가 (#36)

* chore: 토큰의 만료시간 임의 변경

* locale (#39)

* fix: locale 수정

* JsonFormat pattern 변경 (#41)

* fix: localtime 형식 변경

* [Feature/#37] 회고 도메인 생성 및 저장, 조회 로직 구현 (#42)

* refactor: fcmToken 조회 로직 수정, logout, withdraw에 추가

* feat: 회고 도메인 생성 (#37)

* feat: 회고 도메인의 Repository 생성

* feat: 회고 저장 및 조회 로직 구현 (#37)

* feat: 회고의 내용을 담는 RetroSpectContent 분리 (#37)

* test: 회고 저장 및 조회 서비스 로직 테스트

* feat: 회고 저장 및 조회 컨트롤러 구현 (#37)

* refactor: 의존성 관련 오류 수정

* [Refactor/#37] 회고 기능 관련 리팩토링 (#44)

* LocalDate JSON 응답 형식 변경 (#45)

* refactor: GoalController LocalTime 형식 변경

* chore: JPA의 ddl-auto를 create로 설정

* build: 빌드 시 워크플로우에서 secrets 불러오는 것 제외

* feat: Retrospect Response에 hasGuide 컬럼 추가

* build: build.yml 워크플로우에서 서브모듈 로직 제외

* refactor: contents의 @column 삭제

* chore: run_new_was.sh의 내용 일부 수정

* chore: config의 application-dev.yml 수정

* refactor: Retrospect와 Content를 양방향 매핑으로 변경

* refactor: retrospect content가 retrospect를 가져오지 못하는 부분 수정

* chore: ddl-auto를 create로 변경

* [Feature/#38] FCM 푸시 알림 기능 연동 후 하위 목표 알림 스케쥴러와 연결한다 (#46)

* feat: FCM 알림 설정 및 연동 (#38)

* refactor: GoalController LocalTime 형식 변경

* feat: FCM 알림 스케쥴링 기능 복구

* refactor: 테스트 수정 및 도메인 디렉토리 구조 변경

* refactor: DetailGoal 수정 시 locale 정보 변경

* submodule내 FCM 설정 파일 경로 수정 (#50)

* fix: submodule에 fcm_key.json 경로 수정

* 하위 목표 시간 locale 응답 ko로 수정 (#51)

* refactor: 하위 목표 응답 시간 locale ko로 수정

* 상위 목표 개수 카운트 쿼리 수정 (#52)

- 삭제 여부 판단 로직을 쿼리의 having 부분에서 where 절로 옮김

* [Refactor/#47] 사용자 인증 필터에서 발생하는 예외 핸들러 필터 구현 (#49)

* feat: 예외를 발생시키는 JwtExceptionFilter 클래스 생성

* refactor: TokenProvider의 validateToken이 JwtException을 반환하도록 수정

* refactor: 따로 처리가 필요한 인증 예외 클래스를 생성하고, Token 검증 오류 시 Throw한다.

* feat: 블랙 리스트 Exception 클래스 생성, Authentication 필터 수정

* feat: 필터의 오류 핸들링 필터를 추가 (#47)

* feat: 인증 필터를 핸들링하는 필터 작성 (#47)

추가로 궁금한 점 :

(1) 토큰 만료 시 = reissue 요청
(2) 토큰이 없는 경우 = 로그인 요청
(3) 토큰이 잘못된 경우 = 올바르지 않다는 메시지 반환

이런 식으로 구현할려고 했는데, ErrorCode가 달라지는 것 말고는 별 다른 처리할 것이 없다고 생각해서 setErrorResponse 메소드 하나로 통일하여 예외를 처리하였다. 이렇게 획일화하고 나니 그냥 JwtException 하나로만 서로 다른 ErrorCode를 넣어서 구현해도 같은 결과를 가져올 것 같아서, Exception 클래스의 분리의 필요성을 못느꼈다.

* refactor: jwt 토큰의 유효성 검증은 따로 Exception 처리 제외

* chore: config 수정 사항 반영

* 상위 목표 수정 기능 Service 파라미터 수정 및 Security Config 변경 (#53)

* refactor: 상위 목표 수정 컨트롤러에서 Path Variable 사용하도록 변경

* refactor: SecurityConfig 설정 변경

* 기존에 전체 허용으로 열려있던 URL 경로 권한을 인증 URL로 제한

* Spring Security내 permitAll 동작할 수 있도록 JwtFilter 수정 (#54)

* refactor: permitAll한 url은 token 예외가 발생하지 않도록 처리

* GoalResponse @jsonformat 수정 (#55)

* refactor: GoalResponse의 JsonFormat 수정

* JWT 유효기간 수정 (#56)

* refactor: JWT 만료 시간 수정

* 하위 목표 수정 문제 해결 및 상위 목표 페이징 커서 수정 (#57)

* refactor: 페이징 커서 null에서 -1일때 전체 조회하도록 수정

* 회고 작성 시 보관함 내 목표 리마인드 기능 추가 (#58)

* feat: 보관함 목표 리마인드 기능 개발

* 상위 목표 리스트 조회 시 리마인드 여부 컬럼 추가 (#59)

* refactor: 상위 목표 리스트 반환 시 reminder 여부 컬럼 추가

* 보관함에 있는 목표 조회 시 d-day 0으로 계산 (#60)

* 보관함에 있는 목표 d-day 계산 시 0 반환하도록 변경

* 보관함에 있는 목표 조회 시 d-day 값을 음수로 반환 (#61)

* 보관함에 있는 목표 조회 시 d-day 값을 음수로 반환

* feat: 토큰 재발급 시, 재발급된 refresh token을 redis에 저장

* refactor: SecurityConfig 에서 exception Handling 제외

* refactor: reissue 시 refresh token을 조회할 수 없는 부분 수정

* hotfix: import 시 오타 수정

* refactor: /auth 경로를 Authentication Filter를 거치지 않도록 설정

* hotfix: URI와 Request Method 확인을 위한 로깅 처리

* refactor: 허용한 URL 이외의 요청에 인증을 거치도록 설정

* feat: 상위 목표, 세부 목표 API JWT 인증 거치도록 설정

* feat: 최초 로그인 시 관련 정보를 함께 Response에 전달

* 인증 유저 정보를 사용해서 사용자 상위 목표를 식별한다 (#62)

- @AuthenticationPrincipal을 통해 인증 유저 식별자 가져옴

* refactor: 재로그인 시 refresh, fcm token 삭제하는 코드 제거

* refactor: 애플리케이션 실행 시 Asia/Seoul Timezone 설정

* test: 토큰 테스트를 위해 유효 기간을 짧게 설정

* refactor: 저장되지 않은 토큰 입력 시 401 에러 반환하도록 수정

* refactor: 토큰의 유효시간 정상화

* test: 토큰 유효시간 짧게 설정

* refactor: 리프레시 토큰 유효기간 정상화

* test: reissue 테스트를 위한 로그 추가

* refactor: refresh Token 객체 timeToLive설정

* refactor: @column에 unique=true를 추가하여 해결 (#65)

* refactor: 토큰 유효시간 정상화

* 목표 달성 후 보상 지급 시, 로그인한 사용자의 달성 목표만 카운트 하도록 설정한다 (#66)

* refactor: 보상 지급 시 달성 목표 카운트 수정

---------

Co-authored-by: Seo Jemin <[email protected]>
Co-authored-by: MingyeomKim <[email protected]>
@Mingyum-Kim Mingyum-Kim deleted the feature/#2 branch September 17, 2023 09:08
Mingyum-Kim added a commit that referenced this pull request Sep 17, 2023
* 상위 목표 엔티티 구현 (#5)

* chore: Lombok, JPA 의존성 추가

* feat: plan 엔티티 내 유효성 검사 구현

* feat: PlanRepository 생성

* test: plan 엔티티 테스트 작성

- 상위 목표 제목 길이 validation 테스트
- 상위 목표 시작, 달성 날짜 validation 테스트
- 상위 목표 제목 길이 Figma 참고해서 15자 제한

* feat: 상위 목표 기간 LocalDate 타입으로 변경 (#3)

기간을 설정할때 연월일 까지만 데이터를 받기에 시,분까지 데이터를 받는 LocalDateTime은 불필요하다고 판단했음.

* [Feature/#2] 소셜 로그인 구현 (#4)

* feat: BaseEntity 작성

global/entity 폴더에 created_at, updated_at 필드를 넣는 BaseEntity 클래스를 작성하였습니다.

* feat: User Entity 생성 (#2)

DB에 매핑될 User 객체를 생성하였습니다. Kakao, Apple 두 개의 소셜 타입을 구분할 SocialType 필드를 enum Type으로 추가하였습니다.

* chore: Swagger, Logging 클래스 global 폴더로 이동

* feat: OAuthController 생성 및 콜백 메서드 생성

1. 클라이언트가 AccessToken을 전달할 때 접근하는 'POST /auth' 콜백 주소를 연결할 메서드를 생성하였습니다.
2. 컨트롤러 메서드의 request, response dto를 record 클래스로 정의하였습니다.

* feat: login 로직을 구현한 OAuthService 생성

1. 팩토리 메서드 패턴을 적용하여 OAuthClient 인터페이스를 provider에 따라 구현체를 매핑하도록 설정하였습니다.
2. OAuthClient에서 소셜 사용자의 정보를 불러오고 User 객체로 변환하였습니다.
3. User가 기 가입한 회원이라면 바로 반환, 그렇지 않다면 DB에 등록 후 반환하기 위해 UserService에서 로직을 구현하였습니다.
4. 마지막으로 회원에 대한 JWT 를 발급하여 반환하였습니다.

* build: syntax error 수정

* build: syntax error 수정

* build: Junit Test 관련 권한 추가

* feat: WebClient를 이용해 카카오 인증서버에서 사용자 추출 (#2)

KakaoClient 구현체에서 WebClient 라이브러리를 사용해 kapi.kakao.com 서버에 접근하여 사용자 정보 (KakaoUserInfo)를 추출하는 코드입니다.

* feat: JwtProvider 클래스 생성

1. createToken 메서드
2. validateToken 메서드

* chore: .gitignore 수정

* feat: 애플 로그인 구현

* refactor: OAuthHandler에서 Provider별 클래스 분리 구현

* test: OAuthServiceTest 로그인 성공 테스트 생성(#2)

* feat: KakaoClient BASE_URL과 URI 분리

* style: dto 폴더구조 request, response 나눠서 변경

* refactor: SocialId만 이용해서 사용자 조회하도록 변경

* refactor: BaseEntity에 자동으로 날짜를 주입하도록 설정

---------

Co-authored-by: MingyeomKim <[email protected]>

* [Feature/#7] 설정 파일 submodule로 관리 (#8)

* build: db 정보 암호화를 위한 submodules 설정(#7)

* build: github Secrets 설정 수정

* fix: build.yml의 들여쓰기 오류 수정

* feat: 빌드 시 submodule 설정 파일 불러올 수 있도록 build.gradle 수정

* build: deploy.yml ACTION_TOKEN 추가

* build: build.gradle 라이브러리 중복 제거

* "build: build.gradle에 active profile 설정 추가 (#7) "

* feat: dev 환경 데이터베이스 설정 추가

* build: dev 환경에서 빌드되도록 수정

* fix: build.yml의 test 명령어 수정

* fix: build.yml의 Publish unit test r구문 수정

* fix: build.yml test 파일 경로 수정"

* "build: test 시 h2 database에서 작동하도록 application-tets.yml 추가

* chore: .gitignore 수정

* build: test profile을 test로 변경

* test: config 설정 수정

* build: build.yml의 Publish Unit Test Results에 토큰 추가

* build: test-results files 경로 수정

* build: github actions permissions를 write 권한으로 변경

* build: build.yml에 issues: write 권한 추가

* refactor: User 명칭을 Member로 변경

---------

Co-authored-by: MingyeomKim <[email protected]>

* [Feature/#6] 공통 응답 추가 및 상위 목표 단건 조회 기능 구현 (#9)

* feat: 상위 목표 d-day 기능 구현, 테스트 작성 (#6)

- 상위 목표 종료 일자 필수 입력으로 확정 후, d-day 계산 로직 plan 엔티티내 생성 후 테스트
- planService에 상위 목표 단건 조회 로직 추가

* feat: 공통 응답 스펙 추가

* feat: 상위 목표 삭제 기능 추가

- Service에 삭제 기능 추가, 차후 테스트 필요
- 상위 목표 생성 Controller DTO 추가

* chore: application.yml 수정

* test: CI 테스트

* refactor: controller내 pathVariable 제거

* chore: build.yml을 테스트 환경에서 동작하도록 수정

* refactor: 소셜 로그인 시 input을 userId로 맞추어 수정 (#11) (#12)

Co-authored-by: MingyeomKim <[email protected]>

* [Feature/#13] TokenProvider 클래스 생성 및 Refresh Token 반환 (#14)

* feat: Refresh token을 생성하도록 TokenProvider 클래스 추가

* test: TokenProvider 단위 테스트 생성

* test: TokenProviderTest 오류 수정

---------

Co-authored-by: MingyeomKim <[email protected]>

* [Feature/#10] 상위 목표 리스트 조회 기능 구현 (#15)

* feat: 상위 목표 d-day 기능 구현, 테스트 작성 (#6)

- 상위 목표 종료 일자 필수 입력으로 확정 후, d-day 계산 로직 plan 엔티티내 생성 후 테스트
- planService에 상위 목표 단건 조회 로직 추가

* chore: git 캐시 초기화

* feat: 상위 목표 생성, 수정 기능 구현 (#10)

* refactor: 상위 목표 도메인 명을 Plan에서 Goal로 변경

- Goal이라는 단어가 목표라는 의미를 더 잘 표현하는 것 같아서 변경하게 되었습니다

* refactor: 공통 응답 스펙명 CustomResponse로 변경

- Swagger에 있는 ApiResponse와 네이밍이 같아서 패키지 명 전체를 명시해야 함. 따라서 customResponse로 명칭 변경함

* feat: 공통 예외 스펙 추가

- 공통 예외 스펙과 exceptionHandler 추가

* chore: QueryDSL 세팅

* feat: 상위 목표 페이징 조회 기능 개발

- 커서 기반 페이지네이션을 사용
- Service 통합 테스트 후 Controller 개발 예정

* test: 상위 목표 페이징 조회 기능 테스트

- 테스트 데이터간 독립성을 위해 databaseCleaner 추가

* test: 페이징 기능 응답 스펙 변경

- 기존의 Slice의 반환 형식이 no offset 기반 페이징에서는 불필요하다고 판단되어 필요한 데이터만 파싱 처리함

* refactor: 상위 목표 통계 기능 삭제 및 테스트 수정

* feat: 상위 목표 상태별 개수 조회 기능 추가

- 기능 추가 및 테스트 진행 완료

* feat: 상위 목표 리스트에 dDay 컬럼 추가

- Swagger 어노테이션 수정

* feat: ErrorCode에 상위 목표 예외 추가

* test: GoalStatus 변경

* refactor: CustomResponse 오타 수정

* refactor: Swagger ApiResponse 제거

ApiResponse로 응답값을 제대로 표현할 수 없다고 판단되어 우선은 배제하기로 결정

* refactor: GlobalExceptionHandler 수정

* refactor: 클래스 내 빈공간 제거

* refactor: Tag와 Operation 재배치

* [Feature/#17] refresh token 발급 시 Redis에 저장하도록 설정 (#18)

* feat: Redis 저장소 추가 및 세팅 (#17)

* docs: @parameter 어노테이션으로  OAuthController 파라미터 설명 추가

* refactor: 소문자 provider를 대문자로 변경하는 함수 작성

* feat: OAuthController에 issue 메서드 추가 (#17)

* refactor: socialId를 uid로, socialType을 provider로 명칭 변경

socialId가 사실상 사용자 식별 필드로 사용된다. 그러나 문자열인 socialId를 PK로 두는 것은 한계가 있기 때문에 uid로 명칭을 변경한다. 또한, Provider와 SocialType 명칭도 겹치기 때문에 provider라는 단어로 통일한다

* feat: RefreshToken, RefreshTokenRepository 작성 (#17)

* feat: 액세스 토큰 만료 시 재발급 요청하는 reissue 서비스 코드 작성 (#17)

* feat: 로그인 시 refresh token을 redis에 저장하는 기능 추가 (#17)

* refactor: Auth 비즈니스 로직 Exception 처리

* feat: Redis 설정 수정

* refactor: login 호출 시 잘못된 provider가 입력되는 경우 예외처리

* test: reissue, login fail 테스트 케이스 추가 (#17)

* refactor: CustomResponse를 사용하여 Controller 반환

* feat: @Valid 어노테이션 추가

* ci: 배포 시 테스트되지 않도록 deploy.yml 수정

* build: build.yml에 Redis 설정 추가

* build: redis port 입력 방식 수정

* refactor: 풀 리퀘스트 리뷰 반영

---------

Co-authored-by: MingyeomKim <[email protected]>

* [Feature/#16] 하위 목표 기능 구현 (#20)

* feat: 상위 목표 d-day 기능 구현, 테스트 작성 (#6)

- 상위 목표 종료 일자 필수 입력으로 확정 후, d-day 계산 로직 plan 엔티티내 생성 후 테스트
- planService에 상위 목표 단건 조회 로직 추가

* feat: detail_goal 엔티티 설계 (#16)

* feat: detailGoal 엔티티 설계 (#16)

* feat: detailGoal 전체 조회 기능 구현 (#16)

* feat: detailGoal 전체 조회 Controller 구현

* feat: detailGoal 저장 기능 구현 (#16)

* refactor: 에러 코드 수정

- Goal 에러 코드 수정
- Detail Goal 에러 코드 추가

* feat: detail goal 상세 조회 응답값 변경 (#16)

- 요일 정보를 EnumSet으로 관리하는걸 생각했으나 엔티티에는 적용이 되지 않아 List로 관리하기로 결정

* refactor: detail goal 요청 시 요일 정보 string으로 변경

* feat: detail goal 추가 시 goal 내부 카운트 증가 로직 추가 (#16)

* feat: detail goal 수정, 삭제 기능 추가 (#16)

* feat: detail goal 달성, 달성 해제 기능 구현 (#16)

* test: detail goal 서비스 테스트 작성 (#16)

* refactor: application-prod.yml 임시 파일 삭제

* feat: detail goal, goal 조회 쿼리에 isDeleted 판별 조건 추가 (#16)

기본적으로 soft delete를 사용하기 때문에 isDeleted에 대한 판별 조건을 포함해야 한다

* feat: goal 삭제 시 연관 detail goal 삭제 로직 추가 (#16)

* feat: 전체 detail goal과 달성 detail goal 계산 및 조회 로직 추가 (#16)

* [Feature/#21] 보관함 복구 기능, 회고 개수 조회 기능 구현 (#22)

* feat: 상위 목표 d-day 기능 구현, 테스트 작성 (#6)

- 상위 목표 종료 일자 필수 입력으로 확정 후, d-day 계산 로직 plan 엔티티내 생성 후 테스트
- planService에 상위 목표 단건 조회 로직 추가

* 간격 수정

* feat: 상위 목표 복구 기능 구현 (#21)

* refactor: transactional 어노테이션 추가

* feat: LocalTime 요청 응답 값 오전/오후 반영하도록 변경 (#21)

* feat: 상위 목표 제약 조건 수정 (#21)

- 현재 보다 이전 날짜를 시작일로 선택 불가능하다는 조건이 없기에 조건 제거
- 보관함에서 복구 시 시작, 종료 날짜를 초기화 예정이기에 nullable을 true로 변경

* feat: 상위 목표 복구 기능 수정 (#21)

- 복구 시 새로운 데이터로 초기화해야 복구가 완료 되도록 설정

* feat: 회고 작성 가능한 완료 목표 개수 조회 (#21)

* feat: goal 생성시, goalstatus 생성자 주입으로 변경

- goalstatus 값을 변경해서 테스트 해야 할 경우들이 있다고 판단되어, 테스트 코드 편의성과 changeGoalStatus라는 setter 메서드를 제거하기 위해 작업을 진행함

* test: 테스트 작성 완료

* refactor: GoalController내 위치 변경

* application.yml 제거

* refactor: goalController 공통 URI 통일

* [Feature/#23] 하위 목표 모두 성공시 보상 제공 및 팝업 기능 구현 (#25)

* feat: 상위 목표 d-day 기능 구현, 테스트 작성 (#6)

- 상위 목표 종료 일자 필수 입력으로 확정 후, d-day 계산 로직 plan 엔티티내 생성 후 테스트
- planService에 상위 목표 단건 조회 로직 추가

* 간격 수정

* feat: 보상 제공 기능 구현 (#23)

* feat: 상위 목표 달성 시 팝업 기능 구현 (#23)

- 랜덤으로 보석 지급 기능 구현
- 상위 목표 리스트 조회 시 보석 enum도 조회 추가
- 보석 지급과 함께 complete 상태의 상위 목표 개수 조회

* test: 상위 목표 성공 시 기능 테스트 작성 (#23)

* refactor: 상위 목표 개수 반환값 및 주석 수정

* [Feature/#24] 채움함 내 상위 목표의 종료 기간 경과 시 보관함으로 이동하는 스케쥴러 구현 (#26)

* feat: 상위 목표 d-day 기능 구현, 테스트 작성 (#6)

- 상위 목표 종료 일자 필수 입력으로 확정 후, d-day 계산 로직 plan 엔티티내 생성 후 테스트
- planService에 상위 목표 단건 조회 로직 추가

* 간격 수정

* feat: 0시 0분에 호출되는 스케쥴러 구현 (#24)

* .gitignore 초기화

* test: 스케쥴러 테스트 작성

* test: 스케쥴러 테스트 작성 (#24)

* feat: cron 수정 (#24)

* Cicd test (#27)

* feat: 상위 목표 d-day 기능 구현, 테스트 작성 (#6)

- 상위 목표 종료 일자 필수 입력으로 확정 후, d-day 계산 로직 plan 엔티티내 생성 후 테스트
- planService에 상위 목표 단건 조회 로직 추가

* 간격 수정

* 서브 모듈 수정

* ci: redis container 설정 추가

* ci: SuperCharge의 Redis Server를 사용하도록 수정

* ci : build시 submodule을 가져오도록 설정

* ci: deploy 대상을 dev 브랜치로만 변경

* ci: deploy.yml의 submodule를 recursive로 설정

* ci: submodule 업데이트

* ci: dev profile로 빌드하도록 수정 및 submodule update 구문 추가

* [Feature/#19] 로그아웃, 회원 탈퇴 구현 및 Custom Filter 생성 후 Spring Security 적용 (#29)

* feat: 로그아웃 기능 추가 (#19)

* feat: Redis에 블랙 리스트 기능 추가 (#19)

* refactor: BlackList 도메인에서 status 제외

* feat: 회원 탈퇴 기능 구현 (#19)

* feat: reissue 시 refresh token도 새로 발급하도록 수정

* feat: Security Config 생성 및 OAuthController URI 통일

* feat: JwtFilter 구현 및 TokenProvider의 getAuthentication 작성

* feat: 인증, 인가 로직 실패 시 Exception Handler 작성

* feat: Q클래스 생성

* chore: SecurityConfig 작성

* feat: SecurityConfig 설정 추가

* test: TokenProviderTest의 멤버 호출 구문 Mocking

* ci: build.yml, deploy.yml에서 submodule 자동 업데이트하도록 수정

* refactor: 토큰 유효성 검사 중복 제거

* feat: 회원 탈퇴 시 블랙 리스트에 추가

* feat: jwtFilter에서 블랙리스트 조회하는 로직 추가

* refactor: OAuthController의 함수 명칭을 일관되게 변경

* build: 라이브러리 꼬임 해결

* ci: java 실행 시 sudo 권한 추가

* docs: swagger cors에러 수정

* chore: 모든 URL 접근 가능하도록 설정

* refactor: jwtFilter에서 예외 던지지 않도록 수정

* chore: 모든 경로 접근 허용

* chore: 모든 경로 접근 허용

* refactor: JwtFilter에서 모든 Exception을 제외

* refactor: CORS 에러 해결

* chore: swagger에 authorization 인증 받을 수 있도록 수정

* chore: SwaggerConfig 수정

* build: run_new_was.sh 스크립트 들여쓰기 수정

* chore: run_new_was.sh가 동작 확인을 위한 로그 출력

* build: run_new_was.sh 에서 구동할 포트를 죽이는 명령어 수정

* feat: 회원 탈퇴 컨트롤러 URL추가

* [Feature/#31] 유저 로그인 시 fcm token을 저장하는 로직 구현 (#32)

* feat: 로그인 시 fcm token을 함께 전달받도록 수정

* feat: Fcm Token 저장 및 조회 로직 추가

* [Feature/#28] 알림 요일과 시간에 따라 FCM 알림을 전송하는 기능 구현 (#35)

* feat: 상위 목표 d-day 기능 구현, 테스트 작성 (#6)

- 상위 목표 종료 일자 필수 입력으로 확정 후, d-day 계산 로직 plan 엔티티내 생성 후 테스트
- planService에 상위 목표 단건 조회 로직 추가

* 간격 수정

* 최신 사항 머지

* git cache 초기화

* feat: 푸시 알람 스케쥴러 구현 (#28)

- 매일 30분 간격으로 작동하는 스케쥴러 구현
- FCM 서비스를 호출하는 event 구현

* feat: 요일, 시간별 알림 전송 스케쥴러 구현 (#28)

* test: detailGoalQueryRepository 테스트 추가 (#28)

* refactor: 공통 응답 스펙 수정

* docs: swagger 문서 수정

* docs: 코드,메세지 설명 추가

* feat: 응답 Response에 Schema 추가 (#36)

* chore: 토큰의 만료시간 임의 변경

* locale (#39)

* fix: locale 수정

* JsonFormat pattern 변경 (#41)

* fix: localtime 형식 변경

* [Feature/#37] 회고 도메인 생성 및 저장, 조회 로직 구현 (#42)

* refactor: fcmToken 조회 로직 수정, logout, withdraw에 추가

* feat: 회고 도메인 생성 (#37)

* feat: 회고 도메인의 Repository 생성

* feat: 회고 저장 및 조회 로직 구현 (#37)

* feat: 회고의 내용을 담는 RetroSpectContent 분리 (#37)

* test: 회고 저장 및 조회 서비스 로직 테스트

* feat: 회고 저장 및 조회 컨트롤러 구현 (#37)

* refactor: 의존성 관련 오류 수정

* [Refactor/#37] 회고 기능 관련 리팩토링 (#44)

* LocalDate JSON 응답 형식 변경 (#45)

* refactor: GoalController LocalTime 형식 변경

* chore: JPA의 ddl-auto를 create로 설정

* build: 빌드 시 워크플로우에서 secrets 불러오는 것 제외

* feat: Retrospect Response에 hasGuide 컬럼 추가

* build: build.yml 워크플로우에서 서브모듈 로직 제외

* refactor: contents의 @column 삭제

* chore: run_new_was.sh의 내용 일부 수정

* chore: config의 application-dev.yml 수정

* refactor: Retrospect와 Content를 양방향 매핑으로 변경

* refactor: retrospect content가 retrospect를 가져오지 못하는 부분 수정

* chore: ddl-auto를 create로 변경

* [Feature/#38] FCM 푸시 알림 기능 연동 후 하위 목표 알림 스케쥴러와 연결한다 (#46)

* feat: FCM 알림 설정 및 연동 (#38)

* refactor: GoalController LocalTime 형식 변경

* feat: FCM 알림 스케쥴링 기능 복구

* refactor: 테스트 수정 및 도메인 디렉토리 구조 변경

* refactor: DetailGoal 수정 시 locale 정보 변경

* submodule내 FCM 설정 파일 경로 수정 (#50)

* fix: submodule에 fcm_key.json 경로 수정

* 하위 목표 시간 locale 응답 ko로 수정 (#51)

* refactor: 하위 목표 응답 시간 locale ko로 수정

* 상위 목표 개수 카운트 쿼리 수정 (#52)

- 삭제 여부 판단 로직을 쿼리의 having 부분에서 where 절로 옮김

* [Refactor/#47] 사용자 인증 필터에서 발생하는 예외 핸들러 필터 구현 (#49)

* feat: 예외를 발생시키는 JwtExceptionFilter 클래스 생성

* refactor: TokenProvider의 validateToken이 JwtException을 반환하도록 수정

* refactor: 따로 처리가 필요한 인증 예외 클래스를 생성하고, Token 검증 오류 시 Throw한다.

* feat: 블랙 리스트 Exception 클래스 생성, Authentication 필터 수정

* feat: 필터의 오류 핸들링 필터를 추가 (#47)

* feat: 인증 필터를 핸들링하는 필터 작성 (#47)

추가로 궁금한 점 :

(1) 토큰 만료 시 = reissue 요청
(2) 토큰이 없는 경우 = 로그인 요청
(3) 토큰이 잘못된 경우 = 올바르지 않다는 메시지 반환

이런 식으로 구현할려고 했는데, ErrorCode가 달라지는 것 말고는 별 다른 처리할 것이 없다고 생각해서 setErrorResponse 메소드 하나로 통일하여 예외를 처리하였다. 이렇게 획일화하고 나니 그냥 JwtException 하나로만 서로 다른 ErrorCode를 넣어서 구현해도 같은 결과를 가져올 것 같아서, Exception 클래스의 분리의 필요성을 못느꼈다.

* refactor: jwt 토큰의 유효성 검증은 따로 Exception 처리 제외

* chore: config 수정 사항 반영

* 상위 목표 수정 기능 Service 파라미터 수정 및 Security Config 변경 (#53)

* refactor: 상위 목표 수정 컨트롤러에서 Path Variable 사용하도록 변경

* refactor: SecurityConfig 설정 변경

* 기존에 전체 허용으로 열려있던 URL 경로 권한을 인증 URL로 제한

* Spring Security내 permitAll 동작할 수 있도록 JwtFilter 수정 (#54)

* refactor: permitAll한 url은 token 예외가 발생하지 않도록 처리

* GoalResponse @jsonformat 수정 (#55)

* refactor: GoalResponse의 JsonFormat 수정

* JWT 유효기간 수정 (#56)

* refactor: JWT 만료 시간 수정

* 하위 목표 수정 문제 해결 및 상위 목표 페이징 커서 수정 (#57)

* refactor: 페이징 커서 null에서 -1일때 전체 조회하도록 수정

* 회고 작성 시 보관함 내 목표 리마인드 기능 추가 (#58)

* feat: 보관함 목표 리마인드 기능 개발

* 상위 목표 리스트 조회 시 리마인드 여부 컬럼 추가 (#59)

* refactor: 상위 목표 리스트 반환 시 reminder 여부 컬럼 추가

* 보관함에 있는 목표 조회 시 d-day 0으로 계산 (#60)

* 보관함에 있는 목표 d-day 계산 시 0 반환하도록 변경

* 보관함에 있는 목표 조회 시 d-day 값을 음수로 반환 (#61)

* 보관함에 있는 목표 조회 시 d-day 값을 음수로 반환

* feat: 토큰 재발급 시, 재발급된 refresh token을 redis에 저장

* refactor: SecurityConfig 에서 exception Handling 제외

* refactor: reissue 시 refresh token을 조회할 수 없는 부분 수정

* hotfix: import 시 오타 수정

* refactor: /auth 경로를 Authentication Filter를 거치지 않도록 설정

* hotfix: URI와 Request Method 확인을 위한 로깅 처리

* refactor: 허용한 URL 이외의 요청에 인증을 거치도록 설정

* feat: 상위 목표, 세부 목표 API JWT 인증 거치도록 설정

* feat: 최초 로그인 시 관련 정보를 함께 Response에 전달

* 인증 유저 정보를 사용해서 사용자 상위 목표를 식별한다 (#62)

- @AuthenticationPrincipal을 통해 인증 유저 식별자 가져옴

* refactor: 재로그인 시 refresh, fcm token 삭제하는 코드 제거

* refactor: 애플리케이션 실행 시 Asia/Seoul Timezone 설정

* test: 토큰 테스트를 위해 유효 기간을 짧게 설정

* refactor: 저장되지 않은 토큰 입력 시 401 에러 반환하도록 수정

* refactor: 토큰의 유효시간 정상화

* test: 토큰 유효시간 짧게 설정

* refactor: 리프레시 토큰 유효기간 정상화

* test: reissue 테스트를 위한 로그 추가

* refactor: refresh Token 객체 timeToLive설정

* refactor: @column에 unique=true를 추가하여 해결 (#65)

* refactor: 토큰 유효시간 정상화

* 목표 달성 후 보상 지급 시, 로그인한 사용자의 달성 목표만 카운트 하도록 설정한다 (#66)

* refactor: 보상 지급 시 달성 목표 카운트 수정

* feat: 토큰 관리 API 추가 (#68)

Co-authored-by: MingyeomKim <[email protected]>

---------

Co-authored-by: Seo Jemin <[email protected]>
Co-authored-by: MingyeomKim <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants