[Project] 숭고 Soongo - 백앤드 진행편
숨고 사이트를 클론하기로 결정한 이유
첫번째 프로젝트로 경력이 있는 두 분과 잘하시는 분들 두 분이 같은 팀원이 되어서 "숨은 고수"로 우리를 표현하고 싶었다. 😎
그리고 숨고 사이트가 회원가입이 일반, 고수로 이분화되어 있었고
일반회원이 원하는 서비스를 고수가 제공하는 서비스와 매칭해주는 시스템이 백엔드 공부하기에 너무 좋아 보였다!
내가 맡은 역할
고수 회원 가입 API
- 숭고 사이트에 한번도 가입하지 않은 사람은 바로 가입할 수 있다.
- 일반 회원으로 가입했던 사람도 로그인한 상태에서 고수로 전환하기를 선택하면 고수로 가입할 수 있었다.
- 고수로 가입한 회원은 일반 회원의 기능을 모두 이용할 수 있는데, 일반 회원으로 전환하는 버튼을 누르면 로그인한 상태에서 이동이 가능하다.
프로젝트 첫날 모델링 회의를 할 때 먼저 일반회원, 고수를 먼저 만들고 시작했다.
컬럼명은 줄임말을 쓰지 않고 자세하게 적는 게 좋다고 한다. 그래서 최대한 친절하게 만들었다. 이렇게 하니까 확실히 바로 보고 이해하기에 수월했다.
관계형 DB를 모델링할때는 1:1 관계 설정은 지양해야 한다고 들었지만 일반 회원과 고수를 분리해야 각각 연관된 테이블과 관계 설정을 할 수 있어서 분리했다. 가입시 선택한 카테고리, 주소 정보를 전달 받으면 각각 테이블에서 찾아서 중간 테이블에 저장하는 코드를 작성했다.
// 1. 로그인 토큰이 없는 경우
if (typeof token === "undefined") {
// 이메일과 번호로 가입된 사용자인지 확인
const userInfo = await UserDao.findUserInfo(email, phoneNumber)
// 로그인을 하지 않았지만, 일반 회원이나 고수로 이미 가입한 사용자인지 확인
if (userInfo.length !== 0) {
const isExistingMaster = await MasterDao.findMasterInfo(userInfo[0].id)
if (isExistingMaster.length !== 0) {
throw await errorGenerator({
statusCode: 400,
message: "EXISTING_MASTER",
})
} else {
throw await errorGenerator({
statusCode: 400,
message: "EXISTING_USER!_PLEASE_LOGIN",
})
}
}
// 일반 회원으로 가입한 적이 없고 고수로 가입 신청한 경우, user 테이블에 추가
const hashedPW = bc.hashSync(password, bc.genSaltSync())
await UserDao.createUserDirectMaster(name, email, hashedPW, phoneNumber)
// 2. 로그인 토큰이 있는 경우
} else {
try {
// 토큰을 가지고 유저가 맞는지 확인
const isValidUser = jwt.verify(token, process.env.SECRET_KEY)
await UserDao.insertPhoneNum(isValidUser.id, phoneNumber)
} catch (error) {
throw await errorGenerator({
statusCode: 400,
message: "INVALID_USER",
})
}
}
// 3. 이후에는 고수와 연관된 테이블에 정보 추가
고수 후기 API
- 일반 회원은 본인과 매칭된 고수에게 후기를 남길 수 있다.
- 고수 상세 페이지에서 고수의 평점과 후기를 볼 수 있다.
후기 테이블 하나만 더 생성하고 일반 회원과 고수 id를 외래키로 설정해서 각각 1:N관계로 만들 수 있었다.
그리고 리뷰 추가 버튼은 매칭 후 생성되기 때문에 일반 회원 id값을 로그인 토큰에서 받아서 사용하면 된다. 하지만 우리팀은 리뷰 추가 기능을 다음으로 미뤘기 때문에 고수 id를 받아서 그 고수의 리뷰만 찾아서 보내주는 기능만 만들었다.
const sendPreview = async (masterId) => {
try {
// masterId가 master테이블에 있는지 확인
const isMaster = await MasterDao.isMaster(masterId)
if (isMaster.length === 0) {
throw await errorGenerator({
statusCode:400, message: "MASTER_DOES_NOT_EXIST"
})
}
const reviews = await ReviewDao.sendPreview(masterId)
return reviews
} catch (error) {
throw await error
}
}
프로젝트하면서 배운 것들
1. 관계형 DB 1:1 관계와 1:N 관계의 차이
여러 테이블 간 관계 설정을 하기 위해서는 꼭 중간 테이블을 만들어야 한다고 생각했는데, 고수가 주소를 하나만 갖는다는 점을 생각해 보니 고수 테이블과 주소 테이블은 1:1 관계라서 중간 테이블이 필요 없었다. 그래서 중간 테이블은 삭제하게 되었다. 중간테이블은 N:M 관계일때 유용한 테이블이니까!
2. name대신 id 전달받기
프론트단에서 가입시 선택한 주소 정보를 "경기", "일산동구" 이렇게 문자열로 받아야 된다고 생각했는데 id로 전달 받을 수 있었다! 화면 단위로만 생각하다보니 깊게 생각하지 못했다.
3. prisma는 착한 친구다.
prisma 내장 함수를 이용하면 가독성도 훨씬 좋고 세미 콜론 빠드렸다고 소름 돋을 일도 없다..
// prisma 내장 함수
const getAddress = async () => {
return await prisma.address.findMany({
select: {
id: true,
name: true,
detailAddress: {
select: {
id: true,
name: true,
},
},
},
});
};
// SQL 쿼리문
const sendMasterAddress = async (id) => {
return await prisma.$queryRaw`
select a.name as address, d.name as detail_address
from address a, detail_address d, masters m
where m.id = ${id}
and m.address_id = a.id
and m.detail_address_id = d.id;
`;
};
4. 미들웨어를 쓰면 좋은점, 무한스크롤 하는 방법
프로젝트 후기에서 작성할 예정ㅎ
더 해보고 싶은 것들
- 카카오 로그인 API, 지도 API를 적용해서 카카오 간편 로그인 기능, 고수의 이동 가능 거리 선택 기능 넣기
- multer 라이브러리를 이용해서 사용자가 업로드한 사진을 서버에 사용자별 폴더에 저장하고 그 주소를 DB에 저장하기
- Query Parameters 사용하기!
- GIT 더 자세하게 공부해서 GIT공포증 없애기..
Author And Source
이 문제에 관하여([Project] 숭고 Soongo - 백앤드 진행편), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@yeonjoo7/Project-숭고-Soongo-백엔드-진행편저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)