---
phase: requirements
agent: requirements-advisor
agent_version: 1
generated_at: 2026-06-17T18:10:00+09:00
concerns: []
concerns_checked: true
---

# W3 사이트 플랫폼 — 5개 서브기능 골자 카탈로그

## 원 요청

bibimbap(Spring Boot + MyBatis + JSP, Java 21) 프로젝트에서 W3(사이트 플랫폼 워크스트림) 5개 서브기능의 "골자(skeleton)" 카탈로그를 작성한다. 깊이는 윤곽 카탈로그로 확정. 미결질문은 해소하지 않고 목록으로 남긴다.

---

## 코드 현황 요약 (확인 결과)

확인 파일 근거:

1. **`games` 테이블 현황** — `GamesMapper.java`: id, user_id, name, creator_note, git_url, webgl_path, thumbnail_url, like_count, is_visible, sort_order, created_at, updated_at. 태그 컬럼 없음. 검색은 name/display_name/creator_note ILIKE 방식만 존재.
2. **`game_comments` 현황** — `GameCommentsMapper.java`: id, game_id, nickname, content, created_at, deleted_at, is_delete. 로그인 연동 없이 nickname 자유입력. content 글자수 제한 없음(DB 컬럼 타입 미확인). **review 테이블 없음(신규)**, **tag 테이블 없음(신규)**.
3. **권한 현황** — `UserData.java`에 `role` 필드 존재. `UserController.java`에 `ROLE_USER = "USER"` 상수만. **Interceptor 클래스 없음** — 인터셉터 미구현, 권한 게이트 없음(W3-3 포스터 게이트가 얹힐 자리 미비).
4. **`index.jsp` 현황** — 게임 카드 그리드 + 텍스트 검색(ILIKE). 잼 출품작 노출 없음. 섹션 단일(일반 게임만).
5. **WebGL 업로드 현황** — `GameUploadController.java`: `/api/game-files/webgl-zip` 이미 구현. zip-slip 방어·엔트리 수 상한(8000)·압축 해제 크기 상한(512MB) 적용됨. `/game/{uuid}/` 경로 배치 구현. **단, 로그인 체크만 있고 권한 체크 없음. `/game/**` 정적 파일 핸들러가 `UploadResourceConfig.java`에 미등록** — `/profile/**`만 등록, `/game/**` 핸들러 누락 확인.

---

## 기능 요구 (FR)

### W3-1 — 태그 + 검색

- **목적**: 일반 게임 발견성 향상이 1차. 잼 용도(진행 회차 강조, 이전 회차 검색)는 부수 기능.
- **핵심 동작**: 게임/잼에 태그를 붙이고, 태그로 필터링 검색한다. 기존 텍스트 검색과 병행.
- **결합/의존**:
  - `games` 테이블에 태그 연결 → 신규 `tags` + 조인테이블 필요(기존 코드에 없음, 신규).
  - 잼 태그 연결은 W2 게임잼 엔티티(`jams` 테이블) 존재 후에만 가능 — 잼 부분은 W2 선행 의존.
  - 단독 게임 태그 검색은 W2와 무관하게 독립 착수 가능.
  - `GamesMapper.searchVisibleGames`: 현재 ILIKE 방식 — 태그 필터 추가 시 쿼리 확장 필요.
- **주요 미결질문**:
  - Q1: 태그 관리 방식 — 자유입력(사용자 생성)인가, 운영자 사전 정의 목록인가, 혼합인가?
  - Q2: 태그당 게임 수 제한·태그명 최대 길이·허용 문자셋은?
  - Q3: 잼 전용 태그와 게임 공용 태그를 같은 `tags` 테이블로 통합하는가, 분리하는가?
  - Q4: 태그 검색 결과 정렬 기준(좋아요순/최신순/태그 일치도)은?
  - Q5: 다중 태그 AND/OR 조합 검색을 지원하는가?
- **후속 진입점**: design-advisor

---

### W3-2 — 댓글 / 리뷰 분리

- **목적**: 모든 게임 페이지의 일반 기능. 잼 평가기간 게이트 없음, 잼 독립.
- **핵심 동작**: 기존 `game_comments`(닉네임 자유입력)를 로그인 사용자 연동 댓글로 전환하고, 별도 리뷰(게임당 1회, 완성도+종합 평점) 기능을 신설한다. W2-6 시상이 리뷰 평점을 단방향으로 집계한다.
- **결합/의존**:
  - `game_comments` 테이블 기존 존재 — 단, nickname 자유입력 구조. 로그인 연동으로 변경 시 기존 데이터 처리 결정 필요(마이그레이션 우려 → concerns).
  - `game_reviews` 테이블 — 신규, 없음.
  - W2-6(시상)이 이 기능의 평점을 집계 — W2-6이 나중에 리뷰 평점 컬럼 계약을 요구함. W3-2 설계 시 집계 계약을 W2-3(평가 통합설계) 동결과 맞출 필요.
  - 현재 content 길이 제한 미적용 — 200자 제한 신규 적용 필요.
- **주요 미결질문**:
  - Q1: 기존 `game_comments`의 nickname 자유입력 레코드를 어떻게 처리하는가? (유지/마이그레이션/별도 표시)
  - Q2: 댓글 수정·삭제는 작성자 본인만인가, 운영자도 가능한가? 현재 updateGameComment가 있으나 권한 체크 없음.
  - Q3: 평점 척도 — 완성도 및 종합 각각 몇 점 만점인가? (예: 5점/10점)
  - Q4: 리뷰는 수정 가능한가? 게임당 1회 제한이면 수정 허용 여부와 수정 이력 관리 방식은?
  - Q5: W2-3 평가 통합설계와의 리뷰 평점 집계 계약을 W3-2 설계 단계에서 선확정해야 하는가, W2-3 동결 후 맞추는가?
- **후속 진입점**: design-advisor (W2-3 진행 상황 연계 확인 후)

---

### W3-3 — 포스팅 보드

- **목적**: 사이트 공지·블로그 + 외부링크 큐레이션. 별도 메뉴. 잼과 무관한 독립 콘텐츠 채널.
- **핵심 동작**: 포스터 권한자(W1 RBAC로 부여)만 작성. 카테고리(유니티블로그/세션/게임잼대상 후기인터뷰/뒤끝 개발팀) 선택. 일반 유저는 읽기만 가능.
- **결합/의존**:
  - W1(포스터 권한) 선행 필요 — `UserData.role` 필드는 존재하나, 현재 Interceptor 없음. 포스터 권한 게이트를 얹을 인터셉터·어노테이션 인프라가 W1에서 구현돼야 함.
  - `posts` 또는 `board_posts` 테이블 — 신규, 없음.
  - `RecruitPostsMapper`/`RecruitController` 참고 가능(유사 게시판 패턴 기존 존재).
- **주요 미결질문**:
  - Q1: W1 포스터 권한 인프라가 W3-3 착수 전에 완료돼야 하는가, 임시 하드코딩(role=="POSTER" 직접 체크)으로 먼저 구현하고 W1 완료 후 교체하는가?
  - Q2: 카테고리는 DB 저장인가, 코드 enum 고정인가?
  - Q3: 외부링크 큐레이션의 구체적 형태 — 링크 URL + 설명 텍스트만인가, OG 미리보기를 포함하는가?
  - Q4: 포스팅 본문 형식 — 순수 텍스트인가, 마크다운/HTML 허용인가? (XSS 영향)
  - Q5: 포스팅에 댓글(W3-2)을 붙일 수 있는가?
- **후속 진입점**: design-advisor (W1 진행 상황 확인 선행)

---

### W3-4 — 메인페이지 (게임 허브)

- **목적**: `index.jsp`를 게임 + 잼 출품작이 함께 노출되는 허브로 확장. 포스팅은 별도 메뉴이며 메인 통합 아님.
- **핵심 동작**: 현재 일반 게임 카드 그리드에 잼 출품작 섹션을 추가 노출. 진행 중인 잼 출품작 강조, 일반 게임과 시각적 구분.
- **결합/의존**:
  - 현재 `index.jsp`는 `GamesMapper.getVisibleGames()` / `searchVisibleGames()` 단일 소스 — 잼 출품작 섹션 추가 시 쿼리 확장 또는 분리 필요.
  - W2 게임잼 엔티티(`jams` 테이블, 잼-게임 조인) 선행 의존 — 잼 출품작 노출 부분만. 일반 게임 허브 개선은 W2 없이 가능.
  - W3-1 태그 검색 완료 시 메인 필터 UI 연동 가능(선택적 연계).
- **주요 미결질문**:
  - Q1: 잼 출품작 섹션의 노출 조건 — 진행 중인 잼이 있을 때만 표시하는가, 항상 섹션을 보여주는가?
  - Q2: 일반 게임과 잼 출품작이 같은 games 레코드를 재사용한다면, 메인에서 중복 노출 방지 정책은?
  - Q3: 게임 정렬·추천 로직 — 현재 sort_order ASC + created_at DESC 그대로 유지인가, 허브로 개편 시 큐레이션/인기순 등 다른 기준을 도입하는가?
  - Q4: 페이지네이션 또는 무한스크롤 도입 여부 — 현재 전체 목록 단일 조회.
  - Q5: W2 완료 전 메인 개선을 일반 게임 허브 부분만 먼저 착수할 수 있는가? (단계적 착수 가능 여부)
- **후속 진입점**: design-advisor

---

### W3-5 — Unity WebGL 빌드 업로드 자동화 (deferred — 선행 조사 스텁)

- **목적**: 일반 게임 호스팅 자동화. 현 수동 호스팅 대체. 게임잼과 무관한 인프라.
- **현황**: `GameUploadController.java`에 `/api/game-files/webgl-zip` 구현 존재. zip-slip 방어·크기 상한(512MB 압축 해제, 엔트리 수 8000) 적용. UUID 기반 `/game/{uuid}/` 배치 로직 구현. **단, `/game/**` 정적 리소스 핸들러가 `UploadResourceConfig.java`에 미등록** — `/profile/**`만 등록 확인.
- **선행 조사 필요 항목**:
  - zip-slip 방어 충분성 검증 — 현 구현 `target.startsWith(targetDir)` 체크 존재하나, 심볼릭 링크·인코딩 우회 케이스 검토 필요.
  - Unity WebGL 빌드 포맷 검증 — index.html 탐지 외 필수 파일(Build/*.data, Build/*.wasm, Build/*.js) 존재 여부 검증 범위.
  - 업로드 크기/타입 상한 — 현재 압축 해제 후 512MB, zip 원본 크기 상한 미확인. Content-Type 검증이 MIME 헤더 + 확장자 이중 체크인지 검토.
  - 저장 경로 boundary — `app.upload.game-storage-path` 설정값 외부 주입 시 경계 검증.
  - `/game/**` 정적 핸들러 미등록 문제 — 현재 업로드 후 실제 서빙 경로 동작 미보장.
  - 업로드 권한 게이트 — 현재 로그인 체크만, 권한 제한 없음(누구나 업로드 가능).
  - 기존 레코드 덮어쓰기/삭제 정책 — UUID 재사용 시 처리.
- **주요 미결질문 (= 조사 항목)**:
  - Q1: `/game/**` 정적 핸들러 미등록 — 의도적 누락인가, 버그인가? (현재 동작 확인 필요)
  - Q2: 업로드 권한 범위 — 로그인 사용자 전체 허용인가, 특정 권한(W1)자만인가?
  - Q3: 빌드 포맷 검증 수준 — index.html 존재 확인으로 충분한가, WebGL 필수 파일 구조 검증까지 하는가?
  - Q4: 업로드 후 게임 등록 플로우 — 업로드와 `games` 테이블 등록이 별도 단계인가, 자동 연동인가?
  - Q5: 스토리지 전략 — 현재 로컬 파일시스템, 향후 오브젝트 스토리지(S3 등) 전환 계획 있는가?
- **후속 진입점**: research-advisor (조사 완료 후 design-advisor)

---

## 비기능 요구 (NFR)

- **NFR-보안**:
  - W3-3 포스팅: 포스터 권한 게이트 미구현 상태 — W1 인터셉터 선행 없이 착수 시 임시 role 체크로 XSS/권한 우회 위험 있음.
  - W3-2 댓글: 현재 content 길이 제한 없음 — 200자 제한 서버사이드 검증 신규 적용 필요.
  - W3-5 업로드: zip-slip 방어 존재하나 심볼릭 링크 우회 검토 미완.
- **NFR-호환성**: W3-2에서 기존 `game_comments` 닉네임 자유입력 레코드의 호환 처리 결정 필요(스키마 변경 강제 — concerns 이관).
- **NFR-운영**: W3-5 `/game/**` 정적 핸들러 미등록 — 현재 배포 시 게임 서빙 경로 동작 불명확.
- **NFR-성능**: W3-4 메인 — 현재 전체 목록 단일 쿼리. 게임 수 증가 시 페이지네이션 미적용 상태.

해당 없음 항목: 접근성(이 단계 스코프 외), i18n(한국어 단일 서비스).

---

## 스코프

- **포함**: W3-1~W3-5 각 기능의 목적·핵심 동작·결합 지점·미결질문 윤곽. 코드 현황 대조.
- **제외**: DDL/SQL, API 경로, 시퀀스 다이어그램, 구현 세부. W1·W2 자체 설계. W4 유저 배지.

---

## 가정 / 추측

- `game_comments`의 content 컬럼 타입은 TEXT로 추정 — 현재 코드에서 길이 제한 없으므로. 확정은 DB 스키마 직접 확인 필요.
- `UserData.role` 필드의 현재 허용값은 "USER" 확인, 다른 값(ADMIN/POSTER 등)은 코드에서 미확인 — 확정 필요.
- `RecruitPostsMapper` 패턴이 W3-3 포스팅 보드 구현 참고 대상으로 적합하다고 추정(유사 게시판 구조).

---

## 확정 필요 (오픈 질문 — 기능 인라인 목록 외 전체 수준)

- QG-1: W1 인터셉터 구현 완료 시점과 W3-3 포스팅·W3-5 업로드 권한 게이트 착수 순서 — W1이 늦어질 경우 임시 role 직접 체크 허용 여부.
- QG-2: W3-2 댓글의 기존 닉네임 자유입력 레코드 처리 — 마이그레이션, 유지, 또는 레거시 표시?
- QG-3: W3-5의 `/game/**` 정적 핸들러 미등록이 의도적인지 확인 — 현재 WebGL 서빙이 실제로 동작하는지.

---

## 워크스트림 결합 요약

| 기능 | 결합 대상 | 결합 방식 | 독립 출시 가능? |
|---|---|---|---|
| W3-1 태그+검색 | W2(게임잼 엔티티) | 잼 태그 노출 시 의존, 게임 태그는 독립 | 부분 가능 (게임 태그 먼저) |
| W3-2 댓글/리뷰 | W2-6(시상 집계) | 리뷰 평점을 W2-6이 단방향 집계 | 가능 (잼 독립) |
| W3-3 포스팅 보드 | W1(포스터 권한/인터셉터) | 권한 게이트 의존 | W1 선행 필요 (또는 임시 체크) |
| W3-4 메인 허브 | W2(게임잼 엔티티) | 잼 출품작 섹션 노출 시 의존 | 부분 가능 (일반 게임 개선 먼저) |
| W3-5 WebGL 자동화 | 없음 (일반 인프라) | 독립 | deferred (선행 조사 후) |

---

## 착수 순서 제언

독립도 기준 추천 진입 순서(제언, 단정 아님):

**W3-2(댓글/리뷰 분리) 먼저** — W1/W2 무관 완전 독립, 기존 코드(`game_comments`) 위에 확장이므로 착수 비용 최소. 단, W2-3 리뷰 평점 집계 계약 조율은 병행 필요.
**다음 W3-1(태그+검색, 게임 태그 부분)** — 게임 태그 단독은 W2 불필요, 발견성 개선 즉시 효과.
**다음 W3-4(메인 허브, 일반 게임 부분)** — W2 없이 일반 게임 허브 개선 먼저 가능.
**W3-3(포스팅)** — W1 인터셉터 인프라 선행 후.
**W3-5(WebGL 자동화)** — 선행 조사 완료 후, deferred.
