1차 팀 프로젝트 소개

섹션1. 팀프로젝트 주제는 쇼핑몰이었다.

프로젝트의 목표는 요구사항을 충족하는 DB와 API를 설계하고 설계에 맞는 ERD와 API명세를 작성하는 것으로 시작해, 명세된 기능을 fastify를 사용해 웹서버를 구현해 제작한 API가 잘 작동하는지 확인하는 것이다.


필수 요구사항

  • 사용자는 모든 상품을 조회할 수 있다
  • 사용자는 특정 분류의 상품을 조회할 수 있다(상품분류, 브랜드명, 가격, 상품명)
  • 사용자의 타입이 판매자인 경우 자신의 상품을 등록할 수 있다
  • 사용자는 상품을 장바구니에 담을 수 있다
  • 사용자는 자신의 장바구니를 조회할 수 있다
  • 사용자는 자신의 장바구니에 있는 상품의 수량을 변경시킬 수 있다
  • 사용자는 상품을 자신의 장바구니에서 제외할 수 있다

추가 요구사항

  • 회원가입, 로그인, 로그아웃을 할 수 있다.
  • 관리자는 모든회원의 정보를 조회할 수 있다.
  • 사용자는 자신의 정보를 조회할 수 있다.
  • 관리자는 회원을 삭제할 수 있다.

DB 설계

쇼핑몰 프로젝트 ER-Diagram

필요한 테이블은 크게 users, products, Cart테이블에 더해서 product 컬럼 내용의 중복이 많을 수 있는 category와 brand는 따로 테이블을 만들어서 관리한다.

Brands와 Categories는 이 설명만으로 충분하기 때문에 나머지 테이블을 살펴보면

  • users 테이블은 pk인 id, 그리고 유저가 어떤타입(일반, 관리자, 판매자)인지 나타내는 type과 password, email 컬럼으로 구성된다.
  • products 테이블은 pk인 productid, 그리고 판매자(user)의 id인 sellerId, 해당 브랜드의 id인 brandid, 해당되는 카테고리의 id인 categoryid를 각 해당테이블과의 외래키로, 나머지는 상품명인 productName과 가격인 price, 마지막으로 상품 설명인 desc로 이뤄진다.
  • Cart 테이블은 pk인 id, 그리고 장바구니 주인(user)의 id인 userId, 장바구니에 담긴 상품의 id인 productid를 각 해당테이블과의 외래키로, 나머지는 담긴 상품의 양인 qty로 이뤄진다.

API 명세

Method Path Request Header Request Body Response Status Code Response Body
GET /product Content-Type: application.json - 200 OK [ { "sellerID": 1, "brandID": 1, "categoryID": 1, productName": "테스트 상품.", "price: 50000", "desc": "테스트용 상품입니다." }, { "sellerId": 2, "brandId": 2, "categoryId: 2, "productName": "테스트 상품2", "price": 500000, "desc": "테스트용 상품2입니다." } ]
GET /product/:productId Content-Type: application.json - 200 OK 404 Not Found { { "sellerID": 1, "brandID": 1, "categoryID": 1, productName": "테스트 상품.", "price: 50000", "desc": "테스트용 상품입니다." } }
POST /product Content-Type: application.json, Authorization { "brandId": 1, "categoryId": 1, "productName": "테스트 상품.", "price": 50000, "desc": "테스트용 상품입니다." } 201 OK 400 Bad Request 403 Forbidden { "sellerID": 1, "brandID": 1, "categoryID": 1, productName": "테스트 상품.", "price: 50000", "desc": "테스트용 상품입니다." }
PUT /product Content-Type: application.json, Authorization { "brandId": 2, "categoryId": 2, "productName": "테스트 상품 수정.", "price": 50000, "desc": "테스트용 상품 수정입니다." } 201 OK, 400 Bad Request 403 Forbidden { "brandId": 2, "categoryId":2, "productName": "테스트 상품 수정.", "price":50000, "desc": "테스트용 상품 수정입니다." }
DELETE /product/:productId Content-Type: application.json, Authorization { "productID": 1 } 200 OK 204 No Content 400 Bad Request { "Success", "Bad Request" }
GET /cart Content-Type: application.json - 200 OK [ { "cartId": 1, "productId": 1, "productName": "상품명", "brandName": "브랜드명", "categoryName": "분류명", "price": 1000, "desc": "설명" } ]
POST /cart Content-Type: application.json, Authorization { "productId": 1 } 201 OK "Success"
PUT /cart/{cartId} Content-Type: application.json, Authorization { "productID": 1, "Qty": 1 } 200 OK 204 No Content 400 Bad Request "Success", "Bad Request"
DELETE /cart/{cartId} Content-Type: application.json, Authorization { "productID": 1 } 200 OK 204 No Content 400 Bad Request "Success", "Bad Request"
GET /user Content-Type: application.json Authorization - 200 OK [ { "userId": 2, "email": test@test.com, "password": 1234 }, { "userId": 3, "email": test2@test.com, "password": 1234 } ]
GET /user/:userId Content-Type: application.json Authorization - 200 OK 204 No Content { "userId: 2, "email": test@test.com "password": 1234 }
POST /signUp Content-Type: application.json, Authorization { "email": test@test.com "password": 1234 } 201 Created 400 Bad Request "Created", "Bad Request"
POST /signIn Content-Type: application.json { "email": test@test.com "password": 1234 } 200 OK 401 Unauthorized "OK", "Unauthorized"
PUT /user/:userId Content-Type: application.json, Authorization { "email": test@test.com "password": 1234 } 200 OK 400 Bad Request "Success", "Bad Request"
DELETE /user/:userId Content-Type: application.json, Authorization - 200 OK 400 Bad Request "Success", "Bad Request"

 API 명세서를 작성하면서 어떻게 API를 구성해야 구조가 직관적이어서 구현할 때 보기 편할지 고민을 많이 했다.

 그 결과 결국 상품, 사용자, 장바구니 별로 API 경로를 구분해 작성하는 것이 구현에 있어서도, 테스트에 있어서도 가장 직관적일 것이라고 판단해 API url을 정의했다. 그리고 request body값과 response값의 정의는 개발작업 중 편의를 위해서 개발 도중 변경하는 노선을 택했다.


구현작업 중 마주했던 이슈들 

초반 프로젝트 방향성 정리 부족으로 인한 의사소통 문제

 

 처음 프로젝트를 시작할때 서비스를 만듦에 있어서 확실히 정하고 넘어가야 하는 부분에 대한 충분한 의사소통이 없었던 점이 아쉽다.

 프로젝트를 진행하면서 이 프로젝트의 부분간의 연관점을 어떻게 다룰 것인가에 대해서 미리 정하지 않아서 서로가 서로의 작업 끝나는 것을 기다리면서 시간을 허비하거나 부분간의(ex. 깃/깃허브는 어떻게 사용할지) 유기적인 상호작용이 제대로 되지 않는 문제가 있었다. 

 

의사소통 문제로 인한 작업량 불균형 문제

 

앞서 언급했던 의사소통 문제의 연장선으로, 팀원들 간의 논의가 이뤄지지 않은 문제들이 속속 튀어나오면서 개발에 익숙한 팀원들이 프로젝트를 진행하게 되는 상황이 발생해버렸다.  그바람에 개발에 익숙하지 않았던 팀원들이 작업에 제대로 참여하지 못하게 됐고, 결과적으로 역량강화를 위해서 했어야하는 경험들을 팀원들 모두가 충분히 하지는 못했다고 생각한다.

 

어떻게 해야 해결할 수 있을까?

 앞으로는 프로젝트를 진행할 때 시간을 조금 할애하더라도 팀원들간의 차이를 고려해 프로젝트의 어떤작업을 어떻게 진행할지 확실히 해두고 다음 단계로 넘어가야겠다고 다짐했다. 

 그리고 프로젝트 진행 중에도 작업이 버거워보이는 팀원들에게 먼저 도와주러 가는 태도를 더 적극적으로 가져야겠다는 생각이 들었다.

 


 

깃허브 오류 : git pull 명령어 사용시 에러( Need to specify how to reconcile divergent branches. )

 

이 오류는 클론 받아온 로컬 브랜치와 원격 브랜치가 충돌이 있는 상태에서 merge(병합)하려고 할 때 발생한다. 그래서 이 문제를 해결하려면 먼저 충돌을 해결한 뒤에 병합을 진행해야 하는데, 해결법은 다음과 같다.

  1. 로컬 브랜치의 변경 사항을 커밋해준다.
  2. 로컬 브랜치 - 원격 브랜치의 동기화를 위해서 pull을 수행해준다.
  3. 충돌이 발생한 파일을 찾아서 수동으로 충돌을 해결해준다. 충돌은 <<<<<<< HEAD, =======, >>>>>>> 같은 마커로 표시된다.
  4. 충돌이 해결된 파일을 다시 커밋하고, 병합을 완료하면 해결된다.

Postgre 데이터베이스 오류 : 보낸쿼리에서 컬럼명을 찾지 못하는 문제 에러 (column "productname" does not exist)

 

`update public.products set productName = COALESCE($1, productName), price = COALESCE($2,parsedPrice), "desc" =COALESCE($3,"desc") where id=$4`, 
              [productName, parsedPrice, desc, productId]

 이 쿼리문이 Postgre 데이터베이스에서 컬럼명을 찾지 못하는 오류였다.

 이 오류는 알고보니 'productName'컬럼명처럼 대소문자를 구분해서 작성한 구문이 있어서 생기는 오류였다.

 Postgre는 기본적으로 컬럼 이름을 소문자로 해석하는데, 그래서 나는 분명 컬럼명을 대소문자로 구분해 적었지만 Postgre는 컬럼명을 모두 소문자로 해석해서 일어난 오류이다.

 

 

이 오류를 해결하는 법은 매우 간단하다. 아래처럼대소문자를 구분해 적어둔 구문에다가 쌍따옴표를 씌워주면 된다.

`update public.products set "productName" = COALESCE($1, "productName"), price = COALESCE($2,price), "desc" =COALESCE($3,"desc") where id=$4`, 
            [productName, parsedPrice, desc, productId]

이렇게 쿼리문을 작성해주면 오류가 깔끔하게 해결되는 것을 볼 수 있다.

 

 


데브옵스 부트캠프에서 첫 프로젝트 작업이었다. 프젝 진행중에 생기는 상황을 보면서 미리 논의를 하는게 얼마나 중요한지 조금이나마 께닫는 시간이 된 것 같다. 복잡하게 흘러가는 상황에 따라오지 못하는 팀원들을 보며 안타까웠고, 앞으로도 진행할 다른 프로젝트들에 있어서는 이번 프로젝트와 같은 문제를 반복하지 않도록 신경 많이 써야겠다. 

 그리고 회고를 쓰면서 아쉬웠던 점은 구현작업 도중에 마주쳤던 오류, 이슈들에 대한 기록들을 소홀하게 했다는 것이다. 많은 에러와 싸우며 완성한 프로젝트임에도 이 해결과정을 남기지 못하는 점이 너무나도 아쉽다. 앞으로는 오류 마주칠 때마다 입맛다시면서 기록해야겠다 ㅎㅎㅎ

+ Recent posts