Giter VIP home page Giter VIP logo

jmt-monster-backend's Introduction

맛집 몬스터 백엔드

프론트엔드 | 백엔드

친구끼리 공유하는 수집형 맛집 어플리케이션 "맛집 몬스터"!

사용자끼리 친구를 만들고, 친구 지도로 놀러가서 리뷰를 남기는 프라이빗 맛집 공유 어플리케이션입니다.

⚙️ 기술 문서

🌎 Production Server

배포 서버 바로가기

🖼️ Sample Screen

개발 후 스크린샷 TODO

🏢 System Architecture

Untitled

🔧 Tech stack

  • Java 17
  • Gradle 7.4.1
  • Spring Boot 2.6.6
  • Spring Security + OAuth 2.0
  • Spring Data JPA
  • Querydsl 5.0.0
  • MySQL 8
  • Lombok
  • Jackson
  • JUnit 5, Mockito, Hamcrest
  • Spring REST Docs

👨‍👨‍👧‍👦 Members


이름 개발분야 Github
이승준 FE, BE, DevOps litsynp
이지호 FE, BE, DevOps DPS0340
용길한 BE Yong-ga-ri
권종석 BE himJJong
최우석 BE Sith-call

jmt-monster-backend's People

Contributors

dps0340 avatar himjjong avatar litsynp avatar sith-call avatar yong-ga-ri avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

jmt-monster-backend's Issues

이용 가능한 장소 API 작성

구현 세부사항

  • 현재 이용 가능한 지역을 광역시, 도 기준으로 GET
  • 현재 이용 가능한 지역을 시, 구 기준으로 GET
  • 이용하지 않던 구역을 이용 가능하게 구역 POST (PUT?)

자세한 것은 기획 문서 따라서..

이사 API 작성

행정구역 Fetch API (#63) 대체용

  • 현재 모든 행정구역 데이터를 WAS에서 바로 가져오기에는 무리가 있음 (네트워크를 타고 20MB 정도)
  • 네트워크 최적화를 위해 WAS에서 on startup 메소드로 데이터를 가공하기에는 필드 변수가 너무 많아 구현 난이도가 있어 프론트에서 작업하는 것이 효율적이라고 판단됨
  • 이사 API 하나만 만든다 + 조회만 만든다
    • 이사하면 본인의 행정구역이 생김 (행정구역 테이블이 생김)
      • 행정구역 테이블 - 풀네임, 코드 (풀네임: 서울시 강남구 삼성동, 코드는 행정구역 코드)
      • 렌더링(maps.ts) 하지 않거나, 현재 조회 가능한 지도만 렌더링
    • 조회정보를 알려줄 테이블이 생김
    • 마지막에 이사를 온 행정구역은 거주하고 있는 상태

API Resource Authorization 구현

API를 접근할 때 (로그인한) 사용자가 해당 자원에 대한 권한이 있는지 ID 또는 복합 조건을 비교해서 확인해야 한다.

Best practice에 대한 방법 조사 필요.

/users/me API 작성

  • 토큰 인증과 연동되어 사용자 자신의 정보를 얻을 수 있게

API Documentation 라이브러리 선정

API Spec 명시해주는 라이브러리 후보로는 두 개정도 있음.

차이점 비교

Spring REST Docs는 실제 WAS에 통합 테스트를 실행해서 스펙에 맞춰 WAS의 동작을 보장할 수 있음.
OpenAPI 3.0은 Controller 코드에 명세를 선언해서 추가하는 방식에 가까움.

테스트를 많이 짠다면 Spring REST Docs가 조금 더 선호될 것 같고, 그렇지 않다면 OpenAPI 3.0을 선택하는게 맞는 선택일 듯 함.

Jackson - LocalDateTime 매핑 오류

image

  • request를 보내면 LocalDateTime을 Jackson이 매핑을 못하고 있는 이슈 존재
  • 현재 HelloController, ErrorResponse에 LocalDateTime이 들어감
  • 정상적으로 response를 받지 못하고 있음

Entity 생성 후 저장시 저장 전과 후의 ID(기본키) 값이 다른 이슈

ISSUE

Entity 생성 후 저장시 저장 전과 후의 ID(기본키) 값이 다른 이슈가 존재한다.

CAUSE

현재 프로젝트 내 모든 Entity는 @Builder.Default를 이용해 UUID.randomUUID()로 UUID 값을 생성해 주입되는 방식으로 작성되었다.

@Id
@GeneratedValue(generator = "uuid2")
@GenericGenerator(name = "uuid2", strategy = "uuid2")
@Column(columnDefinition = "BINARY(16)")
@Builder.Default
private UUID id = UUID.randomUUID();

다음과 같은 두 개의 테스트 코드를 실행해보면,

@Autowired
private UserRepository userRepository;

/** ID 주입하지 않고 기본 값으로 생성한 것을 DB에 실제 저장된 것과 비교 */
@Test
void testUUID_idNotInserted() {
    User user = User.builder()
            .name("Test")
            .nickname("Test")
            .email("[email protected]")
            .build();

    // Entity 코드에서 private UUID id = UUID.randomUUID(); 에서 생성
    UUID expectedId = user.getId();

    // DB에 저장
    user = userRepository.save(user);

    // DB와 비교
    assertThat(user.getId()).isEqualTo(expectedId);
}

/** ID를 직접 생성해서 주입하고, 해당 ID를 DB에 실제 저장된 것과 비교 */
@Test
void testUUID2_idInserted() {
    // 수동으로 ID 생성
    UUID expectedId = UUID.randomUUID();

    User user = User.builder()
            .id(expectedId)
            .name("Test2")
            .nickname("Test2")
            .email("[email protected]")
            .build();

    // DB에 저장
    user = userRepository.save(user);

    // DB와 비교
    assertThat(user.getId()).isEqualTo(expectedId);
}

둘 다 다음과 같은 결과가 나온다.

image

즉, 수동으로 ID를 주입하든 주입하지 않든, DB에 저장되기 전과 후의 ID 값이 달라진다.

이는 예상하지 못한 방향으로 흘러갈 수 있어 (테스트 코드 작성에도 혼동이 올 수 있음) 가능하다면 수정해서 되도록 하고, 안된다면 기본 키값 생성 비활성화가 필요할 것으로 보인다.

사용자 집주소 변경 및 사용자 행정구역 다대다 연결 관련 메소드 / 서비스 호출

ABOUT

한마디로 말해서, 이사 기능 구현이라고 할 수 있다. 사용자가 집 주소를 변경하면, 행정 구역 조회 API에서도 isAvailable, isReadOnly (가칭) 등의 필드에도 반영이 되어 접근이 가능한 행정구역인지, 리뷰를 남길 수 있는 지역인지를 확인할 수 있도록 변경사항이 같이 조회되도록 한다.

구현 사항

2022.05.28 주간 회의 정리 내용에 따라서, 사용자 수정 API (POST/PUT)인 Extra Info API에 추가 작업하면 될 것으로 보인다.

로직 구현

  1. 사용자가 이사 를 하면, Extra Info API를 통해 사용자 집 주소 수정
  2. 이사 관련 Service 메소드 호출

DB 관련

  • 사용자 (User) - 행정구역 (가칭 AdministrativeDistrict) Entity에 대해서 다대다 (ManyToMany) 연결 관계 Table 필요
  • 요구사항
    • 거주를 한 적이 있다면 거주한 적 없던 지역과 구분할 수 있어야 한다. (isAvailable 등 적절한 필드 네이밍)
    • 과거에 거주를 했던 지역과 현재 거주하는 지역을 구분할 수 있어야 한다. (isReadOnly, isWritable 등 적절한 필드 네이밍)

주의사항

다대다 연관 관계는 @ManyToMany 가 아니라 관계 테이블을 따로 만들어서 구현하는 경우가 많으니 참고 바람

행정구역 데이터 Fetch API 구현

ABOUT

기존에 정적 데이터로 프론트엔드에서 관리하고 있던 행정구역 JSON 데이터를 프론트엔드가 아닌 백엔드에서 조회할 수 있도록 API를 제공하도록 한다.

구현 사항

  • 행정 구역 DTO (Class) 구현
  • 행정 구역 정보를 Entity로 구성해 DB 관리
  • Spring Batch 등 활용하여 초기 값 init
  • GET API로 행정 정보 반환 (필요에 따라 caching 적용 with Redis)
  • 주어진/로그인한 사용자를 확인하여, 각 행정 구역에 대하여 해당 지역에 거주한 적이 있는지 (행정 구역을 조회할 수 있는지), 리뷰를 남길 수 있는지 (현재 그 지역에 살고있는지) 를 같이 반환할 것
    • 해당 과정에서 사용자 - 행정 구역 다대다 관계 매핑 필요할 것으로 보임

추가 사항

  • 로그인한 사용자를 확인해서 (또는 RequestParam으로 필터링해서) 실제로 이 행정 구역이 이용 가능한지 값 (isAvailable)이 같이 받아와야 함
    • 필터링할 경우 로그인한 사용자가 해당 사용자가 맞는지 자원에 대한 권한 확인 필요. 권한 없으면 403 Forbidden 등 에러 코드 반환
      isAvailable, isReadOnly (가칭) 등 네이밍 필요.

See Also

#64

테스트 코드 작성 간 is 접두사 오류

Web 레이어 슬라이스 테스트 진행 간에 is 접두사 관련 오류 발생하는 것을 확인.

@Import 부분에 JacksonConfig.class, JacksonModuleConfig.class를 추가하지 않으면 DTO에서 is 접두사 문제가 발생하고,

image

@Import 부분에 JacksonConfig.class, JacksonModuleConfig.class를 추가하면 Page 관련에서 is 접두사 문제가 발생한다.

image

Related: #36

Exception Handler 구현

직접 Exception Handler를 구현해야 상황에 맞는 Exception을 던졌을 때 알맞은 에러코드, HTTP Status, message 등을 받을 수 있어서 구현 필요.

PersistentToken 인증 로직을 Filter로 이관

문제 정의

현재 개발 조직의 Spring Security 이해도가 낮아 서비스 메소드와 Interceptor로 인증을 구현한 상태이다.
인증을 위해서는 Controller에서 UserService를 DI 받고, 예외처리까지 구현해야 해서 컨트롤러 코드가 자신의 도메인에 있는 서비스의 비즈니스 로직에 집중하지 못하게 된다.

해결 방법

Spring Security를 사용해서 Filter로 사용자를 인증하고, AuthorizationContext로 사용자 객체를 가져오는 것을 구현하고 Util 클래스로 메소드화한다.

이사 API 테스트 코드 작성

문제 정의

이사 API에 대한 테스트 코드가 없고, 전체적으로 테스트가 이루어지지 않은 상태이며 Swagger 정의도 이루어지지 않았다.

해결 방법

이사 API를 JUnit 5, Mockito, Spring Rest Docs 기반으로 테스트하는 코드를 작성한다.

Jackson에 의해 boolean isXXX 값이 is가 제거되어 나오는 이슈

Issue

  • Jackson에 의해 isSomething 필드가 자동으로 is가 떼어져서 something으로 나오는 것 확인.
  • isHangingOut으로 의도하고 만든 필드인데 is가 없어지는 것은 의도하지 않았으므로 issue로 게재

How to Reproduce

친구 요청 생성 -> 친구 요청 수락 -> 친구 조회 시 isHangingOuthangingOut으로 변경되는 것으로 확인

image

테스트 코드 실행 간 java.lang.IllegalArgumentException: JPA metamodel must not be empty! 오류

MockMvc를 이용한 슬라이스 테스트 코드 실행 간 java.lang.IllegalArgumentException: JPA metamodel must not be empty! 오류가 발생한다.

@EnableJpaAuditing 을 루트 경로 클래스인 Application.java에서 제거하고 @Configuration으로 빼면 된다.

Mockito를 이용한 Test code에서 슬라이스 테스트를 할 경우 Spring 컨텍스트를 불러오지 않기 때문에 일어나는 것으로 파악된다.

REF

사용자 추가 정보 DB 반영하기

UserService에서 사용자 추가 정보 입력해도 반영 안되는 이슈 존재.

@Transactional.save() 메소드를 이용해 DB에 반영 필요.

SubReview 기능 추가

ABOUT

  • 기존 리뷰 기능에 SubReview 기능을 추가
  • Review 테이블을 조인하는 형식으로 구현할 지, 아예 새롭게 테이블을 설계할지 고민 중
  • 이 기능을 추가한 이후에 테스트 코드 작성할 에정

ReviewRepository의 findByUserId에서 N+1 문제

ABOUT

image
image
image

이미지와 같이 N+1 문제가 발생했다.

  • Review 조회 쿼리 발생 (2개의 엔티티 조회) - 1번 수행
  • 첫 번째 Review의 foodList 조회 / imageList 조회
  • 두 번째 Review의 foodList 조회 / imageList 조회

TODO

~ToMany 관계가 Review 엔티티에 두 개 존재하여 Querydsl의 fetch join이 불가능하다.
참고
따라서 bath_fetch_size 이용하여 해결할 계획이다.

Address Code User Entity에 추가 필요

문제 정의

현재는 지역 이름만 사용자 엔티티에 넣을 수 있고 지역 코드를 넣을 수 없는 상태이다.
특히 이사 API와의 연동이 어려운 상태이다.

문제 해결

1안과 2안이 있다.

  1. 지역 코드를 User 엔티티의 필드로 새로 만들고 extra info 주입 시점에 지역 코드를 같이 입력하게 한다.
  2. 지역 관련 정보를 HomeService에서 완전히 관리하게 한 후, extra info에서 추가적인 지역 관련 정보를 주입하지 않는다. (migrate API 사용)

프론트엔드에서도 이에 따른 수정이 필요한 상태이다.

saveRestaurantInfo 추가 작업 필요

Restaurant 메소드에 대한 추가 작업 필요

  • 임시 작업이 완료되었고 @himJJong 님의 작업과 합쳐 해당 부분을 수정할 계획입니다.

내용

        // Todo: 외부 요청을 통한 결과를 JsonObject로 반환
        // 임시 값 저장
        jsonObject.put("cid", "562795624");
        jsonObject.put("name", "롯데리아 인천공항제2여객터미널3층점");
        jsonObject.put("x_cord", "374960");
        jsonObject.put("y_cord", "1102598");

놀러가기 기능 구현

ABOUT

등록한 친구에게 놀러가기하면 해당 친구가 보유한 행정 구역을 조회할 수 있도록 한다.

흐름도

  • PUT /api/v1/friends/{친구ID} -- 친구 수정 API -- 로 친구에게 놀러가기 신청
    • Request Body
      {
        "isHangingOut": "true"
      }
  • 놀러가기를 신청하면, 신청한 친구에게 신청된 사용자가 가진 행정 구역을 조회할 수 있도록 권한이 부여된다. -- 행정 구역 API 연동 필요
  • 리뷰를 남길 때, 지도의 주인이 남긴 곳에 리뷰를 같이 남길 수 있다. -- 리뷰 API 연동 필요
    • 친구 지도로 가면 친구 지도에 있는 맛집 리뷰를 볼 수 있음
  • 놀러가기는 다른 사용자에게 놀러가기를 신청하면 나머지 사용자에 대해서 놀러가기를 해제한다.

See Also

#63

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.