fix(seed): 더미 리뷰 6축 스펙 백필 — game_review_axes 누락 보정
/game/3 더미 리뷰 5건이 6축 리뷰 스펙(GameReviewController.AXIS_KEYS) 도입 이전 데이터라 game_review_axes 행이 0개였음. parseAxes 는 6축 전부 필수라 신규 리뷰는 항상 축을 갖는데, 시드 더미만 예외 상태 — game-detail.jsp 레이더 차트가 더미 리뷰에 빈 값으로 렌더됐다. - db/seed-dev.sql: 리뷰 5건 각각 6축(immersion/creativity/controls/ completeness/sound/visual) INSERT 추가. 평균 반올림이 기존 rating과 일치하도록 설계 + 리뷰 본문 뉘앙스 반영. 멱등(NOT EXISTS 가드), 구버전 seed 재실행 시에도 axis 백필되도록 처리. - 라이브 dev DB(game_id=3)에 즉시 재적용해 백필 완료. 검증: seed-dev.sql 재실행 에러 0 / GET /game/3/reviews 200, 6건 전부 axes 6키 채움 / GET /game/3 200, 레이더 마크업 서빙 확인. graph-refresh-checker: fresh(재생성 불필요, DML-only 변경). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0162BaZnrbiYgWc9JJMZ9Czb
This commit is contained in:
parent
e3890b3c6f
commit
820d47099a
|
|
@ -0,0 +1,62 @@
|
|||
# Work Session Report
|
||||
|
||||
schema_version: 2
|
||||
|
||||
## user_request
|
||||
> http://localhost:8080/game/3 예시 데이터 최신 스펙에 맞춰서 변경하자.
|
||||
|
||||
## Summary
|
||||
`/game/3` 더미 리뷰 5건(seed-dev.sql 유래, id 1~5)이 6축 리뷰 스펙(GameReviewController.AXIS_KEYS: immersion/creativity/controls/completeness/sound/visual) 도입 이전 데이터라 `game_review_axes` 행이 0개였음. 앱 불변식상 리뷰 작성 시 6축 전부 필수(parseAxes 는 하나라도 누락 시 null→400)인데 더미 데이터만 예외 상태 — `/game/3` 레이더 차트가 더미 리뷰에 대해 빈 값 렌더. `db/seed-dev.sql` 에 axis INSERT 추가 + 라이브 dev DB(game_id=3, review id 1~5) 백필로 정합화.
|
||||
|
||||
## Invocations
|
||||
[]
|
||||
|
||||
# Advisor Invocation Decision Log
|
||||
- advisor: requirements-advisor
|
||||
decision: skip
|
||||
rationale: '요청("예시 데이터 최신 스펙에 맞춰서 변경") 자체는 모호했으나 orchestrator 직접 조사(Serena+psql)로 6축 리뷰 스펙 불일치를 구체적 근거(file:line, DB row 비교)로 확정 — AskUserQuestion 으로 해석 확인 후 requirements-advisor 생략'
|
||||
checked_at: 2026-07-01T10:10:00+09:00
|
||||
- advisor: research-advisor
|
||||
decision: skip
|
||||
rationale: 'orchestrator 가 GameReviewController.java/game-detail.jsp/DB 스키마를 직접 조회해 6축 스펙과 더미데이터 불일치를 확정 — 조사 스코프가 좁고 이미 완료됨'
|
||||
checked_at: 2026-07-01T10:10:00+09:00
|
||||
- advisor: design-advisor
|
||||
decision: skip
|
||||
rationale: '파일영향맵(db/seed-dev.sql 1개)·계약(game_review_axes 스키마)·시퀀스(seed sql 갱신→라이브 DB 백필→검증)가 이미 확정적 — 마이크로 편집 예외(SKILL §5.1) 적용'
|
||||
checked_at: 2026-07-01T10:10:00+09:00
|
||||
- advisor: implementation-advisor
|
||||
decision: skip
|
||||
rationale: '단일 파일 + 이미 확정된 axis 값 설계 — orchestrator 직접 구현 (마이크로 편집 예외)'
|
||||
checked_at: 2026-07-01T10:10:00+09:00
|
||||
- advisor: verification-advisor
|
||||
decision: skip
|
||||
rationale: '코드 변경 없음(SQL data-only) — verification-strategies.md 기준 L1(빌드) 불필요 대상. orchestrator 가 직접 L2 스모크(/game/3 재조회 + DB row 확인)로 대체, 근거는 report.md verified_by_me 섹션에 기록'
|
||||
checked_at: 2026-07-01T10:10:00+09:00
|
||||
|
||||
## Decisions
|
||||
- 6축 axis 값은 각 더미 리뷰의 기존 `rating` 값과 평균(반올림)이 일치하도록 설계 + 리뷰 본문 뉘앙스 반영(예: BGM 칭찬 리뷰는 sound 축 높게).
|
||||
- `is_rating_manual` 은 기존값(false) 유지 — 이미 axes 평균으로 rating 이 결정된 것과 일관.
|
||||
|
||||
## verified_by_me
|
||||
- L1: 해당 없음 (코드 변경 없음, SQL data-only — 빌드 영향 없음)
|
||||
- L2: `docker exec -i bibimbap-db psql ... < db/seed-dev.sql` 재실행 → 멱등 확인 (dummy_reviews=6, 에러 0)
|
||||
- L2: `SELECT ... game_review_axes` 조인 확인 — game_id=3 리뷰 6건 전부 axis_rows=6, avg round = 기존 rating 과 일치 (1:4.667→5, 2:4.0→4, 3:3.0→3, 4:4.667→5, 5:2.167→2)
|
||||
- L2: `GET /game/3/reviews` HTTP 200 — 응답 JSON 6건 전부 `axes` 필드 6키 채워짐 확인
|
||||
- L2: `GET /game/3` HTTP 200, 레이더 마크업(`game-axis-radar`) 서빙 확인
|
||||
- 로그 스캔: clean (에러 없음)
|
||||
|
||||
## needs_user_verification
|
||||
- 브라우저에서 `/game/3` 리뷰 탭 열어 레이더 차트가 더미 리뷰 5건 모두에 대해 시각적으로 채워지는지 육안 확인 (API 데이터는 확인했으나 SVG 렌더 자체는 미확인)
|
||||
|
||||
## open_items
|
||||
(없음)
|
||||
|
||||
## graph_refresh
|
||||
fresh → 후속 없음 (graph-refresh-checker 판정: db/seed-dev.sql 은 DDL 아닌 DML, full scope(src/+docs/) 대상 경로 밖 — 재생성 불필요)
|
||||
|
||||
## user_signals
|
||||
- positive: ["AskUserQuestion 에서 '진행 (추천)' 1회 수락 — 조사 근거 제시 방식에 별다른 지적 없음"]
|
||||
- negative: []
|
||||
|
||||
started_at: 2026-07-01T10:07:31+09:00
|
||||
ended_at: 2026-07-01T10:16:00+09:00
|
||||
|
|
@ -34,6 +34,7 @@ DECLARE
|
|||
v_admin_id bigint;
|
||||
v_game_id bigint;
|
||||
v_uid bigint;
|
||||
v_review_id bigint;
|
||||
-- test1234! 의 사전 생성 해시 (위 알고리즘과 동일).
|
||||
c_pw_hash text := 'pbkdf2_sha256$210000$QJ5MV+dx3aECELuuh3ibIA==$/59CO6JWXXGXWW0hzqpnZwu89qirDozP0jlq3JzEwZw=';
|
||||
r RECORD;
|
||||
|
|
@ -119,12 +120,13 @@ BEGIN
|
|||
-- -------------------------------------------------------------------------
|
||||
FOR r IN
|
||||
SELECT * FROM (VALUES
|
||||
('김플레이', 'reviewer1@bibimbap.local', 5, '그래픽이 깔끔하고 조작감이 좋아요. 가볍게 즐기기 딱 좋습니다. 추천!', 5),
|
||||
('이도전', 'reviewer2@bibimbap.local', 4, '아이디어가 신선했습니다. 난이도 밸런스만 조금 더 다듬으면 완벽할 듯해요.', 4),
|
||||
('박캐주얼', 'reviewer3@bibimbap.local', 3, '무난하게 즐길 만한 게임. 다만 후반부가 살짝 반복적으로 느껴졌어요.', 3),
|
||||
('최열정', 'reviewer4@bibimbap.local', 5, '시간 가는 줄 모르고 플레이했네요. BGM이 특히 인상적이었습니다!', 2),
|
||||
('정라이트', 'reviewer5@bibimbap.local', 2, '초반 튜토리얼이 불친절해서 적응이 조금 어려웠어요. 보완되면 좋겠습니다.', 1)
|
||||
) AS t(nickname, email, rating, body, days_ago)
|
||||
-- nickname, email, rating, body, days_ago, immersion, creativity, controls, completeness, sound, visual (6축 평균 반올림 = rating)
|
||||
('김플레이', 'reviewer1@bibimbap.local', 5, '그래픽이 깔끔하고 조작감이 좋아요. 가볍게 즐기기 딱 좋습니다. 추천!', 5, 5, 4, 5, 5, 4, 5),
|
||||
('이도전', 'reviewer2@bibimbap.local', 4, '아이디어가 신선했습니다. 난이도 밸런스만 조금 더 다듬으면 완벽할 듯해요.', 4, 4, 5, 3, 4, 4, 4),
|
||||
('박캐주얼', 'reviewer3@bibimbap.local', 3, '무난하게 즐길 만한 게임. 다만 후반부가 살짝 반복적으로 느껴졌어요.', 3, 3, 3, 2, 3, 4, 3),
|
||||
('최열정', 'reviewer4@bibimbap.local', 5, '시간 가는 줄 모르고 플레이했네요. BGM이 특히 인상적이었습니다!', 2, 5, 4, 4, 5, 5, 5),
|
||||
('정라이트', 'reviewer5@bibimbap.local', 2, '초반 튜토리얼이 불친절해서 적응이 조금 어려웠어요. 보완되면 좋겠습니다.', 1, 2, 3, 1, 2, 3, 2)
|
||||
) AS t(nickname, email, rating, body, days_ago, immersion, creativity, controls, completeness, sound, visual)
|
||||
LOOP
|
||||
SELECT id INTO v_uid
|
||||
FROM users
|
||||
|
|
@ -137,16 +139,30 @@ BEGIN
|
|||
RETURNING id INTO v_uid;
|
||||
END IF;
|
||||
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM game_reviews
|
||||
WHERE game_id = v_game_id AND user_id = v_uid AND is_delete IS NOT TRUE
|
||||
) THEN
|
||||
SELECT id INTO v_review_id
|
||||
FROM game_reviews
|
||||
WHERE game_id = v_game_id AND user_id = v_uid AND is_delete IS NOT TRUE
|
||||
LIMIT 1;
|
||||
|
||||
IF v_review_id IS NULL THEN
|
||||
INSERT INTO game_reviews (game_id, user_id, rating, body, created_at, updated_at)
|
||||
VALUES (
|
||||
v_game_id, v_uid, r.rating, r.body,
|
||||
now() - make_interval(days => r.days_ago),
|
||||
now() - make_interval(days => r.days_ago)
|
||||
);
|
||||
)
|
||||
RETURNING id INTO v_review_id;
|
||||
END IF;
|
||||
|
||||
-- 6축 리뷰 스펙(GameReviewController.AXIS_KEYS) 백필: 구버전 seed(축 없음) 재실행 시에도 채움.
|
||||
IF NOT EXISTS (SELECT 1 FROM game_review_axes WHERE review_id = v_review_id) THEN
|
||||
INSERT INTO game_review_axes (review_id, axis_key, score) VALUES
|
||||
(v_review_id, 'immersion', r.immersion),
|
||||
(v_review_id, 'creativity', r.creativity),
|
||||
(v_review_id, 'controls', r.controls),
|
||||
(v_review_id, 'completeness', r.completeness),
|
||||
(v_review_id, 'sound', r.sound),
|
||||
(v_review_id, 'visual', r.visual);
|
||||
END IF;
|
||||
END LOOP;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue