Project

PROJECT :: brandi internship Review

hooti 2020. 10. 22. 01:30

PROJECT :: brandi internship Review

인턴십 과제 프로젝트, brandi Clone Review

🎬영상 보러가기

 

 기업소개, 인턴십 주제와 팀원, 구현한 기능 

 

 

 

1. 기업소개

🧐 No.1 모바일 패션 커머스 플랫폼 브랜디!

누적 거래액 3,000억을 넘긴 20대 여성을 위한 패션/뷰티 앱 브랜디, 론칭 1년만에 30배 성장한 남성 패션 앱 하이버, 지금까지 아무도 성공하지 못했던 동대문 패션의 글로벌화를 꿈꾸며 쇼핑몰 뮤료창업 서비스 헬피와 동대문 D2C 플랫폼 트랜디까지 지원하는 기업! 남들이 못했던 것들을 도전하며 빠르게 성장하는 스타트업입니다!

 

2.인턴십 과제

패션 커머스 플랫폼 브랜디 스테이징 사이트 클론 프로젝트(서비스, 백오피스)

 

3. 제작팀원

서비스 파트 : Front-End 3명(해당 파트 참여했습니다.) /  Back-End 2명

백오피스파트 : Front-End 2명 /  Back-End 3명

 

4. 개발기간

2020.09.14~2020.10.15

 

5. Github & Trello

Brandi-Team1/Service / brandi-internship-service

 

4. 적용기술

HTML,CSS / JS / Vue(Vue router, Vue Webpack, Vuex) / SASS / Webpack Build

 

5. 구현한 기능 (직접 작업한 내용은 색상을 변경하였습니다)

회원가입 & 로그인: v-if를 활용하여 구글소셜회원가입 & 기본회원가입을 한페이지내에서 구현 / JWT와 Cookies를 이용하여 로그인 기능 구현 / 구글 토큰 발행을 활용하여 소셜로그인 및 회원가입 구현 / Cookies 값을 활용하여 로그인&로그아웃 기능 구현

 

메인: 백엔드 API통신을 통해 필요한 데이터 호출하여 인기상품&특가상품 표출 검색 기능을 통해 원하는 제품 또는 셀러 필터링 기능 구현

 

제품 페이지: 카테고리와 메뉴 상세 페이지 동적 라우팅을 이용하여 연결 / 백엔드 API통신을 통해 필요한 데이터 호출 / 상품갯수에 따른 페이지네이션 기능 구현 / 세일상품 필터링 기능 구현

 

제품 상세 페이지: 제품 이미지 미리보기 슬라이드 구현 / 백엔드 API통신을 통해 필요한 데이터 호출 / 쿠폰발급 기능 구현  / 최대재고에 따라 상품 갯수 증가,감소 기능 구현 / QnA 작성 및 내글만보기 기능 구현 / QnA 페이지네이션 구현  / 주문하기 버튼을 눌렀을 경우,해당 상품의 데이터를 로컬스토리지에 저장

 

주문하기: 선택한 제품을 로컬스토리지에서 불러와 주문하기 화면에 표출 받은 쿠폰을 사용하여 금액차감 기능 구현 / 배송지 추가, 삭제 기능 구현  / 플러그인을 활용하여 도로명주소 검색 기능 구현 / 담긴 상품의 총액 표출 기능 구현  / 주문버튼 클릭 시 백엔드 API통신을 통해 데이터베이스에 상품 구매 기록 등록

 

마이페이지: 주문한 상품의 상태에 따라 환불&취소 버튼 활성화 기능 구현 / 환불하기, 취소하기 기능 구현 / 환불 또는 취소 상태에 따라 구매상태값 변경 기능 구현 / 백엔드 API 통신을 통해 내가 작성한 QnA 글 표출 / 백엔드 API 통신을 통해 받은 쿠폰 표출 

 

 


 코드 리뷰 

 

 

1. 구글 소셜 로그인을 시작해볼까?😎 ( 로그인페이지 )

onSignInSuccess (googleUser) {
      const accessToken = googleUser.getAuthResponse(true).access_token;
      const headers = {
        headers: { 'Authorization': accessToken }
      }
      axios.post(`${config.API}social-signin`, null, headers)
      .then((response) => {
        if(response.data.access_token){
          this.$cookies.set("accesstoken", "response.data.access_token");
          this.$router.push({path: '/'});
        }
      })
      .catch((error) => {
        if (error.response && error.response.status === 401) {
          this.$store.state.googleToken = accessToken;
          this.$store.state.isGoogle = true;
          alert('회원정보가 없습니다. 회원가입을 진행해주세요.');
          this.$router.push({path: '/signup'});
        }
    })
  }

구글 소셜로그인은 vue 플러그인(vue-google-signin-button)을 사용하여 제작하였다. 엑세스 토큰을 헤더에 담아 통신을 하게 되는데 이때, 데이터베이스에 해당 구글 아이디의 이메일 정보가 존재하는지 확인하는 작업을 진행하게 된다. 그 이유는 아이디때문인데, 브랜디에서는 유저의 아이디는 소셜로그인을 진행하는 유저여도 입력하게 설계가 되어있다. 그래서 백엔드분과 상의하여 특정 에러 상태값을 정하고 그 상태값이 왔을경우 회원가입을 진행하기로 계획을 세웠다. Catch를 통해 에러의 값을 확인하고 만약 상태값이 401이라면 회원가입 페이지로 이동하게 로직을 구성하였다.

 

해당 코드에서 중요하게 봐야할 부분은 두가지로, this.$cookies.setthis.$store.state.isGoogle 이다.

 

this.$cookies.set

원래 지금까지 위코드에서 진행했던 클론프로젝트에서 엑세스토큰값은 항상 로컬스토리지에 저장했었다. 하지만 이번엔 인턴십을 나와있는 기업의 클론 프로젝트였기 때문에 기업은 어디에 엑세스토큰값을 담는지를 고민하게 되었다. 로컬스토리지에 담게된다면 유효기간을 설정하지 않았을 시, 보안상의 치명적 문제가 발생하게 된다. 그렇다고 vuex에 담으면 새로고침에 따라 state값이 초기화되기 때문에 이 또한 적절한 방법이 아니다. 팀장님께 자문을 구한 후, cookie를 사용해보는 방법으로 방향성을 정했다. 로컬스토리지보다 유효기간 설정이 쉽고, 보안적으로도 안전하기 때문이였다. vue-cookies 라는 플러그인을 사용하여 로그인이 성공했을때, 엑세스토큰이라는 이름으로 토큰값을 저장한다. 해당 로직에는 보이지 않지만 플러그인 초기설정에서 해당 토큰값은 최대기간을 하루로 설정해두었다. 이로써 안전한 토큰저장이 가능해졌다!👍

 

 

this.$store.state.isGoogle

브랜디에선 회원가입 페이지가 구글 소셜인지, 일반 회원가입인지 두가지에 따라 나타나는 입력창이 다른데 그 입력창의 보여주는 상태값을 v-if로 조절하기 위해 vuex를 이용하여 해당값을 전역 state에 저장하여 관리했다. 만약 구글소셜회원가입이라면 해당값이 true로 입력되어 입력폼의 상태값이 변환되고 소셜회원가입에 필요한 아이디값만 입력할 수 있게 된다. 이부분은 조금 더 효율적인 방법이 있었지 않을까 싶은 방법이지만 그래도 나름대로 상황에 맞춰 잘 짰다고도 생각한다.😊✌️

 

 

 

 

2. 뿌듯했던 네비게이션 가드와 라우터 칠드런! ( 라우팅 )

{
      path: "/mypage",
      component: Mypage,
      beforeEnter: function (to, from, next) {
        if (window.$cookies.isKey("accesstoken")) {
          next();
        } else {
          alert("로그인 후 이용해주세요.");
          next("/login");
        }
      },
      children: [
        {
          path: "",
          component: OrderInquiry,
        },
        {
          path: "coupon",
          component: Coupon,
        },
        {
          path: "qna",
          component: QnA,
        },
       ]
  }

로그인을 하지 않은 상태에서 마이페이지와 장바구니에 접근할 경우, 접근을 막기 위해 vue에서 지원하는 네비게이션 가드를 사용했다. 새삼 느끼는것이지만 vue는 정말 지원하는 기능이 많다! 해당 경로로 라우팅해서 컴포넌트가 그려지기 전 체크를 할 수 있는 훅인 beforeEnter를 사용한다. 만약 쿠키의 값에 엑세스토큰이 존재한다면 다음으로 넘어가고, 그렇지 않다면 경고창을 띄운 후 로그인창으로 넘어가도록 로직을 짜봤다. 처음 사용하는 기능인데도 만족스럽게 잘 나왔다!

 

또 라우터를 공부하다가 알게 된 사실인데, vue에서는 라우터에 children이라는 기능이 있어, 해당 라우터의 중첩된 라우팅을 지원해준다. 처음에는 path 주소를 하나 하나 작성하였다가 이부분을 깨닫고 전부 children으로 수정하게 되었다. 라우터에도 순서가 생겨 더 안정적인 서비스 지원이 가능해졌다!😎

 

 

 

 

 

3. 주문한 상품을 환불 & 취소 해보자! ( 마이페이지 )

마이페이지 > 주문/배송내역 을 확인하면 내가 구매한 상품이 뜨며, 해당 상품이 어떻게 진행되고 있는지에 대한 상태값이 뜨게된다. 상태값이 결제완료, 상품준비중일때는 주문취소가 가능하고, 배송준비, 배송중일때는 환불하기가 가능하다. 해당 상태값에 따라 보여지는 버튼이 다르도록 v-if를 사용하였고, 만약 버튼을 누르게 된다면 아래의 로직이 실행된다.

- 마이페이지 > 환불 또는 취소하기 버튼을 눌렀을 시

refundBtn(){
      if (confirm('선택하신 주문을 환불하시겠습니까?')) {
        localStorage.setItem('refundData', JSON.stringify(this.propsdata));
        localStorage.setItem('date', JSON.stringify(this.date));
        this.$router.push({path: '/mypage/refund'});
      }
    },
    cancelBtn(){
      if (confirm('선택하신 주문을 취소하시겠습니까?')) {
        localStorage.setItem('cancelData', JSON.stringify(this.propsdata));
        localStorage.setItem('date', JSON.stringify(this.date));
        this.$router.push({path: '/mypage/cancel'});
      }
    },

 

정말 아쉽게도, 백엔드분의 노력에도 불구하고 시간이 모자라 눌려진 상품을 데이터베이스에 전달하는 API 로직이 구현되지 못했다.😭그래서 로컬스토리지를 이용하기로 방향을 변경하였다. 버튼을 눌렀을 경우, 선택창이 뜨게 되고 만약 yes를 누르게 된다면 로컬스토리지에 필요한 데이터들을 json으로 변환하여 담은 후, 환불 또는 취소페이지로 이동하게 된다. 로컬스토리지에 json으로 변환하지 않는다면 값이 담기지 않는다!

- 환불하기 페이지 > 환불하기 버튼을 눌렀을 시

refundBtn(){
      if(this.selected == 0){
        alert('환불사유를 선택해주세요.');
      }else{
        let confirmResult = confirm('해당 상품을 환불요청하시겠습니까?');
        if(confirmResult){
          this.$store.state.resultSelected = this.selected;
          this.$store.state.resultTotal = this.refundData.final_price;
          axios({
            url: `${config.API}refund`,
            method: 'PUT',
            data: {
              order_detail_number: this.refundData.order_detail_number,
              order_refund_reason_id: this.selected,
              order_refund_reason_description: this.reason,
              order_detail_id: this.refundData.order_detail_id
            },
            headers: { 
                'Authorization': this.$cookies.get('accesstoken')
            }
            })
            .then((response) => {
              localStorage.removeItem("refundData");
              this.$router.push({path: '/mypage/refund/result'});
            })
            .catch((error) => {
              console.log(error.response);
          })
        }
      }
    }

환불 또는 취소페이지로 이동하면, 사유를 선택하고 취소 또는 환불 버튼을 누르게 되는데 해당 로직이 바로 위 로직이다. 사유를 선택하지 않았을 경우, 사유를 선택하라는 경고창이 뜨게된다. 정확하게 필수사유를 선택한다면 그 뒤부터 통신이 시작된다. 데이터베이스에 수정을 요청하는 메소드인 PUT을 사용하여 변경할 사항들을 data에 담아 보낸다. 역시 이때도 header에 현재 유저의 엑세스토큰을 담아서 보내줘야한다. 통신이 완료되면 로컬스토리지에 데이터 중첩문제와 보안의 위험성 때문에 로컬스토리지에 담겨있는 아이템을 삭제하고, 완료페이지로 이동한다. 로컬스토리지를 사용하게 되면 삭제하는 작업을 잊으시는 분들이 몇분 계셨는데 작업이 완료되고도 삭제하지 않는다면 데이터가 계속 쌓이게 되어 원하는 작업을 수행하지 못할 수 있다. 꼭! 꼭! 필요한 작업이 끝나면 지워줘야한다!

 

 

 


 

 반성과 칭찬의 시간 

 

 

한줄로 나를 칭찬하고 반성하기

 

칭찬하자🥳 : 처음 사용하는 프레임워크임에도 불구하고 원하는 목표치를 전부 완료했다!

반성하자😰 : 백오피스까지 작업하려 노력했어야했는데 기간에 맞추느라 또 욕심부리지 못했다.

 

 

협업에 대해서 칭찬하고 반성하기

 

칭찬하자🥳 : 다함께 열심히 작업해서 서비스부분은 필수구현을 완벽하게 완성했다! 모두 git을 사용할때, 소통이 잘되어 있어서 문제가 생기지 않았다. 월요일 오전에는 팀원 전체 회의를 진행하여 각자의 진행사항을 확인했다. 위코드에서 작업했던 팀 인원수는 5명 내외였는데 갑자기 10명으로 늘어났었다. 그럼에도 불구하고 소통을 원활하게 진행하기 위해 다함께 노력했고, 발표까지 원활하게 마무리하게 되었다! 다들 너무 대단하다!

 

 

반성하자😰 : 초반에 프론트와 백엔드 모두 초기세팅, 모델링을 진행하느라 소통이 조금 부족했던 부분이 있었다. 적극적으로 나서서 모델링을 같이 참여했어야했지만, 그렇게 하지 못했다. 결국 만들지 않아도 되는 레이아웃을 만들게 되는 일도 발생했었다. 조금 더 적극적으로 백엔드분들과 소통하며 도왔어야했는데 실천하지 못했다. 많이 반성해야하는 부분이다. 팀원분들중에 스트레스를 받으시거나 의욕저하가 있으실때 조금 더 응원하고, 다독여줬어야했지만 그렇지 못했다. 아직도 팀원으로 성장해야한다고 느꼈다.