Dev forum 과제 리뷰

강준호·2024년 2월 19일

NodeJs

목록 보기
5/7

QnA

실제로 현업에서는 회원이 탈퇴한다고 해서 테이블에서 바로 삭제해버리진 않을 것 같다 → 삭제 여부를 나타내는 컬럼을 따로 두나?

→ 중요한 레코드의 경우 보통 가장 흔한 케이스가 물리 삭제 대신 컬럼을 따로 두는 거라고 하심!

회원 탈퇴를 DB에서 해당 레코드 삭제로 구현할 경우, 회원 ID를 FK로 갖는 다른 테이블들은 cascade 옵션이 걸리면 같이 삭제되어 버릴 것이다 → 이 경우는 어떤 식으로 구현하나? → 실제 물리적 삭제를 잘 안하므로 다양한 방식이 있음.

  • deletedAt
  • isDeleted
    이런 컬럼을 둬서 관리한다.

PK 컬럼 지정에 관한 질문

숫자말고 email 처럼 반드시 unique하게 쓰이는 것을 PK로 설정해도 괜찮은가? auto increment인 int 타입 대신 string을 PK로 설정하면 추후 인덱싱 관련해서 성능 상 손해가 있나? → 설정해도 됨. 성능 이슈는 있긴하다..

  • 유니크 하다면 pk 써도 된다. string 을 PK 쓰는 경우도 많음.
  • uuid 는 구식. => nanoid 를 쓴다던가로 대체

JWT 관련 질문

실무에서는 JWT 토큰에 만료기간을 두고 재발급을 받도록 할 텐데, 클라이언트와 서버 간 사이클이 보통 어떻게 되나? 구체적으로 구현은 어떤 식으로 하게 되는가? → expiresIn과 같은 옵션이 있고, refreshToken과 같은 API를 별도로 만들 수 있다

  • JWT jwt.expiresIn 으로 기간 관리 할 수 있음.
    엑세스 토큰 set time interval 로 리프레시 토큰 계속 요청을 보내서 갱신.

Secret key도 한번 생성한 것을 계속 쓰는 것이 아니라 주기적으로 바꿔가면서 할 것 같은데, 이건 또 어떤 식으로 구현해야 하나? → 잘 안바꿈

secret key의 보관은 DB에 하는 것이 좋은가? .env 파일에 하는 것이 좋은가? → DB에 함께 담는 것은 오히려 더 위험! .env에 하자!

  • 바꿔도 되는데 시크릿 키는 주기적으로 바꾸지는 않아. 이를 바꾸면 이전에 발급된 모든 토큰이 다 invalidate 됨.

  • env 는 DB 에 안넣고 분리하는게 좋음. .env 에 넣자.

auth 관련 질문

유저가 로그인이나 회원가입 시에 id와 password를 http 바디에 그대로 실어서 보내는 것은 위험할 것 같은데, 실무에서는 클라이언트 단에서부터 암호화를 시켜서 보내나? → https를 믿으므로 그렇게 잘 안함. 단, 피시방 같은 클라이언트 측 보안 위험이 높은 곳은 대칭키 같은 것을 이용해서 암호화 하기도 한다

  • 그런곳도 있고 아닌곳도 있음. https 를 믿고있기 때문에 그냥 쓴다.

context 방식의 디렉토리 구조에서의 애매한 점

auth context에 존재하는 service가 users context의 repository를 불러와서 써야하는 경우가 있다. 이런거 보면 그냥 mvc로 나누는게 낫지 않나 싶은데, 현업에서는 이런 경우에 어떻게 하는지? → 그래도 MVC 구조는 요새 잘 안쓴다고 함. nest.js로 가면 마음의 불편함이 덜 할 것이다
디렉토리 명이 그냥 테이블 명을 따라가는 경향이 생기는데, 실제로는 이런 식으로 하면 안되는 것 아닌지? → 디렉토리 명은 도메인 명으로 맞춰준다. 그것이 원칙

  • 디렉토리 명은 테이블 명과는 상관없이 도메인명.

시작

  • board 와 포스트는 포럼에 종속.

  • 디렉토리 구조를 잡은 후 프리즈마 모델 만들기. 프리즈마 src 에 넣고,

프리즈마 경로 추가해주기.
"prisma":{
schema
}

모델링

  • 프리즈마는 이름은 그대로 쓰기 때문에, 모델은 보통 단수로 쓰니까 prisma 에는 단수로. 규칙이 따로 있을경우는 map 매핑으로 이름 매핑

    Board

  • 게시판 언제 생성되었는지 createdAt

  • posts Post[] 로

  • label 로 프론트엔드 백엔드. 이걸 쓰는게 좋아.

    Post

  • updatedAt 도 하나 넣어주자. @updatedAt

  • 게시판 name 으로 외래키 잡으면 한번에 게시판 이름에 대응되는 게시판 아이디 찾을 수 있어. 쿼리 하나 줄일 수 있음 => 근데 프리즈마가 알아서 해줘서 상관은 없긴해.

  • User 와 연결해줄 authorId 를 사용해(userId 써도 되는데 이름겹치니까),

    User

  • user id 가 1,2,3,4 공개되는게 싫어서 string 으로.

  • email string 에 유니크.

  • 내가 작성한 posts , 라이크한 포스트

comment

  • author User

prisma

  • app. ts 가 처음에 불러와서 실행해주도록
    import clientprisma 해주기.
npx prisma studio

boards.service

getBoard

  • RequestHandler 에서 params 보드네임 받아야지. enum으로 선언해서 보드네임 타입.
  • findUnique({where: {name: boardName}}) 그리고, include 전부다.

getBoard 리퀘스트에 대한 고민. boardName: BoardName 으로 하고, 이걸 controller 에서 request들 따로 분리하기. => 서비스 안에 있던 로직을 컨트롤러로 꺼내주기.

  • 왜 서비스는 리퀘스트 핸들러야하는가??

  • 도메인 아키텍쳐를 써보니까 서비스를 이곳 저곳에서 쓰려면
    확실하게 비즈니스로직을 분리하는게 좋겠다는 판단!


게시판에 글쓸때

  • authorId, title, content, boardId 가 필요해.
  • board에 아이디를 가지고 해야하지만, boardName을 사용. 보더 네임을 외래키로 잡아서 하는게 좋다라고 아까 말한거(근데 프리즈마가 해줌).

Auth

auth controller

  • 마찬가지로 여기에 request 써주자.

auth.type 을 써주고

  • signUpDto 라고 써도됨.

auth.service

  • 나노아이디 (낮은버전으로! nanoid 버전 3) 로 아이디 생성.

  • b크립트의 해쉬를 import 해서, 비밀번호에 hash(12) 정도. 오래걸리니까 await 로

  • 리턴으로 엑세스 토큰을 돌려준다.

엑세스 토큰

  • generateAccessToen 함수로 따로 뺴고, jwt.sign() 으로 .

  • jwt.sign()

  • 시크릿 키는 나노아이디 nanoid --size 48 으로

  • jwt.sign()

로그인

  • 패스워드 compare 로, 일반과 인크립트 패스워드를 비교.

  • 근데 이걸 쓰려면 유저를 불러와서 user.encryptedPassword 를 써야해.

  • 유저가 없으면, 그냥 에러 보내. 에러 처리는 컨트롤러 책임이니.

  • 이 과정을 거치면, 프론트에서 Header 의 authrization 의 베어러에 토큰을 보내주지.

  • 그래서 middleware 에서 이를 처리해보자.

auth.middlewares

req.headers.authorization?.split("Bearer ")[1];
  if (!accessToken) return res.sendStatus(401);
  • 값이 없을수도 있으니 옵셔널 체이닝 ? 붙여.

  • Return 꼭 붙여! 안붙이면 코드 계속 내려가.

  • 엑세스 토큰(JWT )을 확인해봐야하는데 이를 검증하려면 jwt의 verify 를 사용!

dotEnv

  • prisma 가 해주는것.

  • 원래는 아래처럼 dotenv install 하고 Config 해줘야함.

import dotenv from 'dotenv'

dotenv.config()

config

  • secret.config.ts

middleware service 여권 검증 과정

  • 타입

  • 정상이면, sub에 넣어준 id 를 꺼낼 수 있지.

  • 타입을 지정해줘야하는데, id는 무조건 있음으로, id as string 써도돼.

  • user 가 없다면(삭제되었다면), throw new Error. throw 에러하면, try catch 에 잡혀서.

types 에 User 정의

express.type.ts

  • req 를 사용할때 쓸 user 타입을 정의. req.header 처럼 새로 인터페이스를 만들어준것.
declare global{
namespace Express{
  interface Request{
  	user: User|null,
  }
}
}

autherization 이 필요한 라우트와 안필요한 라우트를 나누는 가드!

guards/userOnly.guard.ts

  • 조건에 안맞으면 조기에 에러를 리턴하는것!

  • 미들웨어로 구성

  • req에서 유저를 꺼내.

  • 유저 only 인데 유저


좋아요

  • 토글 방식으로 만들거나/ like unlike 로 두개 나눠서 만들거나하는 방식이 있어.

  • posts 아래 likes 디렉토리 만들자.

  • postcontroller 만들고, /:postId

likes.service.ts

  • like를 만들려면 1.유저, 2.포스트가 필요.

  • request 에 userId, postId 두가지 받기.

  • 프리즈마 클라이언트에서 포스트를 가져와 업데이트. 근데 likers 가 userId 인것으로.

  • 중간테이블의 연결을 프리즈마가 알아서 해줘. 기존 (prismaClient.likedPost.create(userId,postId)) 를 안해줘도돼.

  • 업데이트 할건데, 유저와 연결된걸 업데이트 할거야.=> 유저 A 가 포스트 1번에 대해서
    좋아요 토글을 하려고함.

=> 포스트 1번을 유저 A가 좋아요 눌렀는지 확인해야함. => post.findFirst( 여러명 중 userId 가 있는지 some 으로 확인 )

만약 liked포스트가 있으면(눌려있는 상태니)

  • 좋아요를 지워야해. prismaClient.user.update({where: id:userId}...
    likePosts{
    유저 아이디가 PostId 인거 disconnect.
    }
    )

JWT 관련 오류 발생

=> prisma 가 해주던건데, 이게 안될수도 있으니,

dotenv.config 로

import dotenv from "dotenv";

먼저 업로드 하는 파일을 만들어서 처리해주자.


포스트맨

엑세스 토큰 복사해서 헤더 authrization 에 Bearer 00토큰 넣고. 검사.


더미데이터

  • 프리즈마의 seed.ts 만들고ㅡ
    그냥 upsert로. (없으면 create 있으면 insert (insert+create))

  • migrate dev 하면 계속 데이터가 쌓이니 upsert 를 쓰는게 효율적.
    생성만 하고 싶으면 create / createMany

0개의 댓글