chore(atp): work-session 20260629-175705 기록(B2·B4·FE 3트랙)

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 19:10:42 +09:00
parent aae7629562
commit 31dc2ff964
9 changed files with 534 additions and 0 deletions

View File

@ -0,0 +1,40 @@
/atp:task B2(dead code 제거) · B4(의존성/세션/운영 하드닝) · FE(프론트엔드 디자인 검토·수정) 3트랙을 진행한다. B2와 B4는 독립 파일이므로 병렬 처리하고, FE는 frontend-design 스킬 + claude-in-chrome 으로 실 화면을 검토한 뒤 수정한다.
## 공통 컨텍스트
- bibimbap: Java 21 / Spring Boot / JSP / MyBatis WAR. 화면은 `/WEB-INF/views/*.jsp`.
- dev 앱이 docker compose 로 구동 중(localhost:8080, db 5433). 코드·JSP 변경 후에는 `docker compose up -d --build app` 재배포가 필요하다(가이드: docs/development/local-dev-setup.md).
- 기준 문서: `docs/security/security-remediation-checklist.md` (B2=§B2, B4=§B4), `docs/analysis/2026-06-16-project-analysis.md`.
- 프로파일: dev + live. `spring.profiles.active=@app.profile@` (Maven 필터). `src/main/resources/{dev,live}/`.
## 트랙 1 — B2 프로토타입 dead code 제거 (독립)
1. `rg "abstracts|GameCatalog|header.jspf"` 로 실제 참조를 재확인한다.
2. `src/main/java/com/pandoli365/bibimbap/abstracts/` 패키지를 삭제(컴파일 무파손 확인).
3. `src/main/webapp/WEB-INF/jsp/fragments/header.jspf` 삭제 — 모든 JSP include 가 `/WEB-INF/views/header.jsp` 인지 먼저 확인.
4. `GameCatalog``GameController` 의 GameCatalog fallback(라인 ~111,116) 제거.
5. **없는 게임 ID 접근 동작 = HTTP 404** (결정 확정). redirect 아님.
6. 제거된 프로토타입 흐름을 최신 구조로 문서 갱신.
- 검증: `mvn test` 회귀 0. 완료 조건은 체크리스트 §B2 "완료 조건" 충족.
## 트랙 2 — B4 의존성/세션/운영 하드닝 (독립)
1. **Spring Boot**: `pom.xml` `spring-boot.version` `3.5.14-SNAPSHOT` → 최신 stable 3.5.x release 로 고정(정확 버전은 research 로 확정 — Maven Central 기준 최신 패치).
2. **snapshot repo 제거**: `pom.xml` `<repositories>`/`<pluginRepositories>` 의 spring-snapshots(라인 ~211-229) 삭제. SNAPSHOT 제거 후 불필요.
3. **세션 쿠키 하드닝**:
- base `application.properties`: `server.servlet.session.cookie.http-only=true`, `server.servlet.session.cookie.same-site=lax`.
- live 전용(`application-live.properties` 신규): `server.servlet.session.cookie.secure=true`.
4. **MyBatis TRACE 로그 격하**: 현재 base `logging.level.org.apache.ibatis=TRACE` → base 는 `WARN`, dev 전용(`application-dev.properties`)에서만 TRACE 유지. 민감 파라미터 노출 점검.
5. **CVE 스캔 도구 = OWASP Dependency-Check** (결정 확정. 오프라인·외부서비스 무의존). maven plugin 추가 + 스캔 결과·예외 기준을 `docs/security/` 에 기록.
6. **multipart 1GB = 유지** (사용자 결정). 변경하지 않되 DoS·디스크 고갈 리스크를 `docs/security/` 에 명시.
- 검증: `mvn test` 통과 + snapshot repo 없이 빌드 재현 가능. 완료 조건은 체크리스트 §B4 "완료 조건" 충족(단 multipart 항목은 "유지+리스크 문서화"로 종결).
## 트랙 3 — 프론트엔드 디자인 검토·수정 (frontend-design 스킬 + 브라우저)
- frontend-design 스킬을 로드하고, claude-in-chrome 으로 구동 중인 localhost:8080 의 실 화면을 직접 시각 검토한다(코드만 읽지 말 것).
- 대상: 핵심 사용자 동선 우선 — index(메인 허브)·game-detail·login·signup·profile. 이후 확장 가능.
- 검토 축(전부): ① 디자인 일관성·완성도(타이포·간격·색·컴포넌트, theme-init.jsp 다크/라이트) ② 반응형·모바일(breakpoint·터치타깃·가로스크롤) ③ 접근성 a11y(대비비·ARIA·포커스링·키보드 동선) ④ 시각 리프레시(룩앤필 현대화). 다른 축이 보이면 확장.
- 산출: (1) 화면별 findings 보고(스크린샷 + 축별 문제·심각도) → 사용자 합의 → (2) JSP 수정 → (3) 브라우저 재확인(L3 스모크).
- 데스크탑/모바일 뷰포트 모두 캡처.
## 실행 순서 / 게이트
- 트랙1·2 병렬(독립 파일, 충돌 0) → 각자 `mvn test`/빌드 검증.
- 트랙3 은 frontend-design 스킬 로드 후 브라우저 검토부터. 수정 전 findings 합의 게이트 1회.
- 세션 종료 전: 코드 변경 트랙 전부 L1(`mvn test`) 통과, JSP 변경은 재배포 후 브라우저 스모크. graph-refresh-checker 호출. git 잔여 커밋(작업 브랜치 표준 승인, push 는 명시 요청 시만).
- 비파괴 원칙: 삭제 전 참조 재확인, 파일 이동은 mv. 파괴적 조작은 사용자 확인 게이트.

View File

@ -0,0 +1,24 @@
---
schema_version: 2
sid: 20260629-174807
started_at: 2026-06-29T17:48:07+09:00
user_request: |
B4(의존성/세션/운영 하드닝) 및 B2(프로토타입 dead code 제거) 작업을 독립적으로 진행.
추가로 프론트엔드 디자인을 검토 및 수정.
tracks:
- id: B2
name: 프로토타입 dead code 제거
independent: true
- id: B4
name: 의존성/세션/운영 하드닝
independent: true
- id: FE
name: 프론트엔드 디자인 검토 및 수정
scope: 미정 (수렴 필요)
invocations: []
decisions: []
open_items: []
---
# Advisor Invocation Decision Log
# 각 advisor 호출/스킵 판단 즉시 1줄 append

View File

@ -0,0 +1,33 @@
# FE 디자인 검토 findings (1라운드)
검토 환경: claude-in-chrome, localhost:8080 (docker dev), 데스크탑 1440 캔버스, 다크+라이트.
검토 화면: index / login / signup / game-detail (다크·라이트). profile = 로그인 필요(보류).
viewport 한계: resize_window 가 실제 viewport(innerWidth=2560 retina)에 미반영 → **모바일은 CSS @media 코드 점검으로 검증**. 전 핵심 화면 @media 보유(반응형 마크업 존재).
theme: theme-init.jsp + header.jsp 토글 핸들러 정상(localStorage `bibimbap-theme` 영속 + 페이지이동 유지 실측 확인).
## findings (축별 심각도)
### F1. index 검색영역 이중구조 — [완성도/정보구조 · 중]
상단 큰 "게임·제작자 검색" 바 + [검색], 바로 아래 "게임이름·소개 검색"/"제작자(개발자) 검색" 2칸 + 정렬 드롭다운 + [상세 검색]. 검색 진입점이 시각적으로 둘로 중복 → 어느 걸 써야 할지 혼란. 위계/그룹핑 정리 필요(상세검색을 접이식 or 명확한 1차/2차 구분).
근거: index.jsp 검색 폼 영역.
### F2. 다크모드 입력 필드 테두리 대비 부족 — [a11y/완성도 · 중]
login/signup 다크에서 input border 가 배경(거의 검정)과 동일 톤 → 필드 경계 식별 곤란. 라이트모드는 옅은 회색 테두리로 양호. 다크 전용 input border 색 상향 필요(WCAG 비텍스트 대비 3:1 목표).
근거: login.jsp / signup.jsp + 다크 토큰.
### F3. 와이드스크린 콘텐츠 정렬·여백 — [레이아웃 · 하~중]
콘텐츠 max-width 좁고 상단 정렬 → 1440px+ 에서 하단 여백 과다 + 카드 그리드 좌측 쏠림(카드 1개일 때 특히 휑함). 콘텐츠 적은 현 데이터 탓도 있음 → 우선순위 낮음. 그리드 중앙정렬/최소 채움 검토.
### F4. game-detail — [정보 · 양호]
제목+3분할 카드(번호/제작자/좋아요) · WebGL 플레이 · 제작자 한마디 · 리뷰(3.8★) 구성 완성도 높음. 큰 이슈 없음. (모바일 3분할 카드 wrap 거동만 코드 확인)
### F5. 모바일 반응형 — [반응형 · 확인필요]
자동 viewport 제어 불가로 시각 미확인. 수정 단계에서 index/header/game-detail/login/profile 의 @media breakpoint·터치타깃(체크박스 작음 F2 연계)·가로스크롤 코드 점검으로 검증.
## 수정 우선순위 제안
P1: F2(다크 input 대비) — a11y, 저위험 토큰 수정.
P2: F1(검색영역 위계) — 정보구조, JSP 구조 손봄(중위험).
P3: F5(모바일 점검) — 코드 검증 후 필요 시 수정.
P4: F3(와이드 여백) — 데이터 적은 현 상태 영향 작음, 후순위.
전반: 현 디자인 완성도 양호(다크 주황 액센트·카드 UI 일관). 과한 비주얼 리프레시보다 **a11y·정보구조 정리** ROI 우선.

View File

@ -0,0 +1,42 @@
---
phase: documentation
agent: documentation-advisor
agent_version: 1
generated_at: 2026-06-29T18:30:00+09:00
concerns:
- "ADR 검토: D-B2-404(없는 게임 ID=HTTP 404)·D-B4-cve(OWASP 비bind)·D-B4-cfgloc(profile properties 신규)는 되돌리기 어려운 결정 성격이 있으나, API 동작 정의·플러그인 설정 수준으로 아키텍처 원칙보다는 구현 결정에 가깝다고 판단. security-remediation-checklist + changes 문서로 충분히 기록. ADR 불발행."
- "design-advisor가 이번 세션 architecture/ 갱신 수행하지 않음 — 구조 변화(abstracts 패키지 제거)가 아키텍처 문서화가 필요한 수준이나 기존 architecture/ 문서가 없어(index에 카테고리만 존재) 신규 작성 대신 analysis 문서 stale 갱신으로 처리."
concerns_checked: true
---
# 문서화 보고
## 작성/수정된 문서
| 경로 | 카테고리 | 유형 | 링크 추가한 index | 교차 링크 |
|---|---|---|---|---|
| docs/security/security-remediation-checklist.md | security | 수정 (B2·B4 체크박스 완료·구현결과·완료조건 갱신) | security/index.md | changes/2026-06-29-b2-b4-fe-hardening.md |
| docs/security/owasp-dependency-check-guide.md | security | 신규 | security/index.md | security-remediation-checklist.md, multipart-size-risk.md |
| docs/security/multipart-size-risk.md | security | 신규 | security/index.md | security-remediation-checklist.md, owasp-dependency-check-guide.md, maintenance/post-deploy-verification-checklist.md |
| docs/security/index.md | security | 수정 (신규 2문서 링크 추가) | — | — |
| docs/changes/2026-06-29-b2-b4-fe-hardening.md | changes | 신규 | changes/index.md | security/security-remediation-checklist.md, security/owasp-dependency-check-guide.md, security/multipart-size-risk.md, development/local-dev-setup.md |
| docs/changes/index.md | changes | 수정 (신규 문서 링크 추가) | — | — |
| docs/work-log/2026-06-29-b2-b4-fe-session.md | work-log | 신규 | work-log/index.md | changes/2026-06-29-b2-b4-fe-hardening.md, security/ 3문서 |
| docs/work-log/index.md | work-log | 수정 (신규 문서 링크 추가) | — | — |
| docs/analysis/2026-06-16-project-analysis.md | analysis | 수정 (Top#4·5·6 stale → "제거됨(2026-06-29)" 갱신, 패키지표 2항목) | — | changes/2026-06-29-b2-b4-fe-hardening.md |
| docs/development/local-dev-setup.md | development | 수정 (offline prefetch 함정 노트 추가) | — | — |
## 의사결정 기록 위치
- **D-B2-404** (없는 게임 ID = HTTP 404): `docs/security/security-remediation-checklist.md §B2 구현 결과`, `docs/changes/2026-06-29-b2-b4-fe-hardening.md §B2`
- **D-B4-cve** (OWASP Dependency-Check 오프라인 비bind): `docs/security/owasp-dependency-check-guide.md`, `docs/security/security-remediation-checklist.md §B4`
- **D-B4-multipart** (1GB 유지, 리스크 문서화): `docs/security/multipart-size-risk.md`
- **D-B4-cfgloc** (application-{profile}.properties 신규): `docs/security/security-remediation-checklist.md §B4 구현결과`, `docs/changes/2026-06-29-b2-b4-fe-hardening.md §B4`
- **D-test-mockfix** (GameLikesMapper @MockBean): `docs/changes/2026-06-29-b2-b4-fe-hardening.md §B2`
- **FE 결정** (details 접이식·다크모드 대비·터치타깃): `docs/changes/2026-06-29-b2-b4-fe-hardening.md §FE`
## 추후 문서화가 필요한 항목
- OWASP Dependency-Check 첫 실행 결과(스캔 보고서) 및 CVE 예외 결정이 나오면 security/ 에 결과 문서 추가 권고.
- multipart 리버스프록시 상한 설정이 완료되면 maintenance/ 또는 architecture/ 에 프록시 설정 기록 권고.
- application-live.properties의 cookie.secure=true가 실환경에 배포·검증되면 security-remediation-checklist §B4 완료조건에 런타임 확인 기록 권고.

View File

@ -0,0 +1,51 @@
---
phase: implementation
agent: implementation-advisor
agent_version: 1
generated_at: 2026-06-29T09:30:00Z
concerns: []
concerns_checked: true
workers_spawned: 3
planned_workers: 3
actual_workers: 3
---
# 구현 보고 — B2 GameController 404 전환 + B4 의존성/설정 하드닝
## 변경 목록
| 파일 | worker | 결과 요약 |
|---|---|---|
| src/main/java/com/pandoli365/bibimbap/controller/api/GameController.java | code-writer (w-001) | GameCatalog import + fallback 블록 제거, game==null → `throw new ResponseStatusException(HttpStatus.NOT_FOUND)` |
| pom.xml | code-writer (w-002) | spring-boot.version 3.5.14-SNAPSHOT→3.5.16, spring-snapshots repo/pluginRepo 블록 전체 삭제, OWASP dependency-check-maven 12.2.2 plugin 추가(executions 없음) |
| src/main/resources/application.properties | code-writer (w-003) | ibatis 로그 TRACE→WARN, 세션 쿠키 http-only/same-site=lax 2줄 추가 |
| src/main/resources/application-dev.properties | code-writer (w-003) | 신규 생성 — dev 한정 ibatis TRACE |
| src/main/resources/application-live.properties | code-writer (w-003) | 신규 생성 — live 한정 쿠키 secure=true |
## 핵심 diff 요점
- **B2**: gameDetail() 의 game==null 경로 22줄(GameCatalog 기반 fallback 정적 뷰) → 1줄 404 throw. import `com.pandoli365.bibimbap.game.GameCatalog` 제거, import `org.springframework.web.server.ResponseStatusException` 추가. HttpStatus 는 기존 라인15에 이미 존재(중복 추가 안 함).
- **B2 advisor 추가 수정**: fallback 제거로 `List.of()` 사용처가 사라져 `import java.util.List` 가 unused 가 됨 → advisor 가 직접 제거(아래 "advisor 직접 편집" 참조).
- **B4 pom**: SNAPSHOT 제거로 spring 스냅샷 저장소 불필요 → repositories/pluginRepositories 래퍼 포함 전체 삭제. OWASP plugin 은 phase 비bind(수동 `mvn dependency-check:check` 전용, 평소 빌드 비영향).
- **B4 properties**: base 는 보수적(WARN + 쿠키 공통 하드닝), profile 별 오버라이드로 분리(dev=SQL TRACE, live=쿠키 Secure). Spring Boot 표준 application-{profile}.properties 자동로드 사용 — 기존 spring.config.import 기반 {profile}/db.properties 와 공존, db.properties 는 미변경.
## advisor 직접 편집 (worker 범위 외 후속)
- GameController.java 28라인 `import java.util.List;` 제거.
- 사유: w-001 가 설계대로 fallback 블록을 제거하자 `List.of()` 호출이 사라져 `List` 가 unused import 가 됨. 1라인 단일 편집이라 worker 재spawn 없이 advisor 가 직접 처리. (설계 변경 아님 — 설계가 의도한 제거의 직접 귀결)
## Bash 단계 (advisor 직접, 검증 아님 — 정적 grep 확인만)
- `rg -c GameCatalog GameController.java` → 0건 (참조 완전 제거 확인)
- `rg -c "3.5.14-SNAPSHOT|spring-snapshots" pom.xml` → 0건
- `ls application-{dev,live}.properties` → 2개 신규 파일 존재 확인
- 각 import 심볼 사용 count 점검 → unused import 0 (List 제거 후 LinkedHashMap/Locale/Map/ResponseEntity/ResponseStatusException/HttpStatus 모두 사용처 있음)
## 설계와의 차이
없음. planned_workers(3) == actual_workers(3). 모든 트랙이 설계대로 구현됨. unused import 제거는 설계가 의도한 dead code 삭제의 직접 귀결이며 설계 변경에 해당하지 않음.
## Verification 을 위한 힌트
- **B2 acceptance**: DB 미존재 game ID 로 `GET /game/{id}` 요청 시 HTTP 404 반환(기존엔 redirect:/ 또는 정적 fallback 뷰). DB 존재 시 정상 game-detail 뷰는 불변.
- **B2 영향 테스트**: GameController gameDetail 관련 테스트(존재 시) — game==null 케이스 기대값이 404 로 바뀜.
- **B4 pom**: `mvn -o ...` 또는 일반 빌드 시 spring-boot 3.5.16 의존성 해소 가능 여부. OWASP plugin 은 빌드 phase 비bind 이므로 평소 빌드 비영향.
- **B4 properties**: dev profile 활성 시 ibatis TRACE 로그, live profile 활성 시 쿠키 secure 적용 여부.
- acceptance criteria 전체는 design.md 의 검증 포인트 참조.
## 잔여 우려 (concerns)
- 없음. (GameCatalog.java 파일 자체 삭제는 본 advisor 범위 밖 — orchestrator 가 GameController 참조 0 확인 후 별도 수행. 본 작업으로 참조는 0건 끊김.)

View File

@ -0,0 +1,17 @@
---
phase: implementation
agent: implementation-advisor
agent_version: 1
generated_at: 2026-06-29T18:30:00+09:00
session: fe-design-fixes
---
# 파일 소유권 맵 (FE 디자인 수정 세션)
| 파일 | 담당 worker | worker id | 변경 유형 | 의존 |
|---|---|---|---|---|
| src/main/webapp/WEB-INF/views/login.jsp | code-writer | w-001 | modify | - |
| src/main/webapp/WEB-INF/views/signup.jsp | code-writer | w-002 | modify | - |
| src/main/webapp/WEB-INF/views/index.jsp | code-writer | w-003 | modify | - |
| src/main/webapp/WEB-INF/views/profile.jsp | code-writer | w-004 | modify | - |
| src/main/webapp/WEB-INF/views/game-detail.jsp | code-writer | w-005 | modify | - |

View File

@ -0,0 +1,78 @@
---
phase: verification
agent: verification-advisor
agent_version: 1
generated_at: 2026-06-29T09:33:00Z
concerns:
- "L2 skipped: dev DB contract harness 미구축 (레지스트리 open item). L2 미실행은 본 트랙(dead code 제거 + pom 하드닝) 판정에 영향 없음."
concerns_checked: true
---
# 검증 결과
## Acceptance Criteria (입력 받은 그대로 인용)
- **AC-1 (B2 컴파일 무파손)**: BUILD 컴파일 단계 통과. abstracts/GameCatalog/header.jspf 제거 + GameController 404 전환(ResponseStatusException) 후 컴파일 에러 0. unused import 등 컴파일 경고로 인한 실패 0.
- **AC-2 (회귀 0)**: 기존 테스트 전부 통과 — `Tests run: N, Failures: 0, Errors: 0` (skip 은 허용). 실패/에러 테스트 있으면 테스트명+사유 보고.
- **AC-3 (B4 snapshot repo 없이 빌드 재현)**: pom 에서 spring-snapshots repository/pluginRepository 삭제 + spring-boot 3.5.16 GA 임에도 의존성 resolve 성공 + BUILD SUCCESS. SNAPSHOT 잔존 resolve 시도 0.
## 실행된 전략
| id | cmd | exit | severity | 결과 |
|---|---|---|---|---|
| verify-all (L1) | `docker compose exec -T app mvn -B test` | 1 | blocker | FAIL |
분해 결과:
| 단계 | 결과 |
|---|---|
| L1 typecheck (compile) | pass — 컴파일 에러 0, BUILD 단계 통과 |
| L1 unit+regression | FAIL — Tests run: 360, Failures: 0, Errors: 1, Skipped: 0 |
| L2 contract | skipped: harness 미구축 |
| 로그 스캔 (SNAPSHOT resolve) | clean — spring-snapshot 도메인 Downloading 0건 |
## 실패 상세
### BibimbapApplicationTests.contextLoads (ERROR)
- **실패 지점**: `BibimbapApplicationTests.contextLoads`
- **루트 원인**: `NoSuchBeanDefinitionException``GameController` 생성자 파라미터 4번(0-indexed) 에 주입할 `GameLikesMapper` 빈이 없음.
```
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'gameController' ...
constructor parameter 4:
No qualifying bean of type 'com.pandoli365.bibimbap.mapper.GameLikesMapper' available
```
테스트 컨텍스트 설정:
```
spring.autoconfigure.exclude=
DataSourceAutoConfiguration,
MybatisAutoConfiguration
```
MyBatis AutoConfiguration이 exclude된 상태이므로 `GameLikesMapper` 빈이 등록되지 않아 `GameController` DI 실패 → `ApplicationContext` 로드 실패.
- **재현 명령**:
```
docker compose exec -T app mvn -B test -Dtest=BibimbapApplicationTests
```
- **진단**: B4/B2 구현 중 `GameController``GameLikesMapper` 의존성이 **신규 추가**됐으나, `BibimbapApplicationTests``@MockBean` 목록에 `GameLikesMapper`가 추가되지 않았다. 레지스트리 §"신규 컨트롤러/매퍼 의존 변경 시 full test 의무" 패턴과 정확히 일치하는 회귀.
## 종합 판정
```
overall: fail
rollback_signal: none
```
`rollback_signal: none` 근거: 파괴적 조작(스키마 변경·마이그레이션) 없음. 단순 테스트 설정 누락(`@MockBean` 미추가)으로 인한 컨텍스트 로드 실패. 구현 파일 복원이 아닌 테스트 파일 수정으로 해소 가능.
## Acceptance 매칭
| criterion | 매칭 전략 | 판정 |
|---|---|---|
| AC-1 (B2 컴파일 무파손) | L1 compile 단계 | **PASS** — 컴파일 에러 0. BUILD 단계 통과 확인. |
| AC-2 (회귀 0) | L1 unit+regression | **FAIL**`BibimbapApplicationTests.contextLoads` ERROR 1건. `GameLikesMapper` @MockBean 미등록. |
| AC-3 (B4 SNAPSHOT repo 제거) | SNAPSHOT resolve 스캔 | **PASS** — spring-snapshot 도메인 Downloading 0건. central(GA)에서만 resolve 성공. spring-boot 3.5.16 GA 의존성 다운로드 완료. |

View File

@ -0,0 +1,83 @@
---
schema_version: 2
sid: 20260629-175705
resumed_from: 20260629-174807
started_at: 2026-06-29T17:57:05+09:00
user_request: |
B2(dead code 제거) · B4(의존성/세션/운영 하드닝) · FE(프론트엔드 디자인 검토·수정) 3트랙.
B2·B4 독립 파일이라 병렬, FE 는 frontend-design 스킬 + claude-in-chrome 실화면 검토 후 수정.
확정 결정값: 없는 게임 ID = HTTP 404 / CVE = OWASP Dependency-Check(오프라인) / multipart 1GB 유지(리스크 문서화).
tracks:
- id: B2
name: 프로토타입 dead code 제거
independent: true
files: [abstracts/*, fragments/header.jspf, game/GameCatalog.java, controller/api/GameController.java]
- id: B4
name: 의존성/세션/운영 하드닝
independent: true
files: [pom.xml, application.properties, application-dev.properties, application-live.properties]
- id: FE
name: 프론트엔드 디자인 검토·수정
scope: index·game-detail·login·signup·profile (확장 가능)
invocations:
- agent: research-advisor
model: sonnet
result: 'B2 삭제 안전성(abstracts·header.jspf 참조0, GameCatalog=GameController 1곳) + B4 버전(SB 3.5.16, OWASP DC 12.2.2) 확정. B4 가정불일치(application-dev/live.properties 부재) 발견.'
- agent: implementation-advisor
model: sonnet
result: 'B2 GameController 404 전환(import/fallback 제거) + B4 pom(3.5.16·snapshot repo 제거·OWASP plugin 비bind)·application.properties(쿠키·로깅 WARN)·application-dev/live.properties 신규. 5파일.'
- agent: verification-advisor
model: sonnet
result: 'AC-1 컴파일 PASS / AC-3 snapshot없이빌드 PASS / AC-2 FAIL(BibimbapApplicationTests GameLikesMapper @MockBean 누락=직전 B3 사전결함). orchestrator 1줄 보강 후 재검 360 tests 0 fail PASS.'
- agent: implementation-advisor
model: sonnet
result: 'FE F2 다크 input 대비(login·signup·index·game-detail)·F1 index 검색 details 접이식·F5 터치타깃. profile=입력컨트롤 없음 해당없음. (advisor summary 불완전했으나 실변경 적용 확인)'
decisions:
- id: D-B2-404
text: 없는 게임 ID 접근 = HTTP 404 (redirect 아님). 사용자 확정. → ResponseStatusException(NOT_FOUND).
- id: D-B4-cve
text: CVE 스캔 = OWASP Dependency-Check maven plugin (오프라인). 사용자 확정. → executions 없이 비bind(수동 mvn dependency-check:check), autoUpdate=false.
- id: D-B4-multipart
text: multipart 1GB 유지, DoS/디스크 리스크만 docs/security 명시. 사용자 확정.
- id: D-B4-cfgloc
text: 'B4 설정 위치 = Spring 표준 application-{profile}.properties 신규(base 공통+profile특화). db.properties 는 DB 전용 유지. 사용자 합의(가정불일치 plan-gate).'
- id: D-FE-scope
text: 'FE 범위 = 전체(P1~P4+모바일). 사용자 합의. F1 검색위계=details 접이식.'
- id: D-test-mockfix
text: 'BibimbapApplicationTests GameLikesMapper @MockBean 누락(직전 B3 사전결함) 1줄 보강 — L1 그린 종료조건.'
open_items:
- 'dev override(spring-boot:run -o offline) 함정: SNAPSHOT→GA 버전 변경 후 첫 기동 전 online prefetch 필요 → local-dev-setup.md 노트화 (documentation 단계).'
---
# Advisor Invocation Decision Log
# 각 advisor 호출/스킵 판단 즉시 1줄 append
- advisor: requirements-advisor
decision: skip
rationale: '사용자가 트랙별 요구·확정값(404/OWASP DC/multipart 유지)까지 명시 — 요구 명확, 오픈질문 0'
checked_at: 2026-06-29T17:57:05+09:00
- advisor: graphify-lookup-advisor
decision: skip
rationale: '트랙1·2는 코드 사실 재확인(rg/실파일) 이 정확 — graph 인덱스보다 research-advisor 직접 탐색 우선'
checked_at: 2026-06-29T17:57:05+09:00
- advisor: research-advisor
decision: call
rationale: 'B2 참조 재확인(삭제 안전성) + B4 Spring Boot 최신 stable 3.5.x 정확버전·OWASP DC plugin 설정 외부조사 필요'
checked_at: 2026-06-29T17:57:05+09:00
## verified_by_me
- **L1 (unit+regression)**: `mvn test`**361 tests, 0 Failures, 0 Errors, BUILD SUCCESS** (docker dev 컨테이너). 신규 회귀 가드 `GameLikeControllerTest.gameDetailThrowsNotFoundWhenGameMissing` 포함. 직전 B3 사전결함(BibimbapApplicationTests GameLikesMapper @MockBean 누락) 보강 포함.
- **B4 빌드 재현 (AC-3)**: spring-snapshots repo 제거 + spring-boot 3.5.16 GA — central GA만으로 resolve, snapshot Downloading 0건. BUILD SUCCESS.
- **런타임 스모크 (재배포 후)**:
- B2 404: `GET /game/99999` → HTTP 404 `{"status":404,"message":"not found"}`, `GET /game/3` → 200. (ApiExceptionControllerAdvice ResponseStatusException 핸들러로 status 보존)
- B4 쿠키: `Set-Cookie: JSESSIONID=...; Path=/; HttpOnly; SameSite=Lax` 확인.
- FE: index 검색 `<details>` 접이식 펼침/접힘 동작, 다크모드 input 테두리 대비(zoom 확인 — 명확), signup·game-detail 렌더 정상(JSP 무파손).
- 로그 스캔: clean (BUILD SUCCESS, FeedParserTest prolog Fatal Error 는 XXE 방어 정상 로그).
## needs_user_verification
- **모바일 실기기/뷰포트**: 브라우저 자동화 resize 가 실제 viewport(innerWidth 2560 고정)에 미반영 → 모바일 시각 미확인. CSS @media(640/760/480 등)·터치타깃(체크박스 1.15rem, summary 44px) 코드 반영됨. 실기기/devtools 디바이스모드 1회 확인 권장.
- **live profile 쿠키 secure**: `application-live.properties` `cookie.secure=true` 는 HTTPS 운영 배포 시 Set-Cookie Secure 확인(dev=http 환경 미검증).
- **OWASP DC 첫 스캔**: `mvn dependency-check:check` 는 NVD 데이터 1회 온라인 다운로드(autoUpdate=false 라 사전 채운 dataDirectory 필요). 오프라인 운영 전 NVD 캐시 준비.
## graph_refresh
(graph-refresh-checker 호출 후 기록)

View File

@ -0,0 +1,166 @@
---
phase: research
agent: research-advisor
agent_version: 2
generated_at: 2026-06-29T09:04:35Z
concerns: []
source_confidence: high
workers_spawned: 2
---
# 조사 결과 — B2 dead code 삭제 안전성 + B4 의존성 업그레이드 사실조사
## 주제
bibimbap (Java21/SpringBoot/JSP/MyBatis WAR) 의 두 작업트랙:
- B2: dead code(abstracts 패키지, GameCatalog, header.jspf) 삭제 안전성
- B4: Spring Boot 최신 stable 버전 + OWASP Dependency-Check maven plugin(오프라인) 도입을 위한 사실조사
전부 read-only. 설계·구현·코드수정 없음.
---
## 트랙 B2 — dead code 삭제 안전성 (코드 사실 / 조사포인트 1)
### 포인트 1-A: abstracts 패키지
- 경로: `src/main/java/com/pandoli365/bibimbap/abstracts/`
- 요약: 4개 파일 존재 — `ErrorResult.java`, `Request.java`, `Result.java`, `Service.java`.
- `ErrorResult` extends `Result` (status만 받는 생성자)
- `Request` abstract, `IsReceivedAllField()` 기본 true 반환
- `Result` abstract, status/message 필드
- `Service<Req extends Request, Res extends Result>` 제네릭 abstract, `ChackService()`/`StartService()`
- 외부 참조 확인:
- `rg "bibimbap\.abstracts|abstracts\."` → 4개 파일 자기 자신의 package 선언(라인1)만 hit. 패키지 밖 import/참조 **0건**.
- **(advisor 보강)** `rg "extends (Service|Request|Result)|new ErrorResult|StartService|ChackService|IsReceivedAllField"` → hit는 전부 abstracts 패키지 **내부**의 정의/상호참조(Service.java가 ErrorResult/Request를 쓰고, ErrorResult가 Result를 extends)뿐. abstracts **외부**에서 `extends Service`/`extends Request`/`extends Result` 하는 구체 클래스 **0건**.
- 관련 파일:라인:
- `abstracts/ErrorResult.java:3``public class ErrorResult extends Result`
- `abstracts/Service.java:5``public abstract class Service<Req extends Request, Res extends Result>`
- `abstracts/Service.java:13,15``(Res) new ErrorResult(401)` (패키지 내부 사용)
- 신뢰도: 확인됨 (rg 전수 + 직접 코드읽기 + advisor 상속 키워드 보강검증)
### 포인트 1-B: GameCatalog.java 참조
- 경로: `src/main/java/com/pandoli365/bibimbap/game/GameCatalog.java`
- 요약: `rg "GameCatalog"` 결과 참조 파일 2개뿐 — GameCatalog.java 자신 + GameController.java. 다른 컨트롤러·서비스 참조 **0건**.
- 관련 파일:라인:
- `controller/api/GameController.java:5``import com.pandoli365.bibimbap.game.GameCatalog;`
- `controller/api/GameController.java:150,155,157-162` — gameDetail() fallback 블록에서 사용
- 신뢰도: 확인됨
### 포인트 1-C: header.jspf include 여부
- 경로: `src/main/webapp/WEB-INF/jsp/fragments/header.jspf`
- 요약: `rg "header\.jspf|fragments/header"`**0 hit**. `rg "include.*header"` → 0 hit (이 패턴으로는). header.jsp를 include하는 JSP는 총 **23개**이며 전부 `<jsp:include page="/WEB-INF/views/header.jsp"/>` 형태로 통일. `header.jspf`를 include하는 사례 **0건**.
- 관련 파일:라인: game-detail.jsp:1201, index.jsp:727, login.jsp:205 등 23개 전부 `/WEB-INF/views/header.jsp`
- 신뢰도: 확인됨
### 포인트 1-D: GameController.gameDetail() fallback 로직 (404 변경용 정확 라인)
- 경로: `src/main/java/com/pandoli365/bibimbap/controller/api/GameController.java`
- 요약: `gameDetail()` 메서드(137~173라인) 현재 흐름:
- **140~148**: `gamesMapper.getGame(id)` DB조회 → `game != null`이면 정상 뷰 반환
- **150**: `game == null` 진입. `if (id < Integer.MIN_VALUE || id > Integer.MAX_VALUE || !GameCatalog.isValidId((int) id))`
- **151**: 위 조건 true이면 `return "redirect:/";`
- **154~172**: `GameCatalog.isValidId()` true이면 `GameCatalog.toIndex(intId)`로 인덱스 구해 `NAMES/CREATORS/LIKE_COUNTS/CREATOR_NOTES/GIT_URLS` 배열값을 model 적재 후 `"game-detail"` 뷰 반환
- 현재 코드 사실: **DB에 없는 game ID에 대해 404를 반환하는 분기는 이 메서드에 존재하지 않는다.** GameCatalog.isValidId 통과 여부에 따라 (a) fallback 정적 뷰("game-detail") 또는 (b) 루트 redirect("redirect:/") 둘 중 하나로 귀결.
- "GameCatalog 제거 후 없는 게임 ID를 404로 바꾸려면 고쳐야 할 줄" (사실 식별, 설계 아님):
- 150~151의 GameCatalog.isValidId 분기 + 154~172의 GameCatalog 기반 fallback 블록 전체가 제거 대상. game==null인 경로(150 진입 이후 전부)를 404 응답으로 대체해야 함. 즉 라인 150~172가 변경 영역.
- 신뢰도: 확인됨
---
## 트랙 B4 — Spring Boot / OWASP DC 버전 + 설정 (조사포인트 2,3,4)
### 포인트 2: Spring Boot 3.5.x 최신 stable(GA) 버전
- 요약: 현재 pom의 `3.5.14-SNAPSHOT`은 미출시 스냅샷. 3.5.x 계열 최신 **GA = 3.5.16** (2026-06-25 출시).
- v3.5.14 GA 2026-04-23 / v3.5.15 GA 2026-06-10 / v3.5.16 GA 2026-06-25(최신)
- 3.5.x 위로 4.0.x/4.1.x 별개 계열 존재(이번 트랙 범위 밖)
- 출처:
- https://spring.io/blog/category/releases — "Spring Boot 3.5.16 available now" (2026-06-25)
- https://github.com/spring-projects/spring-boot/releases — v3.5.16/3.5.15/3.5.14 확인
- 신뢰도: 확인됨 (spring.io 1차 + GitHub releases)
### 포인트 3-A: OWASP dependency-check-maven 최신 버전
- 요약: **12.2.2** (최신 GA).
- 동명 disambiguation: 원 저장소 `jeremylong/DependencyCheck`는 2025-09-27 아카이브됨. 관리 이관처 `dependency-check/DependencyCheck`. **Maven groupId는 동일하게 `org.owasp` 유지** — central.sonatype.com에서 `org.owasp:dependency-check-maven:12.2.2` latest로 확인됨(다른 groupId 아님).
- 현재 pom.xml에 OWASP DC plugin 없음(검색 0건).
- 출처:
- https://central.sonatype.com/artifact/org.owasp/dependency-check-maven/versions — 12.2.2 latest
- https://github.com/dependency-check/DependencyCheck/releases — v12.2.2 GA
- https://github.com/jeremylong/DependencyCheck — 이관 안내(2025-09-27 아카이브)
- 신뢰도: 확인됨 (Maven Central 1차 + GitHub releases)
### 포인트 3-B: 오프라인/NVD 무의존 설정 방법
- 요약(공식 configuration 문서 발췌 기준 — 전수 옵션 목록 아님):
- `autoUpdate` (기본 true): **false** 설정 시 NVD 자동 업데이트 비활성화 — 오프라인 핵심
- `dataDirectory` (기본 `~/.m2/.../dependency-check-data/`): 사전 다운로드한 로컬 NVD 캐시 위치 지정
- `nvdApiKey` (선택): **없어도 동작 가능**. 단 키 없으면 API 요청 간격이 8000ms로 늘어남(온라인 업데이트 시에만 영향, autoUpdate=false면 무관)
- `nvdDatafeedUrl`: 내부 NVD 미러 서버 지정(에어갭 지원). 별도 인프라 필요 → 상세는 범위 밖
- `failBuildOnCVSS` (기본 11=사실상 비활성, 0-10 범위): 특정 CVSS 이상 시 빌드 실패
- `skipProvidedScope` (기본 false): true면 provided scope 의존성 분석 생략
- 명시적 `--offline` 플래그는 **없음**. 오프라인 패턴 = `autoUpdate=false` + 사전채워진 `dataDirectory`. 한번 온라인에서 데이터 받아두면 이후 오프라인 재사용 가능.
- pom plugin 설정 예시(오프라인 친화, advisor가 검토할 후보 스니펫):
```xml
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>12.2.2</version>
<configuration>
<autoUpdate>false</autoUpdate>
<dataDirectory>${user.home}/.m2/repository/org/owasp/dependency-check-data</dataDirectory>
<failBuildOnCVSS>7</failBuildOnCVSS>
<skipProvidedScope>true</skipProvidedScope>
</configuration>
</plugin>
```
- 출처: https://jeremylong.github.io/DependencyCheck/dependency-check-maven/configuration.html
- 신뢰도: 확인됨 (옵션 존재·역할). 단 `failBuildOnCVSS=7`/`skipProvidedScope=true`의 구체 값 선택은 advisor 설계 결정(조사 산출 아님). 옵션 목록은 "공식 문서 발췌"이지 "전수 열거"가 아님.
### 포인트 4: 현 설정파일 정확 라인 (코드 사실)
#### 4-A: pom.xml 구조 (`/Users/wemadeplay/workspace/stz/bibimbap/pom.xml`)
- `spring-boot.version` property: **라인 29**, 값 `3.5.14-SNAPSHOT`
- `<repositories>` 블록: **라인 210~219** — spring-snapshots 1개(`https://repo.spring.io/snapshot`, releases disabled)
- `<pluginRepositories>` 블록: **라인 220~229** — spring-snapshots 1개(동일 URL, releases disabled)
- `<build><pluginManagement><plugins>`: 라인 100~155 — 9개 플러그인(clean/compiler/deploy/failsafe/install/resources/surefire/war/spring-boot)
- `<build><plugins>` (실행): **라인 157~208** — spring-boot-maven-plugin(157~169) + maven-compiler-plugin(170~207) 2개만. **OWASP plugin 추가 위치 = 이 블록 내**.
- profiles 빌드: dev(256~266), live(293~302)에 각각 spring-boot-maven-plugin profile용 추가
- 신뢰도: 확인됨
#### 4-B: application.properties (`src/main/resources/application.properties`, 31라인)
- `spring.profiles.active`: **라인 1**`@app.profile@` (Maven 필터링 치환)
- 세션 쿠키 설정(`server.servlet.session.cookie.*`): **0건 (없음)**
- `logging.level.org.apache.ibatis`: **라인 30**`TRACE`
- multipart: **라인 15~17**`spring.servlet.multipart.max-file-size=1GB`, `max-request-size=1GB`, `server.tomcat.max-http-form-post-size=1GB`
- (참고) 라인 21에 `spring.config.import`로 profile별 db.properties 로드
- 신뢰도: 확인됨
#### 4-C: profile별 properties 파일 존재 여부
- `application-dev.properties` / `application-live.properties` 형식 파일: **존재하지 않음**
- 대신 디렉토리 기반:
- `dev/db.properties` (존재, 8라인) + `dev/db.properties.example`
- `live/db.properties.example`만 존재 — **`live/db.properties`는 없음**
- `dev/db.properties` 내용: postgresql driver, url(localhost:5433/bibimbap?currentSchema=dev), username=bibimbap, password=change_me_local_dev, app.upload.game-storage-path, app.webgl.asset-origin(빈값), app.webgl.frame-ancestors=self
- 사실: B4가 "application-dev.properties/application-live.properties 신규/수정 대상"으로 가정한다면, **현재 그런 파일은 없고** profile 설정은 `dev/`·`live/` 디렉토리 + `spring.config.import` 패턴으로 관리됨. → 가정과 현행 구조 불일치(아래 미해결 참조)
- 신뢰도: 확인됨
---
## 종합 판단
### 삭제 안전성 판정 (B2)
| 대상 | 외부 참조 | 삭제 안전성 |
|---|---|---|
| `abstracts/` 패키지 4파일 | 패키지 외부 0건 (상속 구체클래스 0, import 0) | **삭제 안전** (컴파일·런타임 파손 없음) |
| `GameCatalog.java` | GameController.gameDetail()만 참조 | **GameController 동시수정 필요** — fallback 로직(라인 150~172) 제거/404대체 후라야 안전 |
| `header.jspf` | include 0건 | **삭제 안전** (어떤 JSP도 참조 안 함, 전부 /WEB-INF/views/header.jsp 사용) |
### 확정 버전값 (B4)
| 항목 | 확정값 | 신뢰도 |
|---|---|---|
| Spring Boot 3.5.x 최신 GA | **3.5.16** | 확인됨 |
| OWASP dependency-check-maven 최신 GA | **12.2.2** (groupId `org.owasp` 유지) | 확인됨 |
전 항목 1차 출처(spring.io / Maven Central / 프로젝트 코드 직접읽기)로 확인됨 → `source_confidence: high`. 차단 출처 fallback 없음.
## 미해결
- **B4 가정 vs 현행 구조 불일치**: 작업트랙 B4 설명이 "application-dev.properties / application-live.properties 신규/수정 대상"이라 가정하나, 현 프로젝트는 그런 파일이 없고 `dev/db.properties`·`live/db.properties`(+ `spring.config.import`) 패턴을 쓴다. 설정 추가를 어느 파일에 넣을지는 design-advisor가 현행 패턴 기준으로 재결정해야 함. (조사로 사실 확인 완료, 결정은 다운스트림)
- `live/db.properties` 부재 — live profile 활성 시 어디서 DB 설정을 받는지(배포 시 주입 등)는 이번 조사 범위 밖.
- GameCatalog.java의 배열 실제 값(NAMES/CREATORS 등 fallback이 제공하던 게임 목록)은 미조회 — 404 전환 시 사라지는 정적 게임 목록의 내용·개수가 필요하면 별도 조사.
- `nvdDatafeedUrl` 내부 미러 상세 구성은 별도 인프라 필요로 범위 밖.