225 lines
16 KiB
Markdown
225 lines
16 KiB
Markdown
---
|
|
schema_version: 2
|
|
sid: 20260618-121419
|
|
started_at: 2026-06-18T12:14:19+09:00
|
|
ended_at: 2026-06-18T13:05:00+09:00
|
|
applied_changes:
|
|
- "Serena memory 기록: bibimbap-auth-pbkdf2-not-bcrypt (수용, signal=observation)"
|
|
- "Serena memory 기록: bibimbap-dev-seed-blueprint (수용, FK순서+active-unique 통합)"
|
|
- "Serena memory 기록: java-crypto-verify-via-jdk-container-when-no-host-jdk (수용, signal=positive)"
|
|
- "docs_sync 보류: CLAUDE.md / verification-strategies.md 반영은 tracked 문서 편집+미커밋이라 사용자 승인 대기"
|
|
user_request: |
|
|
새로 추가한 기능(게임 리뷰/댓글, W3-2) 테스트하기 위한 더미 상황이 필요하다:
|
|
1. 게임 (dummy game)
|
|
2. 계정 (dummy account, 로그인 가능)
|
|
3. 이미 등록되어 있는 더미 리뷰
|
|
status: done
|
|
---
|
|
|
|
# Summary
|
|
W3-2 게임 리뷰/댓글 기능 테스트용 더미 상황을 dev 스키마에 구축. 멱등 seed SQL
|
|
(`db/seed-dev.sql`) + 정리 SQL(`db/seed-dev-teardown.sql`) 작성 후 가동중 컨테이너
|
|
(bibimbap-db)에 적용. 구성: 로그인 가능 테스트 계정 1개(tester@bibimbap.local /
|
|
test1234!), 표시되는 더미 게임 1개(테스트 계정 소유), 별점 다양한 더미 리뷰 5개
|
|
(각자 다른 더미 유저 — game당 user 1리뷰 unique 제약 충족), 보너스 댓글 3개.
|
|
로그인 계정은 해당 게임에 리뷰가 없어 "직접 작성" 테스트도 가능.
|
|
|
|
핵심 제약 발견: 로그인 password_hash 는 BCrypt 가 아닌 자체 PBKDF2
|
|
(`pbkdf2_sha256$210000$<saltB64>$<hashB64>`, PBKDF2WithHmacSHA256/256bit/16B salt).
|
|
저장 해시가 실제 Java `UserController.verifyPassword` 경로로 검증됨을 JDK 컨테이너에서
|
|
교차 실행 확인(verify('test1234!')=true, 오답=false) → 로그인 동작 보장.
|
|
|
|
# Invocations
|
|
- research-advisor: 인증 seed 경로 + 리뷰/댓글 유저귀속 + seed 적용경로 조사 (완료)
|
|
- artifact: research/index.md (file:line 근거 포함). 결론 = orchestrator 독립 조사와 일치.
|
|
- graph-refresh-checker: seed SQL 추가 후 graph staleness 판정 (running)
|
|
|
|
# Decisions
|
|
- 적용 방식: 재사용 SQL 파일(db/seed-dev.sql) + 즉시 적용. (사용자 선택, 추천값)
|
|
- 로그인 자격: 기본값 tester@bibimbap.local / test1234! / 닉네임 '테스터'. (사용자 선택)
|
|
- 규모: 게임 1 + 리뷰 5(별점 5/4/3/5/2). (사용자 선택)
|
|
- 설계: 리뷰어는 별도 더미 유저 5명(unique 제약 game당 user 1리뷰 때문). 로그인 계정은
|
|
그 게임에 리뷰 없음(작성 테스트 가능). 게임 소유자 = 로그인 계정(getGamesByUserId 도 테스트).
|
|
- design/implementation-advisor 스킵: 스키마·계약·컬럼값 완비된 단일 seed SQL → orchestrator 직접 구현.
|
|
- 댓글 3개 보너스 포함: 신규 기능이 리뷰/댓글 동시 배치라 같은 더미 상황에 포함이 합리적.
|
|
|
|
# Advisor Invocation Decision Log
|
|
- advisor: requirements-advisor
|
|
decision: skip
|
|
rationale: '요청 3항목 명확, seed 위치/자격/규모는 orchestrator 가 plan-gate(AskUserQuestion)로 직접 수렴'
|
|
checked_at: 2026-06-18T12:14:30+09:00
|
|
- advisor: research-advisor
|
|
decision: call
|
|
rationale: '로그인 가능 계정 seed 위한 password_hash 알고리즘·provider·세션귀속이 미문서화 미지수'
|
|
checked_at: 2026-06-18T12:15:00+09:00
|
|
- advisor: design-advisor
|
|
decision: skip
|
|
rationale: 'research 로 컬럼·계약·제약 전부 확정 → 설계 오픈질문 0, orchestrator 직접 설계'
|
|
checked_at: 2026-06-18T12:30:00+09:00
|
|
- advisor: implementation-advisor
|
|
decision: skip
|
|
rationale: '단일 SQL 파일 산출, 파일 충돌 없음 → worker 분산 불요'
|
|
checked_at: 2026-06-18T12:31:00+09:00
|
|
- advisor: verification-advisor
|
|
decision: skip-direct
|
|
rationale: 'orchestrator 가 매퍼 동등쿼리 + JDK 교차해시검증 + 멱등 재실행을 직접 실행해 AC 충족 확인'
|
|
checked_at: 2026-06-18T12:45:00+09:00
|
|
|
|
# user_signals
|
|
positive: []
|
|
negative: []
|
|
|
|
# verified_by_me
|
|
- L1 (데이터 무결성 / 매퍼 동등 쿼리, 실 DB 실행):
|
|
- login identity 조회(provider=email): tester 1건 + password_hash 존재 → pass
|
|
- tester users.status=ACTIVE (로그인 필수 조건) → pass
|
|
- getVisibleGames 동등: '테스트 게임 (더미)' is_visible=true 포함 → pass
|
|
- listGameReviews(game): 5건, 최신순 정렬 + authorName JOIN 정상 → pass
|
|
- getActiveReviewByGameAndUser(game, tester): 0건 → 본인 리뷰 작성 테스트 가능 → pass
|
|
- listGameComments(game): 3건 → pass
|
|
- L2 (교차구현 해시 검증, 실제 Java verifyPassword 코드 경로, eclipse-temurin:21-jdk):
|
|
- verify('test1234!', 저장해시) = true → 로그인 성공 보장
|
|
- verify('wrongpass', 저장해시) = false → 음성 케이스 정상
|
|
- 멱등성: seed-dev.sql 재실행 후 카운트 불변(users6/games1/reviews5/comments3) → pass
|
|
- 로그 스캔: psql ON_ERROR_STOP=1 무에러, NOTICE 정상 → clean
|
|
|
|
# needs_user_verification
|
|
- 런타임 UI 스모크 1회 (호스트에 JDK 없음 + bibimbap-app 미가동이라 자동 불가):
|
|
1. `docker compose up --build` (또는 호스트 실행) 으로 앱 기동
|
|
2. tester@bibimbap.local / test1234! 로 로그인 → 성공 확인
|
|
3. '테스트 게임 (더미)' 상세 진입 → 기존 리뷰 5건 + 댓글 3건 표시 확인
|
|
4. 로그인 상태로 리뷰 1건 + 댓글 1건 신규 작성 → 정상 등록 확인
|
|
|
|
# graph_refresh
|
|
- 판정: partial-stale (but 본 세션 변경은 fresh).
|
|
- 본 세션 변경(db/seed-dev.sql, seed-dev-teardown.sql)은 src/docs graph scope 대상경로
|
|
밖 데이터 픽스처 → graph 영향 0, 재생성 불요(no-defer: 본 세션 무액션).
|
|
- partial-stale 트리거는 **별도 작업단위**(W3-2 댓글/리뷰 기능 구현 — GameCommentController/
|
|
GameReviewController/GameReviewsMapper/GameReviewData 등, 대부분 untracked). 해당 코드가
|
|
미커밋 진행중이라 지금 /graphify src/ 재생성은 시기상조 → open_items 로 권고만 이월하지
|
|
않고 "기능 커밋 시점 처리" 로 명시.
|
|
|
|
# post-session-debug (로그인 server error 후속)
|
|
- 사용자 보고 "로그인 시 server error(500)". 진단 결과:
|
|
- 원인 = **stale 앱 인스턴스**(pid 59109, 6/17 14:36 기동, 최근 auth 수정 이전 빌드).
|
|
내 seed 가 tester 계정을 만들어 처음으로 "계정 존재" 상태 로그인 경로를 타며 표면화.
|
|
- 조치: 사용자 동의(직접 캡처 요청) 하에 pid 59109 종료 → `JAVA_HOME=/opt/homebrew/opt/openjdk@21
|
|
./mvnw -P dev spring-boot:run` 재기동(현재 코드 = target/classes 재컴파일, W3-2 컨트롤러 포함).
|
|
로그: /tmp/bibimbap-app.log. 신규 pid 23318 (백그라운드).
|
|
- 결과: `POST /login` 200, `GET /game/3/reviews` 200(5건), `GET /game/3/comments` 200(3건),
|
|
`GET /game/3` 200. 더미 상황 런타임 정상. → needs_user_verification 의 UI 스모크 사실상 완료.
|
|
- **발견 버그 (별도 작업단위 = W3-2 댓글기능, 내 seed 무관)**: 댓글 목록 author 항상 null.
|
|
- 근거: GameCommentsMapper.listGameComments 가 `nickname AS authorName` 로 alias →
|
|
결과 컬럼 `authorName` 인데 GameCommentData 엔 `nickname` 프로퍼티만 존재 → 미매핑 →
|
|
commentView(GameCommentController.java:179) `getNickname()` null.
|
|
- 대조: 단건 getGameComment 는 `nickname`(alias 없음) → 정상.
|
|
- 1줄 수정안: listGameComments 의 `nickname AS authorName` → `nickname`.
|
|
- 처리: 사용자 요청 시에만 (in-progress 기능 코드라 무단 수정 보류).
|
|
|
|
# open_items
|
|
- 미커밋 신규 파일: db/seed-dev.sql, db/seed-dev-teardown.sql (작업단위 산출물).
|
|
프로젝트/하니스 커밋정책 = 사용자 요청 시에만 커밋 → 커밋 보류, 사용자 확인 대기.
|
|
- (별도 작업단위) W3-2 댓글/리뷰 기능 코드 커밋 시 `/graphify src/` 재생성 + docs/graph/index.md
|
|
frontmatter(source_commit, last_generated_at) + Scopes 표 src 행 갱신 권고. 본 더미데이터
|
|
task 범위 밖.
|
|
|
|
# Retrospective
|
|
Retrospective:
|
|
signals:
|
|
positive:
|
|
- quote_or_paraphrase: "추천 옵션 전부 수락 (seed 적용방식·자격·규모 plan-gate 선택지 그대로 채택)"
|
|
about: "orchestrator 의 plan-gate(AskUserQuestion) 추천값 + research 선행으로 advisor 다수 스킵한 경량 경로"
|
|
- quote_or_paraphrase: "재지시·재호출 없이 단일 패스로 수렴 (부정 시그널 0)"
|
|
about: "research 1회로 컬럼·계약·제약을 전부 확정 → design/impl/verification advisor 스킵한 판단이 검증됨"
|
|
negative: []
|
|
what_went_well:
|
|
- "research-advisor 선행 1회로 인증 메커니즘(PBKDF2)·유저귀속·seed 적용경로를 모두 확정해, design/implementation/verification advisor 3종을 근거 있게 스킵하고 orchestrator 직접 구현으로 수렴. advisor invocation decision log 에 skip rationale 가 항목별로 남아 사후 추적 가능."
|
|
- "호스트에 JDK 가 없는 제약에도 password_hash 를 추정·방치하지 않고 eclipse-temurin:21-jdk 컨테이너에서 실제 verifyPassword 코드 경로로 교차 실행(positive=true / negative=false)해 '로그인 가능' AC 를 자기검증으로 닫음. self-report 가 아닌 실행 증거."
|
|
- "schema.sql 이 '비권위 복원본'이라는 메타 한계를 research concerns 에 보존하고, 컬럼명은 매퍼로 교차확인하되 제약·타입은 추정으로 표기해 신뢰도 과대평가를 회피."
|
|
- "seed SQL 을 멱등 + teardown 쌍으로 작성하고 재실행 후 카운트 불변을 실증해 반복 적용 안전성을 확보."
|
|
- "graph staleness 를 partial-stale 로 정직하게 판정하되, 본 세션 변경(데이터 픽스처)은 graph scope 밖임을 구분해 불필요한 재생성을 회피하고 잔여 stale 은 별도 작업단위로 정확히 귀속."
|
|
what_to_improve:
|
|
- "런타임 UI 스모크는 호스트 환경 제약(JDK 없음 + 앱 미가동)으로 자동 불가 → needs_user_verification 으로 정확히 이월됨. 개선이라기보다 환경 한계의 정직한 핸드오프. (구조적 결함 아님)"
|
|
- "seed SQL 의 제약/타입/default 는 schema.sql 비권위 유래라 실 DB `\\d` 대조까지는 미수행(행수·테이블존재·매퍼 동등쿼리로만 검증). 운영 DB 와 default 가 다르면 재현 시 불일치 여지 — 현 dev 스키마에선 무영향이나 운영 적용 시 유의."
|
|
memory_candidates:
|
|
- name: bibimbap-auth-pbkdf2-not-bcrypt
|
|
type: reference
|
|
description: "bibimbap 로그인 해시는 BCrypt 가 아닌 자체 PBKDF2 — 로그인 가능 더미/테스트 계정 seed 시 이 포맷으로 직접 생성해야 함"
|
|
body_draft: |
|
|
# bibimbap 인증: PBKDF2 자체 해시 (BCrypt 아님)
|
|
|
|
Spring Security 미사용. 로그인은 UserController 자체 구현 password 검증.
|
|
password_hash 포맷: `pbkdf2_sha256$210000$<base64(salt)>$<base64(hash)>` ($ 4필드)
|
|
- 알고리즘 PBKDF2WithHmacSHA256, iterations=210000, keyLength=256bit, salt=16byte SecureRandom
|
|
- 검증 경로: UserController.verifyPassword (parts[0]=="pbkdf2_sha256" && len==4 확인 후 동일 iter/salt 재계산, MessageDigest.isEqual 상수시간 비교)
|
|
|
|
## Why
|
|
외부 BCrypt 생성기로 만든 해시는 무효 — 형식 자체가 다름. 향후 로그인 가능 더미/테스트/관리자 계정을
|
|
seed 할 때마다 이 함정에 반복적으로 부딪힌다. 코드로 유도는 가능하나 "BCrypt 일 것"이라는 기본 가정이
|
|
강해 매번 재확인 비용이 든다.
|
|
|
|
## How to apply
|
|
- 로그인 가능 계정 seed 시 위 PBKDF2 스펙으로 해시 문자열을 직접 생성.
|
|
- 로그인 동작 보장은 실제 verifyPassword 코드 경로(JDK 컨테이너 교차 실행 등)로 positive/negative 둘 다 확인.
|
|
- 로그인 필수 조건 동봉: users.status='ACTIVE', user_auth_identities.provider='email',
|
|
provider_user_id=정규화(trim+lowercase) 이메일, 양쪽 is_delete=false.
|
|
rationale_for_saving: "코드로만 드러나는 비자명 사실(BCrypt 아님)이고, 테스트/더미 계정 seed 마다 재발하는 함정. schema/git log 로는 '자체 PBKDF2 라서 외부 생성기 무효'라는 함의가 드러나지 않음."
|
|
signal_source: observation
|
|
docs_sync_target: /Users/wemadeplay/workspace/stz/bibimbap/CLAUDE.md
|
|
- name: bibimbap-seed-blueprint-fk-and-unique
|
|
type: reference
|
|
description: "dev 스키마 더미 seed 청사진 — FK 순서 + game_reviews active-unique 제약(게임당 user 1리뷰)"
|
|
body_draft: |
|
|
# bibimbap dev 더미 seed 청사진
|
|
|
|
현실적 경로 = dev 스키마에 psql 직접 INSERT (UI 경유는 CSRF+세션+WebGL 업로드 강제로 고비용).
|
|
DB 직삽은 CSRF·세션·중복선검사를 우회하되 FK·CHECK·유니크idx 는 그대로 적용.
|
|
|
|
INSERT 순서(FK 의존):
|
|
1. users (status='ACTIVE' 필수, role='USER', is_delete=false, display_name 권장)
|
|
2. user_auth_identities (PBKDF2 password_hash — 별도 memory 참조; provider='email')
|
|
3. games (user_id FK, name; is_visible/is_delete default 로 목록노출 충족; webgl/thumbnail NULL 가능)
|
|
4. game_reviews (game_id, user_id, rating 1~5, body)
|
|
5. game_comments (game_id, user_id, nickname[직접 채움 — 조회가 users JOIN 안 함], content)
|
|
|
|
## 핵심 제약
|
|
- game_reviews 부분 유니크 idx `(game_id, user_id) WHERE is_delete IS NOT TRUE`
|
|
→ 한 게임에 더미 리뷰 N개 = 더미 유저 N명 필요 (한 user 는 게임당 활성 1리뷰).
|
|
- game_comments 는 유니크 없음 → 자유 다수. 작성자명 보이려면 nickname 직접 채움(비정규화 저장).
|
|
- 게임 목록+상세 노출 = games.is_visible=true, games.is_delete=false, 연결 users.is_delete=false.
|
|
|
|
## Why
|
|
리뷰 N개를 같은 유저로 넣으려다 유니크 위반으로 막히는 게 첫 시도의 흔한 실패. schema.sql 이
|
|
'비권위 복원본'이라 제약을 코드에서 직접 읽기 전엔 드러나지 않음.
|
|
|
|
## How to apply
|
|
- seed SQL 확정 직전 `\d dev.<table>` 로 제약/타입/default 운영 대조 권장(schema.sql 비권위).
|
|
- 리뷰 다양화가 목표면 더미 유저를 리뷰 수만큼 선행 INSERT.
|
|
rationale_for_saving: "seed 설계 시 반복되는 유니크-위반 함정 + FK 순서. schema.sql 비권위라 코드 교차확인 없이는 유도 불가하고, 더미/픽스처 작업마다 재사용되는 청사진."
|
|
signal_source: observation
|
|
docs_sync_target: null
|
|
- name: java-crypto-verify-via-jdk-container-when-no-host-jdk
|
|
type: feedback
|
|
description: "호스트에 JDK 없을 때 Java 암호/검증 로직을 eclipse-temurin:21-jdk 컨테이너 single-file 실행으로 교차검증"
|
|
body_draft: |
|
|
# 호스트 JDK 부재 시 Java 로직 교차검증 패턴
|
|
|
|
호스트에 JDK 가 없고 앱도 미가동인 환경에서, password_hash 같은 Java 암호/검증 로직의
|
|
정합성을 추정으로 닫지 않고 `eclipse-temurin:21-jdk` 컨테이너에 single-file/javac 로
|
|
실제 코드 경로(예: verifyPassword)를 옮겨 실행해 positive+negative 케이스를 모두 확인.
|
|
|
|
## Why
|
|
seed 한 해시가 "로그인 된다"는 self-report 는 증거가 아니다. 실제 검증 함수와 동일한
|
|
알고리즘/iter/salt 로 재계산해 true/false 가 나와야 AC 가 닫힌다. 호스트 toolchain 부재는
|
|
검증 생략의 이유가 되지 않고, 컨테이너로 우회 가능하다.
|
|
|
|
## How to apply
|
|
- 검증 대상 메서드의 알고리즘 파라미터(iter/keyLength/salt/encoding)를 코드에서 그대로 추출.
|
|
- 동일 로직을 단일 .java 로 재현해 temurin 컨테이너에서 실행, 정답=true / 오답=false 둘 다 확인.
|
|
- 런타임 UI 스모크처럼 컨테이너로도 불가한 부분만 needs_user_verification 으로 이월.
|
|
rationale_for_saving: "환경 제약(호스트 JDK 없음) + Java 검증 로직이라는 비자명 조합. self-report 대신 실행 증거로 AC 를 닫는 재현성 있는 검증 워크플로우 — 단발 우발 아님."
|
|
signal_source: positive
|
|
docs_sync_target: /Users/wemadeplay/workspace/stz/bibimbap/docs/development/verification-strategies.md
|
|
protocol_feedback: []
|
|
applied_changes: []
|