[위코드 1차 프로젝트] 오늘의집 클론코딩 후기

여주링·2020년 12월 27일
12

Project

목록 보기
4/6
post-thumbnail

🏠위코드 15기 폭주기관차🚄팀

폭주기관차 '늘집' Backend Github
폭주기관차 '늘집' Frontend Github

Project Overview🌱

위코드에서 한달간 열심히 배운 개념을 실제로 써보는 두번째달이 시작되었다. 오늘의집이 코린이에게 어려울거같은 생각에 피하려고했는데 아뿔싸, 귀신같은 멘토님들이 오늘의집에 나를 넣어주셨다. 백엔드 적으로 많이 배울 수 있을거라는 멘토님의 말에 내가 가진걸 다 쏟아부어보자는 마음으로 접했다.
폭주기관차라는 이름처럼 정말 앞만 보고 달린 2주일이였다.

  • 진행기간 : 2020년 12월 14일 ~ 2020년 12월 24일
  • 프로젝트 인원 : Frontend 3명, Backend 3명

기술 스택🌹

  • FrontEnd : HTML / CSS / JavaScript (ES6) / React (CRA 세팅) / SassE
  • BackEnd : Python / Django / CORS Header / Bcrypt / PyJWT / MySQL / AqeuryTool
  • 협업도구 : Slack / Git + GitHub / Trello를 이용, 일정관리 및 작업 현황 확인 / Postman (API 관리)

구현 사항(Backend기준)🤜

모델링 구축

-데이터베이스 모델링 참여(Aquerytool이용)
-django & mysql연결

주요구현사항(내가 구현한건 🌹표시)

  • bcrypt를 사용한 암호화🌹
  • JWT 로그인 구현 및 @decorator를 이용해서 토큰 인증🌹
  • Email&닉네임 정규화를 통한 Validation적용🌹
  • 상품의 장바구니 등록 🌹
  • 장바구니 내역 조회🌹
  • 장바구니 상품 수량 변경 및 가격반영(DB에 전부 반영되도록 설정)🌹
  • 카테고리-서브카테고리 사이드바 (카테고리를 반영하여 상품 나열)
  • 상품 상세 페이지 (상품 정보: 가격, 사진, 옵션 )

과정&결과화면🏠

'늘집🏠'동영상

1.회원가입 화면


오늘의집은 회원가입이 생각보다 허.술.했.다. 실제 오늘의집 홈페이지에서 회원가입시 @다음에 .이 아닌 콤마','여도 로그인이 되더라... email유효성검사를 안하는건가? 라는 생각이 들었다.
그래서 이부분을 보완하여 작성했다.
그리고 암호화를 동시에 적용해서 데이터베이스에 저장하도록 처리했다
(자세한 코드내역은 바로 이어서 쓸거라서 간단하게 남기겠다)

class Signup(View):
    def post(self, request):
        data           = json.loads(request.body)
        REGEX_EMAIL    = '^[a-zA-Z0-9+-_.]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$'
        REGEX_PASSWORD = '^[A-Za-z0-9@#$%^&+=]{8,}$'

        try:
            if not re.match(REGEX_EMAIL,data['email']):
                return JsonResponse({"message":"INVALID_MAIL"},status=401)

            if not re.match(REGEX_PASSWORD,data['password']):
                return JsonResponse({"message":"INVALID_PW"},status=401)

            if len(data['nickname']) < 2 and len(data['nickname']) > 8:
                return JsonResponse({"message":"INVALID_NICKNAME"},status=401)

            if User.objects.filter(email=data['email']).exists():
                return JsonResponse({"message":"USER_EXIST"}, status=409)

            if User.objects.filter(nickname=data['nickname']).exists():
                return JsonResponse({"message":"NICKNAME_EXIST"},status=409)

2.로그인화면


유효성검사에 관련된 내용은 이미 회원가입에서 끝났기때문에, 로그인시 이메일과 암호화된 패스워드를 체크하고 로그인성공시 토큰을 발급하게 했다

class Signin(View):
    def post(self, request):
        data = json.loads(request.body)
        try:
            if User.objects.all().filter(email=data['email']).exists():
                if bcrypt.checkpw(data['password'].encode('utf-8'),User.objects.get(email=data['email']).password.encode('utf-8')):
                    access_token = jwt.encode({'id':User.objects.get(email=data['email']).id}, SECRET, ALGORITHM).decode('utf-8')
                    image = User.objects.get(email=data['email']).profile_image
                    name = User.objects.get(email=data['email']).nickname
                    return JsonResponse({"message":"SUCCESS", "TOKEN":access_token, "IMAGE":image, "NAME":name}, status=200)

                return JsonResponse({"message":"INVALID_PW"},status=401)
            return JsonResponse({"message":"INVALID_EMAIL"},status=401)
        except KeyError:
            return JsonResponse({"message":"KEY_ERROR"},status=403)
        except ValueError:
            return JsonResponse({"message":"INVALID_USER"},status=404)

3.회원전용화면에서 로그인 데코레이터 적용

회원만 사용이 가능한 기능에서 토큰을 유효성 확인을 통해 접근권한을 지정했다. 로그인이후 거의 대다수의 화면에 적용될것으로 생각하고 가장 많은 시간을 소비했다.

def login_decorator(func):
    def wrapper(self, request, *args, **kwargs):
        if "Authorization" is None:
            return JsonResponse({"MESSAGE":"INVALID_LOGIN"}, status=401)
        encode_token = request.headers["Authorization"]
        try:
            data         = jwt.decode(encode_token, SECRET, ALGORITHM)
            user         = User.objects.get(id = data["id"])
            request.user = user        
        except jwt.DecodeError:
            return JsonResponse({"MESSAGE" : "INVALID_TOKEN"}, status = 401)
        except User.DoesNotExist:
            return JsonResponse({"MESSAGE" : "INVALID_USER"}, status = 401) 
        except jwt.InvalidTokenError:
            return JsonResponse({'MESSAGE': 'INVALID_ACCESS_TOKEN'}, status=401)       
        return func(self, request, *args, **kwargs)
    return wrapper

4.상세페이지에서 물건 장바구니에 추가하기


유저가 원하는 상품을 장바구니에 추가하는 로직을 만들었다. 비회원이 아닌 회원을 기준으로 작성하였고, 따라서 2번에서 만든 데코레이터를 적용해 해당토큰값을 가진 유저의 장바구니에 아이템이 추가될 수 있도록 작성했다.
옵션별로 맞출수 있게 구현했는데 시간이 모자라 일단 옵션에 한가지 상품만 넣고 발표를 했다.

@login_decorator
    def post(self, request):
        data = json.loads(request.body)
        user = request.user
        try:   
            if Cart.objects.filter(
                user=user.id, 
                product=data['product_id'], 
                color=data['color_id']).exists():
                item = Cart.objects.get(
                    user=user.id, 
                    product=data['product_id'], 
                    color=data['color_id'],
                    option=data['option_id'])
                item.quantity += int(data['quantity'])
                item.save()
                return JsonResponse({"message":"SUCCESS"}, status=200)      
            Cart.objects.create(
                user     = User(id = user.id),
                product  = Product(id = data['product_id']),
                quantity = int(data['quantity']),
                color    = OptionColor(id = data['color_id']),
                option    = Option(id = data['option_id'])
            )
            return JsonResponse({"message":"SUCCESS"}, status=201)     

5.장바구니 조회 및 상품 수량 변경


해당 유저의 장바구니를 조회하고 상품 수량을 변경하는 로직을 담당했다. 처음으로 patch라는 개념을 사용했는데, 주변 백엔드분들이 써보신 분들이 잘 없어서 혼자서 개념을 잡는게 좀 어려웠었다. 결국 멘토님이 대대적인 수정을 해주셨지만 혼자서 잘 생각해냈다는데 의의를 두었다!

   #장바구니 갯수변경
class CartDetailView(View):
    @login_decorator
    def patch(self, request, cart_id):
        try: 
            data = json.loads(request.body)
            item = Cart.objects.get(id = cart_id)
            item.quantity = int(data['counts'])
            item.save()
            
            return JsonResponse({
                "message"  : "SUCCESS", 
                "QUANTITY" : item.quantity, 
                "PRICE"    : item.option.price * int(item.quantity)}, status=201)

        except KeyError as ex:
            return JsonResponse({'message' : 'KEY_ERROR_' + ex.args[0]}, status=400)

팀프로젝트 후기🏠

잘한 점😎

나를 믿고 팀을 믿은점

다들 처음하는 사람들이고, 팀 프로젝트도 처음이니 결과물이 안나와도 과정을 중요시 여기자고 생각하며 팀 프로젝트를 진행했다. 물론 압박감을 안느꼈다고 하면 거짓말이지만, 하나하나의 과정을 보며 우리는 잘될거라는 믿음을 가질 수 있었다.

⭐️⭐️팀내 원활한 소통을 주도했다⭐️⭐️

첫 프로젝트인만큼 소통방법을 맞춰나가는데 초점을 두고 진행했다. 팀원들에게 왜 팀으로 진행하는지 잊지말아달라고 많이 말했는데, (잔소리라고 생각할지 모르겠지만)프로젝트의 궁극적인 목적을 잊지않았으면 하는 마음에 말한 거였다.
뒷풀이에서 팀원분들이 나중에 이부분에 감사를 표해주셔서 너무나 기뻤다!!!🥰

반성할 점😞

모델링에 너무 많은 시간을 보낸점

오늘의집이 너무 방대한양이라 추상적으로 모델링을 잡고 시작했는데,계속 변동사항이 생기며 마지막까지 모델링을 수정했다. 수정내역을 github에 올리고 merge될때까지 올스톱이 되는 상황이 많아서 다른 부분에 집중할 시간을 많이 버린것 같다.

멘탈관리

운좋게 사무실을 빌리면서 환경은 완성이 되었지만, 내 멘탈이 문제였다. 한달동안 배운걸로 홈페이지를 만든다는 사실만으로 너무 압박감을 느꼈는데, 이게 마지막에되서 펑 터졌다. 다른분들을 비교하면서 혼자서 자책도 많이하고, 팀원분들에게 짜증도 좀 냈었던거 같아 이부분이 제일 마음에 걸렸다.. 긍정긍정이였는데 한순간에 부정부정으로..ㅠㅠ 2차에서는 힘들겠지만 멘탈관리를 잘 해야겠다

잊을 수 없는 순간들👩‍💻

진짜 우리팀은 드라마 한 편 찍었다고 자신있게 말할 수 있다.

-발표 D-1, 멘탈붕괴시작

발표 전 날 저녁, 우리팀 백엔드 한분의 컴퓨터에서runserver가 안되는 사건이 발생했다. 홈페이지 스토어관련 API였는데, 서버를 돌려 테스트를 못하고 멘토님들에게 구조요청을 보내느라 시간이 엄청나게 지체되었다.
결국 내 컴퓨터로 branch를 불러오는식으로 진행했는데, 2명의 branch를 한명의 컴퓨터로 runserver하게되면서 멘붕이 시작되었다. 프론트에서도 빨리 맞춰봐야 수정사항을 알 수 있던 상황이라 너무 죄송스러웠고, 왜 이 타이밍에 컴퓨터가 말썽인지 눈물이났었다...😞

-발표순간 401에러가 발생, 망했어요

프로젝트 발표 직전 우리는 수십번 테스트를 통해 로그인과 회원가입에 문제가 없는걸 확인했다.

그런데

발표하자마자 401ERROR가 뜨기 시작하는것이 아닌가....
내가 2주간 밤샘하며 만든 회원가입&로그인&장바구니가 모두 구현이 불가능한 상황이 된상태로 발표가 끝났다.......

말그대로 팀분위기는 초상집이고..
다른팀분들도 진짜 다들 엄청 안타까워하는 상황이라..
발표끝나고 서버를 끄고 다시켜보니..
와.. 된다..ㅠㅠㅠㅠㅠㅠㅠ(장난하냐)
결국 마지막팀의 발표가 끝나고 한번 더 기회를 얻어서 15기앞에서 시도를 하고..
⭐️대⭐️성⭐️공⭐️

마지막으로

1차프로젝트에서 강조하고 또 강조하는건 팀워크!

1차 프로젝트에서 6명중 혼자 여자였는데, 남자사람들이랑 (혼자서) 마음의벽 잘 쌓는 1인으로 엄청나게 당황스러웠다. 결론적으로 말하면 오히려 더 편하게 프로젝트에 임할 수 있었다.
모든 일을 시작할때 팀워크가 가장 중요하다고 생각했고 이걸 잘 유지하려고 나름 노력했었다. 다행히 너무너무 착하신 분들이라 내 의견을 많이 반영해주셨고, 잘 웃으면서 마무리 되었던 것 같다. 2주간 동거동락하며 많이 친해져서 그런지 헤어지는게 아쉽다..코로나때문에 같은 공간에서 만날수 있는 사이도 아니라 언제 다시 볼 수 있을지 모르는 상황 ㅠㅠ 너무나 아쉬워...😞

  • 성훈님 : 전설아니고 레전드... 진짜 제 말도 안되는 요구 다 들어주는 프론트는 성훈님밖에 없을거같습니다 ㅠㅠ 진짜 마지막까지 힘드셨을텐데 너무 감사해요!!
  • 영재님 : 저랑 회원가입,로그인을 맞춰본 첫 프론트인 영재님! 정말 처음에 서로 통신되던 그 기쁨을 앞으로도 잊을수는 없을것 같습니다. 2차도 서로 더 성장하는 기회가되었으면 좋겠어요. 화이팅!!
  • 태현님 : 거의 풀스택같은 지식을 가지신 태현님, 진짜 태현님이 없었으면 완성이 될 수 있었을지 ... 원하시는걸 다 못해드려 너무 죄송한 마음이 많습니다 ㅠㅠ 마지막에 너무 고생하셔서 진짜 고생하셨어요 ㅠㅠ!! 뭐 이미 완벽하셔서 2차 걱정안됩니다.. 태현님은👍
  • 민철님 : PM님 다음 프로젝트는 더 잘합시다!! 제 멘탈 수습해주느라 정말 고생많으셨어요. 2차도 같이하게 되었는데 진짜 서로 아쉬워하던 부분 다 완성해보아요~👍
  • 수한님 : 우리팀 막내이자 15기 전체 막내 수한님!! 진짜 제일 많이 성장한분을 꼽으라면 수한님이 아닐까 싶을정도로 너무 잘해주셔서 감동했습니다😎 2차에서 이번에 함께한걸로 날아다니길 바래요 막내 잘가요ㅠㅠ!!
profile
🌱Backend Developer👩‍💻

14개의 댓글

comment-user-thumbnail
2020년 12월 27일

고생했어요 석석주 이제 어디가든 다 찢으십쇼 ^-^👊

1개의 답글
comment-user-thumbnail
2020년 12월 27일

trello를 본인건강보다 아낀여자... pm이 아닌데 pm처럼 모두를 케어한여자.... 키보드를 80키로인 나보다 더 쎄게 두둘기는여자... 마지막까지 잠도 안자고 열정을 쏟은여자.... 당신을 존경합니다 프로젝트기간 너무 수고했어요 여주링^^

1개의 답글
comment-user-thumbnail
2020년 12월 27일

여주님! 팀 분위기 다 만들어주셔서 너무 고맙습니다 ㅋㅋ 1차 프로젝트 하면서 고생 너무 많았어요 !!
2차 프로젝트도 같이 하게 되서 영광이고 화이팅입니다 !!!

1개의 답글
comment-user-thumbnail
2020년 12월 29일

우리 2차 프로젝트 PM님 models.py도 도맡아 하시고 항상 솔선수범 하는 모습에 감동하고 있습니다. 이번 프로젝트로 같이 성장해요 🌱

1개의 답글
comment-user-thumbnail
2020년 12월 29일

같은 팀, 같은 공간이 아니어서 프로젝트 기간 내내 아쉬웠지만 우리 정말 무서운 속도로 성장하고 있다고 생각해요!!
장바구니 끝내버린 여주님 축하드려요!!!! 앞으로도 백엔드 화이팅입니닷 ㅎㅅㅎ❤️

1개의 답글
comment-user-thumbnail
2021년 1월 2일

좋은 후기글 잘 읽었습니다 :)
한가지 궁금한 점이있어요!
클론코딩을 진행할때 제품 데이터는 크롤링하여 백엔드분들이 api를 만드시는건가요?!

1개의 답글