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

배경 (Background)

  • 사용자들이 앨범에 있는 사진을 활용하여 피드를 작성하고 수정, 삭제하는 기능을 구현한다.
  • 피드에 댓글을 작성하고 수정, 삭제하는 기능을 구현한다.
  • 사용자가 전체 피드 또는 팔로우한 유저의 피드만 필터링하여 조회하는 기능을 구현한다.

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

  • 피드 신고 기능은 포함하지 않는다.
  • 비공개 피드 기능은 포함하지 않는다

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

ERD

  • 유저

스크린샷 2025-04-27 23 17 27

  • 사진

스크린샷 2025-04-27 23 17 53

  • 앨범

스크린샷 2025-04-27 23 17 57

  • 피드-사진

스크린샷 2025-04-27 23 17 47

  • 피드

스크린샷 2025-04-27 23 17 41

  • 팔로우

스크린샷 2025-04-27 23 17 33

  • 댓글

스크린샷 2025-04-27 23 18 04

API 명세

모든 헤더에는 access token이 필수로 들어갑니다. 토큰 관련 명세는 유저 도메인 테크스펙에 명시했으므로 본 테크스펙에서는 생략합니다.

  • 피드 관련
    • 피드 메인페이지
      • Endpoint
        • 전체 피드 조회 : GET /api/feed?cursor={lastFeedId}
        • 팔로우한 유저 피드 조회 : GET /api/feed/follow?cursor={lastFeedId}
      • 구현상세
        • Request Header
          • Authorization: Bearer <access_token> (필수)
        • Request Parameter
          • cursor (optional, Long) : 마지막으로 조회한 피드 ID
            • null이면 최신 피드부터 조회 시작
            • 존재하면 lastFeedId보다 작은 피드를 조회
        • 처리로직 :
          1. Access token을 기반으로 로그인된 userId를 추출한다.
          2. 요청된 API에 따라 조회 대상 피드를 구분한다.
            • /api/feed : 전체 공개된 피드를 조회
            • /api/feed/follow : 로그인 사용자가 팔로우한 유저들이 작성한 피드를 조회
          3. Cursor(커서) 기반 페이징을 수행한다.
            • cursor가 없으면 최신 피드 기준 내림차순으로 size(10) 조회
            • cursor가 있으면 cursor(피드 ID)보다 작은 feedId를 가진 피드를 내림차순으로 size(10) 조회
          4. 피드 목록을 가공하여 다음 정보를 포함해 반환한다:
            • feedId
            • 썸네일 URL
            • 작성자 닉네임, 프로필 사진
            • 작성 시각 (createdAt)
            • 좋아요 수 (likeCount)
            • 로그인 사용자가 좋아요를 눌렀는지 여부 (isLiked)
          5. hasNext 값을 계산한다.
            • 10개보다 적게 조회되면 hasNext = false
            • 10개 꽉 채워 조회되면 hasNext = true
          6. lastFeedId를 결과에 포함한다.
            • 가장 마지막으로 조회된 feedId를 반환하여 다음 요청의 cursor로 사용
    • 피드 CRUD
      • Endpoint

        • 피드 등록 : POST /api/feed
        • 피드 상세 조회 : GET /api/feed/{feedId}
        • 피드 수정 : PUT /api/feed/{feedId}
        • 피드 삭제 : DELETE /api/feed/{feedId}
      • Request Header

        • Authorization: Bearer <access_token> (필수)
      • Request Body

        • 피드 등록, 수정 시 필요

          {
            "albumId": 1,
            "content": "판교 산책",
            "pictureIds": [101, 102, 103]
          }
          
      • Path Variable

        • feedId (Long, 필수) : 조회/수정/삭제 대상 피드 ID
      • 처리 로직

        1. 피드 등록
          • Access token에서 로그인 사용자의 userId를 파싱한다.
          • 요청받은 albumId, pictureIds를 검증한다.
            • 모든 pictureIdsalbumId에 속하는지 확인
            • 사진 존재 여부 확인
          • 검증이 통과하면 새 Feed를 생성하고 저장한다.
          • 피드 등록 성공 응답을 반환한다.
        2. 피드 상세 조회
          • 요청한 feedId로 Feed를 조회한다.
          • Feed 작성자 정보, 사진 리스트(장소 정보 포함), 좋아요 수, 댓글 수, 로그인 유저의 좋아요 여부를 함께 조회한다.
          • 조회 결과를 반환한다.
        3. 피드 수정
          • 요청한 feedId로 기존 Feed를 조회한다.
          • 로그인한 사용자가 Feed 작성자인지 검증한다.
          • 수정 요청된 albumId, pictureIds를 다시 검증한다.
            • 사진 존재 여부, 앨범 일관성 확인
          • Feed 내용을 수정하고 저장한다.
          • 수정 완료 응답을 반환한다.
        4. 피드 삭제
          • 요청한 feedId로 Feed를 조회한다.
          • 로그인한 사용자가 Feed 작성자인지 검증한다.
          • 삭제를 수행한다 (deletedAt에 timestamp 입력).
          • 삭제 완료 응답을 반환한다.
    • 댓글 CRUD
      • Endpoint

        • 댓글 작성 : POST /api/feed/{feedId}/comment
        • 전체 댓글 조회 : GET /api/feed/{feedId}/comment?cursor={commentId}
        • 특정 댓글 조회 : GET /api/feed/{feedId}/comment/{commentId}
        • 댓글 수정 : PUT /api/feed/{feedId}/comment/{commentId}
        • 댓글 삭제 : DELETE /api/feed/{feedId}/comment/{commentId}
      • Request Header

        • Authorization: Bearer <access_token> (필수)
      • Request Body

        • 댓글 작성, 수정 시 필요

          {
            "content": "댓글 내용입니다."
          }
          
      • Path Variable

        • feedId (Long, 필수) : 피드 ID
        • commentId (Long, optional) : 댓글 ID
      • Request Parameter

        • cursor (optional, Long) : 마지막으로 조회한 댓글 ID (무한스크롤 커서)
      • 처리로직

        1. 댓글 작성
          • Access token에서 로그인 사용자의 userId를 파싱한다.
          • 요청한 feedId에 해당하는 피드 존재 여부를 확인한다.
          • content를 기반으로 새로운 댓글을 생성하여 저장한다.
          • 작성 성공 응답을 반환한다.
        2. 전체 댓글 조회
          • 요청한 feedId에 해당하는 댓글들을 최신순으로 조회한다.
          • cursor가 없으면 최신 댓글부터 조회하고, 있으면 cursor보다 작은 commentId 기준으로 10개 조회한다.
          • 조회된 댓글 리스트, hasNext, lastCommentId를 응답에 포함한다.
        3. 특정 댓글 조회
          • 요청한 feedIdcommentId를 기준으로 댓글을 조회한다.
          • 조회 결과를 반환한다.
        4. 댓글 수정
          • 요청한 commentId를 기준으로 댓글을 조회한다.
          • 로그인 사용자가 해당 댓글 작성자인지 검증한다.
          • 수정하려는 content를 업데이트한 뒤 저장한다.
          • 수정 완료 응답을 반환한다.
        5. 댓글 삭제
          • 요청한 commentId를 기준으로 댓글을 조회한다.
          • 로그인 사용자가 해당 댓글 작성자인지 검증한다.
          • 삭제 처리(soft delete 또는 DB 삭제)를 수행한다.
          • 삭제 완료 응답을 반환한다.
    • 좋아요 등록, 삭제
      • Endpoint
        • 좋아요 등록 : POST /api/feed/{feedId}/like
        • 좋아요 취소 : DELETE /api/feed/{feedId}/like
      • Request Header
        • Authorization: Bearer <access_token> (필수)
      • Path Variable
        • feedId (Long, 필수) : 좋아요를 등록하거나 취소할 피드 ID
      • 처리 로직
        1. 좋아요 등록
          • Access token에서 로그인 사용자의 userId를 파싱한다.
          • 요청한 feedId를 기준으로 피드 존재 여부를 확인한다.
          • 사용자가 해당 피드에 이미 좋아요를 눌렀는지 확인한다.
          • 이미 좋아요가 등록된 경우, 400 에러를 반환한다.
          • 좋아요가 등록되지 않은 상태면, 좋아요를 추가하고 likeCount를 증가시킨다.
          • 성공 응답을 반환한다.
        2. 좋아요 취소
          • Access token에서 로그인 사용자의 userId를 파싱한다.
          • 요청한 feedId를 기준으로 피드 존재 여부를 확인한다.
          • 사용자가 해당 피드에 좋아요를 누른 기록이 있는지 확인한다.
          • 좋아요를 누른 적이 없으면 400 에러를 반환한다.
          • 좋아요를 누른 상태면, 좋아요를 취소하고 likeCount를 감소시킨다.
          • 성공 응답을 반환한다.