도서 리뷰 작성·조회·댓글·좋아요·태그·통계 관리를 담당하는 독서 게이미피케이션 플랫폼 Frolog의 리뷰 도메인 서비스입니다.
도서별 리뷰 CRUD, 대댓글 지원 댓글 시스템, 좋아요 추적, 긍정/부정 태그, 평점 및 통계 집계, 독서 완료 상태 변경을 처리합니다.
- 리뷰 생성·수정·삭제 (도서 ISBN 연동, 평점 0-5)
- 리뷰 검색·조회 (ISBN/작성자 필터, 페이지네이션)
- 리뷰 좋아요/좋아요 취소 (upsert 패턴)
- 태그 시스템 (긍정/부정 태그, 차등 업데이트)
- 댓글 생성·수정·삭제 (대댓글 지원, depth=0/1)
- 댓글 검색·조회 (리뷰별, 작성자별, 부모 댓글별)
- 댓글 좋아요/좋아요 취소
- 멘션 기능 (mention_id)
- 리뷰 통계 자동 집계 (평균 평점, 리뷰 수, 태그 Top 4)
- 독서 완료 상태 변경 (well-service 연동)
- 리뷰 삭제 시 연관 우물 아이템·메모 삭제
- Feed 서비스 연동 (리뷰 생성 시 피드 등록)
- Node.js (ESM), Express 기반
@frolog/express-api-server - ORM: Sequelize (
@frolog/models) - 공통 유틸:
@frolog/common-utils(로거, HashId 등) - API 계약:
@frolog/frolog-api - Lint/Format: ESLint, Prettier
npm install
npm run dev # 개발 (nodemon)
npm start # 프로덕션
npm run lint # 코드 규칙 검사
npm run doc # JSDoc 생성src/
index.js # API 서버 부트스트랩 및 라우팅
services/
postReview.js # 리뷰 생성 (태그 적용, 통계 업데이트, 완료 상태 변경, feed 등록)
getReview.js # 리뷰 단건 조회 (좋아요/ 댓글 수 포함)
editReview.js # 리뷰 수정 (태그 재적용, 통계 업데이트)
deleteReview.js # 리뷰 삭제 (소프트 삭제, 우물 아이템·메모 삭제)
searchReview.js # 리뷰 검색 (ISBN/작성자 필터, 페이지네이션)
likeReview.js # 리뷰 좋아요/취소 (upsert)
updateReviewTag.js # 태그 차등 업데이트 (긍정/부정 태그)
updateReviewStat.js # 리뷰 통계 집계 (평균 평 점, 리뷰 수, 태그 Top 4)
postReviewComment.js # 댓글 생성 (대댓글 지원, depth=0/1)
getReviewComment.js # 댓글 단건 조회 (첫 답글 샘플 포함)
editReviewComment.js # 댓글 수정 (소유자 전용)
deleteReviewComment.js # 댓글 삭제 (소프트 삭제)
searchReviewComment.js # 댓글 검색 (리뷰별, 작성 자별, 정렬)
likeReviewComment.js # 댓글 좋아요/취소 (upsert)src/index.js에서 @frolog/frolog-api 스펙과 서비스 로직을 매핑합니다.
리뷰:
- GET: SearchReview (공개), GetReview (공개)
- POST: PostReview (login), LikeReview (login)
- PATCH: EditReview (login)
- DELETE: DeleteReview (login)
댓글:
- GET: SearchReviewComment (공개), GetReviewComment (공개)
- POST: PostReviewComment (login), LikeReviewComment (login)
- PATCH: EditReviewComment (login)
- DELETE: DeleteReviewComment (login)
없음. 리뷰 통계는 리뷰 생성·수정·삭제 시 동기적으로 업데이트됩니다.
- SearchReview, GetReview, SearchReviewComment, GetReviewComment: 공개 API (인증 불필요)
- 나머지 엔드포인트: 로그인 필수 (소유자/관리자 권한 검증)
- 소유자 검증: 리뷰/댓글 수정·삭제 시 writer_id 일치 확인
- HashId 인코딩: 모든 ID는 해시 형식으로 처리
리뷰 생성 (PostReview)
- 평점 검증 (0-5)
- 기존 리뷰 카운트 조회 (variant 계산, 재독 지원)
- 리뷰 레코드 생성 (writer_id, isbn, variant, title, content, rating)
- 긍정/부정 태그 적용 (updateReviewTag)
- 리뷰 통계 업데이트 (updateReviewStat)
- 우물 아이템 상태 "완료" 변경 (ChangeWellItemStatus)
- Feed 서비스에 피드 등록 (PostFeedContent)
- 인코딩된 리뷰 ID 반환
리뷰 조회 (GetReview / SearchReview)
- 단건 조회: 좋아요 상태, 총 좋아요 수, 댓글 수 포함
- 검색: ISBN/작성자 필터, 페이지네이션 (limit 1-100, 기본 값 10), 최신순 정렬
리뷰 수정 (EditReview)
- 소유자/관리자 확인
- 부분 업데이트 (title, content, rating, tags)
- 태그 재적용 (차등 업데이트)
- 리뷰 통계 재계산
리뷰 삭제 (DeleteReview)
- 소프트 삭제 (deleted_at 설정)
- 연관 우물 아이템 삭제 (SearchWell, DeleteWellItem)
- 연관 메모 삭제 (SearchMemo, DeleteMemo)
- 리뷰 통계 재계산
태그 적용 (UpdateReviewTag)
- 긍정 태그 (tags_pos): 장점 표시
- 부정 태그 (tags_neg): 단점 표시
- 차등 업데이트: 기존 태그와 비교하여 추가/삭제 태그 식별
- ReviewTag 테이블: review_id, tag_id 조인 테이블
- Tag 테이블: tag_key로 태그 조회
통계 집계 (UpdateReviewStat)
- ReviewStat 테이블: ISBN별 통계 저장
- 계산 메트릭: a. 리뷰 수: 삭제되지 않은 리뷰 총 개수 b. 평균 평점: 작성자별 평균 → 전체 평균 (2단계 집계) c. 긍정 태그 Top 4: 빈도순 상위 4개 d. 부정 태그 Top 4: 빈도순 상위 4개
SQL 집계 쿼리 -- 작성자별 평균 평점 → 전체 평균 SELECT AVG(writer_avg) FROM ( SELECT AVG(rating) AS writer_avg FROM reviews WHERE book_isbn = :isbn AND deleted_at IS NULL GROUP BY writer_id )
-- 태그 빈도 Top 4 SELECT tag_id, tag_key, COUNT(*) as tag_count FROM review_tags WHERE book_isbn = :isbn GROUP BY tag_id ORDER BY tag_count DESC LIMIT 4
구조
- depth=0: 루트 댓글
- depth=1: 대댓글 (parent_id 참조)
- mention_id: 언급된 사용자 ID (멘션 기능)
제약사항
- 최대 depth=1 (2단계만 지원)
- 댓글에는 대댓글만 가능 (3단계 이상 X)
조회
- 루트 댓글 조회 시 첫 번째 답글 샘플 포함 (하드코딩: limit 1)
- 답글 카운트 집계
- 좋아요 수 및 사용자 좋아요 상태 포함
소프트 삭제
- deleted_at 타임스탬프 설정
- 삭제된 댓글은 "deleted" 텍스트로 표시
- 물리적 삭제하지 않음
Review
- review_id (PK), writer_id (FK), book_isbn (FK)
- variant (재독 횟수), title, content, rating (0-5)
- tags_pos (긍정 태그 배열), tags_neg (부정 태그 배열)
- created_at, updated_at, deleted_at
ReviewComment
- comment_id (PK), review_id (FK), writer_id (FK)
- parent_id (FK, 대댓글용), mention_id (FK, 멘션용)
- content, depth (0 또는 1)
- created_at, updated_at, deleted_at
ReviewLike
- review_id (FK), user_id (FK) - 복합 PK
- value (boolean, true=좋아요, false=좋아요 취소)
ReviewCommentLike
- comment_id (FK), user_id (FK) - 복합 PK
- value (boolean)
ReviewTag
- review_id (FK), tag_id (FK) - 복합 PK
- book_isbn (FK, 통계용)
Tag
- tag_id (PK), tag_key (unique)
ReviewStat
- book_isbn (PK), review_cnt, avg_rating
- tags_pos (긍정 태그 Top 4 배열), tags_neg (부정 태그 Top 4 배열)
- Feed Service: 리뷰 생성 시 PostFeedContent 호출
- Well Service: 독서 완료 상태 변경 (ChangeWellItemStatus), 우물 아이템 삭제 (SearchWell, SearchWellItem, DeleteWellItem)
- Memo Service: 리뷰 삭제 시 연관 메모 삭제 (SearchMemo, DeleteMemo)
- SSC_TOKEN: 서비스 간 인증 토큰