| kind |
title |
session_id |
created_at |
status |
related_security_checklist |
related_work_log |
related_design |
| change |
W3-2 댓글/리뷰 분리 구현 |
20260618-104034 |
2026-06-18 |
implemented |
../security/security-remediation-checklist.md |
../work-log/2026-06-17-w3-feature-skeletons.md |
../../.atp/work-session/20260618-104034/design.md |
W3-2 댓글/리뷰 분리 구현 변경 이력
상위 골자: W3 사이트 플랫폼 기능 골자 카탈로그 §W3-2.
개요
기존 game_comments(닉네임 자유입력, localStorage 전용)를 서버 영속화 + 로그인 연동으로 전환하고,
별점 5점 + 서술 평가 형태의 game_reviews 도메인을 신설했다.
변경된 런타임 동작
1. 댓글 서버 영속화 전환
- 이전: 댓글이
localStorage에만 저장. game_comments 매퍼·테이블은 고아 상태.
- 이후: 댓글이 서버 DB
game_comments에 영속. 새로고침·브라우저 변경 후에도 유지.
- 기존 localStorage 댓글은 마이그레이션하지 않음(보안 [hold] 정합 — QG-2 결정).
game_comments.user_id bigint NULL FK 추가(비파괴, 레거시 nickname 레코드 보존).
- content 200자 앱레벨 검증 신규 적용(이전: 길이 제한 없음).
2. game_reviews 도메인 신설
- 신규 테이블
game_reviews: 게임당 1회 제한(partial UNIQUE WHERE is_delete IS NOT TRUE), rating smallint CHECK(1~5), body text.
- "수정됨" 상태: in-row(updated_at > created_at). 별도 이력 테이블 없음(열람 권한 확정 시 후속).
- 삭제: soft-delete(is_delete, deleted_at).
3. 권한 모델
- 댓글/리뷰 수정·삭제: 작성자 본인(
sessionUserId == 리소스.userId) OR 운영자(ROLE_ADMIN="ADMIN").
- 운영자 role 부여 경로는 W1 RBAC 연결 시 활성(현재 휴면 — 부여자 없음).
- 로그인 없는 쓰기 시도: 401.
- CSRF 토큰 없는 상태 변경: 403.
4. 게임 삭제 cascade 확장
GameController.deleteGame에 softDeleteGameReviews 추가.
- 게임 삭제 시 관련 리뷰도 soft-delete.
신규/변경 파일
신규 파일 (백엔드)
| 파일 |
설명 |
src/.../data/GameReviewData.java |
리뷰 도메인 POJO |
src/.../mapper/GameReviewsMapper.java |
리뷰 MyBatis 매퍼 |
src/.../controller/api/GameCommentController.java |
댓글 CRUD API (C1~C4) |
src/.../controller/api/GameReviewController.java |
리뷰 CRUD API (R1~R5) |
docs/game-reviews-ddl.sql |
권위 DDL (멱등 ALTER, 기존 DB 적용용) |
src/test/.../GameCommentControllerTest.java |
댓글 컨트롤러 단위 테스트 12건 |
src/test/.../GameReviewControllerTest.java |
리뷰 컨트롤러 단위 테스트 13건 |
변경 파일
| 파일 |
변경 내용 |
src/.../data/GameCommentData.java |
userId 필드 추가 |
src/.../mapper/GameCommentsMapper.java |
user_id 기반 쿼리 확장 |
src/.../mapper/GamesMapper.java |
softDeleteGameReviews 추가 |
src/.../controller/api/GameController.java |
deleteGame cascade 확장, currentUserId/userRole 모델 노출 |
db/schema.sql |
game_reviews CREATE + game_comments user_id ALTER |
src/main/webapp/WEB-INF/views/game-detail.jsp |
댓글 localStorage→서버 fetch 교체, 리뷰 UI 신규(별점 위젯·수정됨 마커·게임당1회·로그인 게이트) |
src/test/.../BibimbapApplicationTests.java |
GameCommentsMapper/GameReviewsMapper @MockBean 2개 추가 |
신규 API 9개
| ID |
메서드 |
경로 |
설명 |
| C1 |
GET |
/game/{id}/comments |
댓글 목록 조회 |
| C2 |
POST |
/game/{id}/comments |
댓글 작성 (CSRF·로그인·200자 검증) |
| C3 |
PUT |
/game/{id}/comments/{commentId} |
댓글 수정 (작성자/운영자) |
| C4 |
DELETE |
/game/{id}/comments/{commentId} |
댓글 삭제 (작성자/운영자) |
리뷰 (GameReviewController)
| ID |
메서드 |
경로 |
설명 |
| R1 |
GET |
/game/{id}/reviews |
리뷰 목록 조회 |
| R2 |
GET |
/game/{id}/reviews/{reviewId} |
리뷰 단건 조회 |
| R3 |
POST |
/game/{id}/reviews |
리뷰 작성 (게임당 1회, CSRF·로그인·rating 검증) |
| R4 |
PUT |
/game/{id}/reviews/{reviewId} |
리뷰 수정 (수정됨 마커, 작성자/운영자) |
| R5 |
DELETE |
/game/{id}/reviews/{reviewId} |
리뷰 삭제 (soft-delete, 작성자/운영자) |
모든 상태 변경 API 공통 시퀀스: @Transactional → CsrfTokens.isValid (403) → sessionUserId (401) → 검증 (400) → mapper → JSON.
범위 밖 (미변경)
- 좋아요: 여전히 localStorage 전용. 보안 체크리스트 B3 좋아요 항목 별도 관리.
- 운영자 role 부여: ROLE_ADMIN 상수 정의만. 실제 부여 경로는 W1 RBAC 연결 시.
- W2-3 집계 계약: game_reviews가 평점 공급원(rating 컬럼)까지만. AVG/COUNT 집계·뷰 미생성(W2-6 시상 후속).
- 리뷰 이력 열람: in-row 수정됨 마커만. 이력 테이블은 열람 권한 확정 시 후속.
검증 결과 요약
| 레이어 |
결과 |
| L1 단위 테스트 (31건) |
PASS (GameCommentControllerTest 12 + GameReviewControllerTest 13 + UserControllerCsrfTest 5 + BibimbapApplicationTests 1) |
| AGG-1 엔드포인트 수 |
PASS (Comment 4, Review 5) |
| AGG-3 CSRF 게이트 |
PASS (합산 6개) |
| AGG-2 DDL 3종 |
PASS |
| L3 브라우저 스모크 |
needs_user_verification |
| DDL 적용 |
needs_user_verification (docs/game-reviews-ddl.sql 참조) |
이월 항목
- W2-3 평점 집계 계약 (SELECT AVG/COUNT) — W2-6 시상 후속.
- 운영자 role 부여 경로 — W1 RBAC/Interceptor 연결 시 활성.
- 다축(육각형) 평점 — 현재 단일 rating, game_review_axes 분리 여지(주석).
- 리뷰 이력 열람 권한 — 열람 정책 확정 시 별도 이력 테이블.
- GameCatalog 정적 폴백 게임 대상 댓글/리뷰 — DB 실제 게임만 기능 동작(폴백은 404).