김데이의 개발공부

[ WIL ] Day 62~64 - 중급 프로젝트 : ERD / Prisma Schema / OAuth 본문

코드잇 Node.js(BE) 부트 캠프/WIL (Weekly I Learn) 📚

[ WIL ] Day 62~64 - 중급 프로젝트 : ERD / Prisma Schema / OAuth

theday365 2025. 12. 28. 19:37
반응형

🚀 이번 주 핵심 📚

1. 중급 프로젝트 진행 : 주요 작업 내용

  • 프로젝트 주제 선정
  • 협업 규칙 설정 : 프로젝트 문서 - 노션 / 코드 공유 - 깃허브 등등
  • 프로젝트 전체 ERD 정리
  • 정리 한 ERD를 바탕으로 Prisma Schema 작성

 

2. 프로젝트 작업에 필요한 개념 공부

  • ERD 작업
    • DB Diagram 서비스 이용
    • 각 테이블 별 고유 필드 / 관계형 필드 / enum 설정
  • Prisma Schema 작업
    • 실무에서 보편적으로 사용하는 네이밍 방식으로 설계
    • 하나의 테이블에서 여러 필드를 관계형으로 불러오는 방식 적용 
  • 유저 인증 절차
    • 일반 회원 가입 방식 : 토큰을 활용한 User 가입 / 로그인 방식
    • Oauth : 자사 서버에 직접 가입/로그인 하지 않고 제 3자를 통해 권한을 위임 받는 방식 
    • Passport : 유저의 인증&인가 과정을 좀 더 쉽게 구현하기 위한 라이브러리. 특히, 다양한 플랫폼의 Oauth 인증&인가가 가능함 

 



🤔 어려웠던 개념, 다시 공부하기 📑

1. 실무에서 많이 쓰는 ERD 작업 플로우 

 

1️⃣ 도메인 / 요구사항 정리

  • 사용자가 어떤 일을 하고, 어떤 데이터가 쌓이는지 정리
  • 엔티티 = 서비스에서 '독립적으로 존재하고, 저장돼야 하는 명사',
                  ID가 있고, 여러 개 존재하고, 관계를 맺고, 나중에 따로 관리하고 싶은 대상
    ⇒ 엔티티들 추출

2️⃣ 전체 테이블(엔티티) 네이밍

  • users, products, orders, order_items 같은 큰 덩어리 작업

3️⃣ 테이블별 PK 설계

  • id, 복합키(2개 이상의 id 또는 unique를 결합) 설계
  • PK에 적용할 uuid, ai(Auto-Increment) 결정

4️⃣ 관계 정의 (FK, 1:1 / 1:N / N:M)

  • 테이블 간의 관계 정의 및 관계에 사용 할 필드 설정
  • N:M 관계의 경우 중간 테이블 추가 생성

5️⃣ 나머지 필드 설계

  • 일반 컬럼을 작성하며 해당 컬럼의 속성(string, int, enum, Boolean 등) 설정
  • 컬럼의 nullable 여부 설정
  • id 값 이 외에 사용할 unique / index 확인

 

2. Prisma Schema 작업

[ Prisma Schema sample ]

model Order {
  id        Int         @id @default(autoincrement())
  userId    Int         @map("user_id")
  status    OrderStatus @default(PENDING)
  createdAt DateTime    @default(now()) @map("created_at")
  updatedAt DateTime    @updatedAt @map("updated_at")

  user User @relation(fields: [userId], references: [id])

  @@map("orders")
}

enum OrderStatus {
  PENDING
  PAID
  CANCELED
}

 

1️⃣ Model 이름

 

  • PascalCase, 단수형
  • 예시 : User, Product, OrderItem 등
  • JS/TS 코드에서 쓰기 좋은 명사형 사용 
  • DB 테이블 이름 
    • @@map() 사용하여 model 최 하단에 재선언
    • snake_case, 복수형
    • 예시 : users, products, order_items 등
    • SQL에서 가독성 좋아지고, 시스템 친화적

2️⃣ 필드 이름 

 

  • camelCase
  • 예시 : name, userId, status, createdAt
  • JS/TS 친화적인 방식
  • DB 테이블 이름 
    • @map() 사용하며, 한 단어로 끝나지 않은 필드 값에만 적용
    • snake_case, 복수형
    • 예시 : user_id, created_at 등 / name, status 같은 한 단어에는 적용하지 않음
    • SQL에서 가독성 좋아지고, 시스템 친화적

3️⃣ Enum 이름 / 값

 

 

 

  • 이름 : PascalCase / 값 : SCREAMING_SNAKE_CASE
  • 이름 예시 : OrderStatus, Category 등
    값 예시 : PENDING, CANCELED 등

4️⃣ 다중 관계형 설정

  • 같은 모델을 두 번 참조하면 @relation 작성 시 이름을 넣어 연결 해 주어야 함
  • @relation 이름은 ‘의미 기준’으로 작성 
  • 양쪽 모델 모두 컬럼을 각각 따로 선언해야 함(하나의 @relation에 합쳐서 선언하면 안됨)
model User {
  id      Int     @id @default(autoincrement())
  name    String

  // 관계 (역방향)
  orders           Order[] @relation("OrderUser")
  deliveryOrders   Order[] @relation("OrderAddress")

  @@map("users")
}

model Order {
  id Int @id @default(autoincrement())

  // 주문자
  userId Int @map("user_id")
  user   User @relation("OrderUser", fields: [userId], references: [id])

  // 배송지 
  addressUserId Int @map("address_user_id")
  addressUser   User @relation("OrderAddress", fields: [addressUserId], references: [id]  )

  createdAt DateTime @default(now()) @map("created_at")

  @@map("orders")
}

 

 

 

 

 

3. 유저 인증 절차

  1. 사용자자사 홈페이지에 들어와서 로그인을 진행할 때, 구글을 선택함.
  2. 그럼 자사 클라이언트(=브라우저)가 서버(=백엔드)를 거치지 않고, 바로 구글 Oauth 인증 서버로 요청을 보내는데
    이때 자사 서버의 정보(client id = 구글 Oauth 서버에 등록 된 자사 서버 id)와 콜백 url 등을 담아서 보냄
    [ 요청 URL 예시 ]
    GET https://accounts.google.com/o/oauth2/v2/auth
      ?client_id=YOUR_CLIENT_ID : 우리 앱 식별자
      &redirect_uri=https%3A%2F%2Fapi.myapp.com%2Fauth%2Fgoogle%2Fcallback : 인증 끝나면 돌아 올 주소
      &response_type=code : 응답은 코드로 전달 해 달라 요청
      &scope=openid%20email%20profile%20https%3A%2F%2Fhttp://www.googleapis.com%2Fauth%2Fcalendar.readonly : 필요한 권한 범위
      &access_type=offline 
      &prompt=consent
      &state=RANDOM_CSRF_TOKEN

  3. 구글 Oauth 서버가 위 내용을 보고, 사용자가 접속 할 수 있는 "구글 로그인 창"을 클라이언트(=브라우저)에게 보냄
  4. 사용자는 자신의 정보를 입력하고 "로그인"을 누름
  5. 구글 Oauth서버가 "Authorize 코드"를 클라이언트(=브라우저)로 보냄
    [ 응답 URL 예시]
    GET https://api.myapp.com/auth/google/callback
      ?code=4%2F0AbCdEfGhIjKlMn... : Authorization Code
      &state=RANDOM_CSRF_TOKEN
      &scope=openid%20email%20profile%20https%3A%2F%2Fhttp://www.googleapis.com%2Fauth%2Fcalendar.readonly
  6. 클라이언트는 받은 코드로 추가 작업을 할 수 없으므로, 자사 서버(=백엔드)에게 인증 코드(= Authorize 코드)를 줌
    ( = 이 과정이 일상으로 비교 했을 때, 우리가 공공기관 같은데 접속할 때 본인인증 하면 핸드폰으로 인증 번호가 전달 되서, 사람이 공공기관 사이트에 인증번호를 입력하게 됨. "핸드폰=클라이언트"는 필요한 인증번호를 받아주는 역할일 뿐, 결국 그걸 가지고 어떤 시도를 하는건 "사람=서버" 임)
  7. 자사 서버(=백엔드)Authorize 코드와 함께 "자사 서버 인증 정보(client id, secret 등 구글 Oauth에 등록 된 서버의 로그인 정보)" 를 보내서 구글 Oauth에 등록 된 서버임을 증명함.
    [ 요청 URL 예시]
    POST https://oauth2.googleapis.com/token
    Content-Type: application/x-www-form-urlencoded
        code=4%2F0AbCdEfGhIjKlMn...  : Authorization Code
        client_id=YOUR_CLIENT_ID
        client_secret=YOUR_CLIENT_SECRET
        redirect_uri=https://api.myapp.com/auth/google/callback
        grant_type=authorization_code

  8. 구글 Oauth 서버에서는 해당 정보를 확인 한 뒤 권한 영역(scope)과 Access 토큰, 유저 id (id_token) 등을 담아서 자사서버로 보내 줌. 자사 서버(=백엔드)는 받은 정보를 DB에 저장 해 두고, 클라이언트에게는 자사 Access 토큰 / refresh 토큰을 만들어 보내 주면서 접속 성공을 알림
    [ 응답 JSON 예시 ]
    {
      "access_token": "ya29.a0ARrdaM...", : 구글 Oauth Access 토큰
      "expires_in": 3599,
      "refresh_token": "1//0gL... ", : 조건에 따라 보내주거나 생략함
      "scope": "openid email profile https://www.googleapis.com/auth/calendar.readonly",
      "token_type": "Bearer",
      "id_token": "eyJhbGciOiJSUzI1NiIs..." : 구글에서 사용하는 User id
    }

  9. 사용자가 자사 홈페이지를 이용하다가 구글 캘린더에 저장/정보 불러오기 할 일이 생기면 클라이언트 자사에서 생성한  Access 토큰을 사용해 자사 서버(=백엔드)로 요청을 보내면,
    자사 서버(=백엔드)가 클라이언트에게 받은 Access 토큰을 이용해 구글 OAuth Access 토큰 찾음
    (구글 Oauth서버가 보내주면, 로그인 성공 할 때 서버가 DB에 유저 정보와 함께 보관하고 있었음)
  10. 서버에 보관한 구글 Oauth Access 토큰을 가지고 자사 서버(=백엔드)구글 캘린더 서버로 접속 요청을 보냄.
    [ 요청 URL 예시]
    GET https://www.googleapis.com/calendar/v3/calendars/primary/events
    Authorization: Bearer ya29.a0ARrdaM... : 구글 Oauth Access 토큰

  11. 구글 캘린더에서 Access 토큰 검증을 하여 요청 한 내용을 실행!
    [응답 JSON 예시]
    {
      "items": [
        {
          "id": "abc123",
          "summary": "회의",
          "start": { "dateTime": "2025-12-29T10:00:00+09:00" },
          "end":   { "dateTime": "2025-12-29T11:00:00+09:00" }
        }
      ]
    }

OAuth 인증 인가 과정
OAuth 인증 인가 과정


 

다른 팀에 비해 팀원이 조금 적은 편이라 각자의 역할이 중요한데, 

내 실력이 많이 뒤떨어 지는 느낌이 들어서 

휴일과 주말을 반납하고 열심히 공부 했다.. 📖✍️

 

근데도 너무 어려운 유저 인증 절차 😭

아무리 파고 또 파도 그 순간에는 이해 되지만 뒤돌아 서면 리셋 되버리니..

어떡하면 좋아..ㅠㅠ

반응형