docs(game): game_likes UNIQUE 제약 dev DB 적용 완료 반영

중복 0 점검 후 ALTER TABLE ADD CONSTRAINT uq_game_likes_game_user UNIQUE(game_id,user_key)
를 dev DB(bibimbap-db/schema dev)에 적용, pg_constraint 검증. B3 체크리스트 [~]→[x].
별도 prod DB 는 배포 시 동일 마이그레이션 적용 필요.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K3FeMrbtxfTScjrwUukyHD
This commit is contained in:
이정수 2026-06-29 17:42:46 +09:00
parent ee9487e118
commit 4c16d16dd9
2 changed files with 3 additions and 3 deletions

View File

@ -61,7 +61,7 @@
## 잔여 / 미수행 (needs_user_verification) ## 잔여 / 미수행 (needs_user_verification)
- UNIQUE 마이그레이션(`db/migrations/20260629-game-likes-unique.sql`) 운영 적용 미수행 — 중복 점검 후 적용 게이트 대기. (로컬 dev DB 볼륨은 기존 init 이라 `schema.sql` 의 UNIQUE 변경도 미반영 — 앱레벨 멱등 토글로 기본 동작엔 무관.) - ~~UNIQUE 마이그레이션 운영 적용 미수행~~**dev DB 적용 완료 (2026-06-29, `bibimbap-db`/schema `dev`)**: 중복 점검 0건 확인 후 `ALTER TABLE game_likes ADD CONSTRAINT uq_game_likes_game_user UNIQUE (game_id, user_key)`. `pg_constraint` 검증 완료. (별도 prod DB 가 있으면 배포 시 동일 마이그레이션 적용 필요 — `db/migrations/20260629-game-likes-unique.sql`.)
- 상세 초기 `aria-pressed` 상태(AC-7) 정밀 수동 확인은 선택(좋아요 반영 핵심 동작은 스모크로 확인됨). - 상세 초기 `aria-pressed` 상태(AC-7) 정밀 수동 확인은 선택(좋아요 반영 핵심 동작은 스모크로 확인됨).
- L2 dev DB contract: PostgreSQL dev 기동 후 mapper SQL 실DB 동작 확인. - L2 dev DB contract: PostgreSQL dev 기동 후 mapper SQL 실DB 동작 확인.
- 기존 `like_count` 컬럼값과 `game_likes` row 수 초기 불일치는 보존(±1 상대 증감, 절대 재계산은 비목표). 선택적 정합 보정 쿼리는 설계 문서 롤아웃 §3 참조. - 기존 `like_count` 컬럼값과 `game_likes` row 수 초기 불일치는 보존(±1 상대 증감, 절대 재계산은 비목표). 선택적 정합 보정 쿼리는 설계 문서 롤아웃 §3 참조.

View File

@ -15,7 +15,7 @@
| --- | --- | --- | --- | | --- | --- | --- | --- |
| B1 | P1 | login/signup CSRF 검증 추가 | MED, 완료 | | B1 | P1 | login/signup CSRF 검증 추가 | MED, 완료 |
| B2 | P2 | 프로토타입 dead code 제거 | LOW-MED | | B2 | P2 | 프로토타입 dead code 제거 | LOW-MED |
| B3 | P2 | 좋아요/댓글 서버 영속화 연결 | MED, 기능 무결성. 댓글 완료(W3-2) + 좋아요 완료(20260629-151216, 실환경 스모크 PASS 20260629-171042, UNIQUE 마이그레이션 운영 적용 대기) | | B3 | P2 | 좋아요/댓글 서버 영속화 연결 | MED, 기능 무결성. 댓글 완료(W3-2) + 좋아요 완료(20260629-151216, 실환경 스모크 PASS + UNIQUE 제약 dev DB 적용 20260629-171042) |
| B4 | P2 | 의존성/세션/운영 하드닝 | MED | | B4 | P2 | 의존성/세션/운영 하드닝 | MED |
## B1. login/signup CSRF 검증 추가 (MED) ## B1. login/signup CSRF 검증 추가 (MED)
@ -103,7 +103,7 @@
- [x] `POST /game/{id}/like` 또는 `/api/games/{id}/like` 엔드포인트를 설계한다. → **`POST /game/{id}/like` 토글(@Transactional). 게이트 CSRF(403)→로그인(401)→존재(404).** - [x] `POST /game/{id}/like` 또는 `/api/games/{id}/like` 엔드포인트를 설계한다. → **`POST /game/{id}/like` 토글(@Transactional). 게이트 CSRF(403)→로그인(401)→존재(404).**
- [x] 좋아요 추가/취소는 CSRF 검증을 적용한다. → **`CsrfTokens.isValid(request)` 선행(403). 회귀 테스트 AC-4 PASS.** - [x] 좋아요 추가/취소는 CSRF 검증을 적용한다. → **`CsrfTokens.isValid(request)` 선행(403). 회귀 테스트 AC-4 PASS.**
- [~] `game_likes` 중복 방지 키를 DB 또는 트랜잭션에서 보장한다. → **애플리케이션 레벨 select-then-act + 단일 트랜잭션으로 1차 방어. DB UNIQUE(game_id,user_key) 제약은 `db/schema.sql` 반영 + `db/migrations/20260629-game-likes-unique.sql` 신규, 운영 DB 미적용(중복 점검 후 적용 게이트 — [maintenance/post-deploy-verification-checklist.md](../maintenance/post-deploy-verification-checklist.md)).** - [x] `game_likes` 중복 방지 키를 DB 또는 트랜잭션에서 보장한다. → **애플리케이션 레벨 select-then-act + 단일 트랜잭션 1차 방어 + DB UNIQUE(game_id,user_key) 제약 2차 방어. `db/schema.sql` 반영 + `db/migrations/20260629-game-likes-unique.sql`. dev DB 적용 완료(2026-06-29, 중복 0 점검 후 ALTER, `pg_constraint` 검증). 별도 prod DB 배포 시 동일 마이그레이션 적용.**
- [x] `games.like_count` 증감은 race condition 없이 처리한다. → **`incrementLikeCount`(`SET like_count = like_count + 1`)/`decrementLikeCount`(`GREATEST(like_count - 1, 0)`) DB 원자 UPDATE + row 변경과 동일 `@Transactional` 단위. 클라이언트 ±1 추정 제거(토글 직후 컬럼 재조회 응답).** - [x] `games.like_count` 증감은 race condition 없이 처리한다. → **`incrementLikeCount`(`SET like_count = like_count + 1`)/`decrementLikeCount`(`GREATEST(like_count - 1, 0)`) DB 원자 UPDATE + row 변경과 동일 `@Transactional` 단위. 클라이언트 ±1 추정 제거(토글 직후 컬럼 재조회 응답).**
- [x] `GET /game/{id}/comments` 또는 상세 모델 주입 방식을 결정한다. → **초기 모델 주입 가능 + 별도 GET C1(`GET /game/{id}/comments`) fetch 방식 채택.** GameCommentController C1 구현 완료(20260618-104034). - [x] `GET /game/{id}/comments` 또는 상세 모델 주입 방식을 결정한다. → **초기 모델 주입 가능 + 별도 GET C1(`GET /game/{id}/comments`) fetch 방식 채택.** GameCommentController C1 구현 완료(20260618-104034).
- [x] `POST /game/{id}/comments`는 CSRF, 길이 제한, 작성자 정책을 적용한다. → **C2 `POST /game/{id}/comments`: CsrfTokens.isValid(403), content 200자(400), 로그인(401) 적용.** L1 12건 PASS(20260618-104034). - [x] `POST /game/{id}/comments`는 CSRF, 길이 제한, 작성자 정책을 적용한다. → **C2 `POST /game/{id}/comments`: CsrfTokens.isValid(403), content 200자(400), 로그인(401) 적용.** L1 12건 PASS(20260618-104034).