BE 테크스펙(User) - 100-hours-a-week/5-yeosa-wiki GitHub Wiki

배경 (Background)

  • 회원가입과 로그인 기능을 구현하고 유저별 마이페이지와 활동페이지의 테크스펙을 정의한다.
    • 결과 1 : 카카오 OAuth2를 통한 로그인 및 회원가입 기능 구현
    • 결과 2 : 마이페이지와 활동페이지를 통한 개인화된 정보제공
    • 결과 3 : 앨범, 피드 관련 활동에 대한 알림기능 구현

목표가 아닌 것 (Non-goals) (Optional)

  • 회원 탈퇴는 정의하지 않는다.
  • 카카오를 제외한 다른 OAuth는 정의하지 않는다.

설계 및 기술 자료 (Architecture and Technical Documentation)

관련 ERD

  • 유저

    스크린샷 2025-04-26 21 33 31

  • 토큰 관리

    스크린샷 2025-04-26 21 33 52

  • 알림

    스크린샷 2025-04-26 21 33 38


API 명세

  • 로그인
    • 로그인 요청
      • endpoint : /api/auth
      • 구현 상세 :
        • request param 해당없음
        • 처리로직 :
          1. 유저는 서버에 로그인 요청 api를 요청한다.
          2. 해당 유저에게 kakao REST_API_KEY와 REDIRECT_URI가 포함된 헤더를 리턴한다.
          3. 유저는 전달받은 URL로 리다이렉트되어 카카오 로그인을 수행한다.
          4. 카카오 로그인이 성공하면 카카오로부터 authorization_code를 발급받는다.
          5. 발급받은 코드를 서비스 로그인 시 사용한다.
    • 서비스 로그인
      • endpoint = /api/auth/callback?code={authorization_code}
      • 구현 상세
        • request param : authorization_code
        • 처리로직 :
          1. /api/auth 를 통해 리다이렉트된 유저는 카카오 페이지에서 카카오 로그인을 수행한다.
          2. authorization_code를 query string으로 서버에 보낸다.
          3. 서버는 전달받은 코드를 https://kauth.kakao.com/oauth/token 로 보내 토큰 발급 요청을 한다.
          4. 정상적인 코드라면 Access token과 Refresh token과 profile_image를 받는다.
          5. id토큰의 picture(프로필사진)과 sub(유저 아이디), email(유저이메일)을 파싱한다.
            1. 만약 sub가 User 테이블에 이미 있다면 로그인 처리하고, 만약 그렇지 않다면 회원가입 후 로그인 처리 한다.
            2. 로그인 처리는 자체 JWT토큰(access token, refresh token) 발급하여 유저에게 응답으로 전송하며, 서버는 refresh token만을 보관한다.
              1. refresh token 보관 장소는 redis이다.
    • 유저 정보 확인
      • endpoint = /api/user/{userId}
      • 구현상세
        • request header : access token 필수
        • 처리로직 :
          1. 클라이언트가 보유한 access token을 기반으로 로그인된 유저의 정보를 확인한다.
          2. 캐싱하고 있는 유저정보가 만료되면 자동으로 유저정보를 요청하여 갱신한다.
          3. 프로필, 닉네임과 같은 기본정보와 cacheTil과 같은 캐시 유효시간이 포함되어 있다. 이를 사용하여 유저정보를 캐싱한다.
    • 만료 토큰 재발급
      • endpoint = /api/auth/refresh
      • 구현상세
        • request body : refresh token
        • 처리로직
          1. access token이 만료되었을 때 재발급 요청을 한다. 이때 보유하고 있는 refresh token을 서버에 전송한다.
          2. 서버는 refresh token을 redis에 저장된 값과 확인하여 일치하는지 아닌지 확인한다.
          3. 만약 토큰 유효성이 통과된다면 access token을 새로 발급한다.
            1. refresh token이 만료되거나 유효하지 않다면 로그아웃시키고 다시 로그인하게 한다.
  • 마이페이지
    • 유저 사진 수 월별 조회(단위 : 일)
      • endpoint = /api/user/statistics/picture/?yearmonth={yearMonth}
      • 구현상세
        • request param : yearMonth(yyyy-mm)
          • 해당 값은 비어있을 수 있음. 비어있으면 유저가 등록한 모든 사진 수 반환
        • 처리로직
          1. 먼저 header로 전달받는 access token의 userId를 파싱한다.
          2. Picture 테이블에서 userId와 yearMonth와 일치하는 데이터를 조회한다.
          3. 조회한 데이터 수를 일자별로 리턴한다.
        • MVP는 테이블에서 읽는 방식으로 개발하고, v2에서는 redis에 캐싱한다.
    • 유저 방문 장소 조회
      • endpoint = /api/user/statistics/place?yearMonth={yearMonth}
      • 구현상세
        • request param : yearMonth(yyyy-mm)
          • 해당 값은 비어있을 수 있음. 비어있으면 유저가 방문한 모든 장소의 숫자만 반환
        • 처리로직
          1. 먼저 header로 전달받는 access token의 userId를 파싱한다.
          2. Picture 테이블과 Place 테이블을 조인하여 userId별 장소를 yearMonth 조건에 맞추어 조회한다.
          3. 조회한 데이터를 리턴한다.
        • MVP는 테이블에서 읽는 방식으로 개발하고, v2에서는 redis에 캐싱한다.
  • 알림
    • 알림 조회
      • endpoint = /api/notification?cursor={lastNotificationId}
      • 구현상세
        • request param : lastNotificationId
          • null이면 최신 알림부터 조회 시작
        • 처리 로직
          1. 먼저 header로 전달받는 access token의 userId를 파싱한다.
          2. lastNotificationId가 null이면:
            1. userId 기준으로 가장 최근 알림부터 (createdAt 내림차순) size(20) 만큼 조회한다.
            2. lastNotificationId가 존재하면:
              • lastNotificationId보다 작은(id < lastNotificationId) 알림들을
              • userId 기준, createdAt 내림차순으로 size(20) 만큼 조회한다.
          3. 다음 커서를 계산한다.
            1. 조회된 알람 중 가작 마지막 알림의 id를 nextCursor로 지정
            2. 만약 가져온 알림이 20보다 작으면 hasNext=False로 표시한다.
          4. 알림 리스트, nextCursor, hasNext를 포함한 응답을 반환한다.
    • 알림 읽음
      • endpoint = /api/notification/{notificationId}/status
      • 구현상세
        • request param : notificationId
        • 처리 로직
          1. 먼저 header로 전달받는 access token의 userId를 파싱한다.
          2. userId에 해당하는 notificationId를 조회한다.
          3. 해당 알림의 is_read를 true로 변경한다.
          4. 알림 읽음 처리 성공 응답을 반환한다.

사용 기술 (Optional)

💡

🤔 이 섹션은 왜 필요한가요?

  • 설계 및 기술자료에서 구현하는데 추가적으로 필요한 기술들을 명시합니다.

이외 고려사항들 (Other Considerations) (Optional)

💡

🤔 이 섹션은 왜 필요한가요?

  • 주요 설계 외에 추가적으로 고민했거나, 특별히 주의해야 할 점, 혹은 내린 결정의 배경 등을 기록합니다.
  • 성능, 보안, 확장성, 장애 대응 등 다양한 측면에서의 고려사항을 담을 수 있습니다.

함께 논의하고 싶은 내용 (Open Questions) (Optional)

💡

🤔 이 섹션은 왜 필요한가요?

  • 설계나 구현 과정에서 아직 결정되지 않았거나, 다른 팀/동료의 의견이 필요한 부분을 명시합니다.
  • 협업을 촉진하고, 기술적인 결정에 대한 합의를 이끌어내는 데 도움을 줍니다.

용어 정의 (Glossary) (Optional)

💡

🤔 이 섹션은 왜 필요한가요?

  • 프로젝트 내에서 사용되는 특정 용어, 약어, 상태 값 등의 의미를 명확히 정의합니다.
  • 팀원 간의 오해를 줄이고 원활한 의사소통을 돕습니다.
⚠️ **GitHub.com Fallback** ⚠️