bibimbap/docs/work-log/2026-06-17-w3-feature-skele...

168 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
kind: work-log
title: W3 사이트 플랫폼 — 기능별 골자 카탈로그
description: W3(사이트 플랫폼 워크스트림) 5개 서브기능(W3-1 태그+검색 / W3-2 댓글·리뷰 / W3-3 포스팅 보드 / W3-4 메인 허브 / W3-5 Unity업로드 deferred)의 골자. 기능당 목적·핵심동작·결합/의존·미결질문·후속진입점. 윤곽 카탈로그 깊이 — 미결질문 해소 안 하고 남김. 당장 구현 아님, 착수 전 굳혀두는 기획 메모.
status: confirmed
source_roadmap: 2026-06-17-jam-platform-roadmap.md
source_session: 20260617-172407
confirmed_session: 20260617-174635
confirmed_at: 2026-06-18
created_at: 2026-06-17
owner: art
---
# W3 사이트 플랫폼 — 기능별 골자 카탈로그
상위 로드맵: [2026-06-17-jam-platform-roadmap.md](./2026-06-17-jam-platform-roadmap.md) §W3.
**깊이**: 윤곽 카탈로그. 기능당 목적·핵심동작·결합/의존·미결질문·후속진입점만 굳혀둔다. DDL/API 계약/시퀀스는 기능별 착수(design) 단계에서. **미결질문은 해소하지 않고 남긴다** — 골자의 목적은 "무엇을/왜 + 무엇이 미결인지"를 1페이지로 굳히는 것. 당장 구현 아님.
> W3 전부 잼 일정 독립(독립 출시 가능). 게임잼(W2)은 W3 기능의 소비자 중 하나일 뿐.
---
## 코드 현황 (착수 전 확인된 결합점)
골자의 "결합/의존" 정확도를 위해 현 코드베이스를 대조했다. file 근거:
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/creator_note ILIKE 방식만.
2. **`game_comments`** (`GameCommentsMapper.java`) — id, game_id, **nickname(자유입력)**, content, created_at, deleted_at, is_delete. 로그인 연동 없음. content 길이 제한 없음. **review 테이블·tag 테이블 모두 없음 → W3-1·W3-2 구조 전부 신규.**
3. **권한 인프라**`UserData.role` 필드 존재, `UserController``ROLE_USER="USER"` 상수만. **Interceptor 클래스 없음** (`WebMvcConfigurer` 구현체에 `addInterceptors` 없음). W3-3 포스터 게이트가 얹힐 자리 미비 → W1 의존 강화.
4. **`index.jsp`** — 게임 카드 그리드 + 텍스트 검색(ILIKE) 단일 섹션. 잼 출품작 노출 없음.
5. **WebGL 업로드** (`GameUploadController.java`) — `/api/game-files/webgl-zip` 이미 구현. zip-slip 방어·엔트리 수 상한(8000)·압축 해제 크기 상한(512MB)·UUID 기반 `/game/{uuid}/` 배치 적용. **단 (a) 로그인 체크만, 권한 체크 없음 (b) `/game/**` 정적 핸들러가 `UploadResourceConfig.java` 에 미등록** — `/profile/**` 만 등록. → 서빙 경로 동작 미보장(QG-3, 의도/버그 미확인).
---
## 기능별 골자
### W3-1 — 태그 + 검색
- **목적**: 일반 게임 발견성 향상이 1차. 잼 용도(진행 회차 강조, 이전 회차 검색)는 부수.
- **핵심 동작**: 게임/잼에 태그를 붙이고 태그로 필터 검색(기존 텍스트 검색과 병행). 개발자(제작자) 검색 지원. 정렬은 태그 일치도 가중 × 2차 정렬키(좋아요/최신/방문수/리뷰수/점수).
- **결합/의존**:
- C1: 신규 `tags` + 조인테이블 필요(현 코드에 태그 구조 없음). — 코드사실
- C2: 잼 전용 태그 연결은 W2 게임잼 엔티티 선행 의존.
- C3: 게임 태그 기본 기능은 W2 무관 독립 착수 가능. **단 정렬 일부는 의존** — 리뷰수·점수 정렬은 W3-2, 방문수 정렬은 신규 조회수 인프라.
- C4: `GamesMapper.searchVisibleGames` ILIKE 쿼리 확장 필요. — 코드사실
- C5: 방문수 정렬 → 신규 조회수 카운터 필요(games 에 `like_count`만, 조회수 컬럼 없음). — 코드사실
- C6: 리뷰수·점수 정렬 → W3-2(`game_reviews`) 의존. 정렬 점수의 정확한 의미(단일 평점 vs 다축)는 W3-2 설계 종속.
- C7: 개발자 검색 → `games.user_id` ↔ user 조인 확장.
- 태그 테이블 구조: **통합 1테이블 + 용도 구분(게임 공용/잼 전용)** 권장. 잼 태그 요건(W2) 확정 시 분리 재검토.
- **미결질문** (합의된 방향 + 잔여):
- Q1 태그 관리: 출시는 운영자 사전정의, 구조는 혼합(운영자 사전정의 + 사용자 생성) 지원. *잔여*: 사용자 생성 태그 개방 시점·승인 흐름.
- Q2 제한·허용: 태그당 게임 수·게임당 태그 수 제한 없음. 허용 조건은 보안(주입·XSS sanitize) + 욕설/금칙어 필터 통과. *잔여*: 태그명 길이·허용 문자셋 구체값, 금칙어 사전 출처.
- Q3 테이블 구조: 통합 1테이블 채택(위 결합/의존). *잔여*: 잼 태그 요건 확정 시 분리 여부.
- Q4 정렬: 태그 미선택=최신순(기본), 태그 미선택+좋아요=전체 좋아요순, 태그 선택=태그 일치도 가중+2차키(최신/좋아요/방문수/리뷰수/점수). *잔여*: 태그 일치도 가중 계산·동률 처리는 design 단계.
- Q5 다중 태그·개발자 검색: 다중 태그 AND/OR 지원 + 개발자(제작자) 검색 추가. *잔여*: AND/OR 노출·입력 방식은 design 단계.
- **후속 진입점**: design-advisor
### W3-2 — 댓글 / 리뷰 분리
> **구현 완료** (2026-06-18, 세션 20260618-104034). 변경 이력: [changes/2026-06-18-w3-2-comments-reviews.md](../changes/2026-06-18-w3-2-comments-reviews.md). L1 31테스트 PASS. L3 스모크·DDL 적용은 사용자 확인 필요.
- **목적**: 모든 게임 페이지 일반 기능. 잼 평가기간 게이트 없음, 잼 독립.
- **핵심 동작**: 기존 `game_comments`(닉네임 자유입력)를 로그인 사용자 연동 댓글로 전환 + 별도 리뷰(게임당 1회) 신설. 리뷰 = **별점 5점 평점 + 서술 평가**, 다축(육각형 레이더)은 후속 확장 여지. W2-6 시상이 리뷰 평점을 **단방향 집계**. 댓글 content 200자 제한 신규.
- **결합/의존**:
- ①: `game_comments` 기존 존재 — 닉네임 자유입력, 로그인 연동 없음 → 로그인 연동 전환 시 기존 데이터 처리 결정 필요. — 코드사실
- ②: `game_reviews` 신규 (review 테이블 없음). — 코드사실
- ③: W2-6 시상이 리뷰 평점을 단방향 집계 → W2-3(평가 통합설계) 동결과 정합 필요. — 해석
- ④: 댓글 content 200자 제한 신규 (현 `game_comments` content 길이 제한 없음). — 코드사실
- ⑤: W3-1 의 리뷰수·점수 정렬이 W3-2(평점·리뷰수)에 의존 — W3-1 C6 의 역방향. — 신규
- **미결질문** (합의된 방향 + 잔여):
- Q1 기존 닉네임 레코드 처리: **미결로 유지** (전체수준 QG-2 사안 — 골자 단계 해소 보류).
- Q2 댓글 수정·삭제 권한: 작성자 본인 + 운영자. *잔여*: `updateGameComment` 권한 체크 신규 적용 범위는 design.
- Q3 평점 척도: 별점 5점(초기 단일), 다축(육각형) 후속 확장 여지. *잔여*: 다축 시 축 구성·완성도/종합 분리 여부는 design.
- Q4 리뷰 수정: 수정 가능 + 이력 보존, 노출은 "수정됨" 마커만 표시. *잔여*: 이력 열람 권한은 design.
- Q5 W2-3 평점 집계 계약: W2-3 동결 후 정합 (W3-2 선확정 안 함).
- Q6 *(신규)* 리뷰 단위: 업데이트 단위 분리 여부 + 나눠도 통합 평점 여부 — 미결 유지.
- **후속 진입점**: design-advisor (W2-3 진행 연계 확인 후)
### W3-3 — 포스팅 보드
- **목적**: 사이트 공지·블로그 + 외부링크 큐레이션. **별도 메뉴**, 잼 무관 독립 채널.
- **핵심 동작**: 포스터 권한자(W1 RBAC 부여)만 작성, 일반 유저 읽기만(댓글 없음). 카테고리는 운영자가 추가/수정/삭제 가능(DB 저장). 본문은 **마크다운 류 여러 서식(sanitize)**. 외부링크 큐레이션은 **OG 미리보기 포함**. 유니티블로그는 고정 카테고리가 아니라 **외부 피드(레퍼런스) 감시 — 새 글 게시 감지 후 알림** 형태로 별도 취급.
- **결합/의존**:
- C1: **W1 선행 필요**`UserData.role` 존재하나 Interceptor 미구현. 권한 게이트 인프라가 W1 에서 구현돼야 함. — 코드사실
- C2: `posts`/`board_posts` 신규.
- C3: `RecruitPostsMapper`/`RecruitController` 유사 게시판 패턴 참고 가능. — 코드사실(참고)
- C4: *(신규)* 외부 fetch 인프라 — OG 미리보기 + 유니티블로그 피드 감시 → SSRF 방어·캐싱·실패처리·폴링 필요. — 신규
- **미결질문** (합의된 방향 + 잔여):
- Q1 착수 시점: **W1 완료 후 착수** (임시 role 직접 체크 안 함). → 전체수준 QG-1 의 W3-3 부분 결정. *(W3-5 권한 부분은 여전히 미결)*
- Q2 카테고리 저장: DB 저장 (운영자 추가/수정/삭제 가능).
- Q3 외부링크: OG 미리보기 포함. *잔여*: SSRF 방어·캐싱·실패처리 방식은 design.
- Q4 본문 형식: 마크다운 류 여러 서식(sanitize). *잔여*: 허용 서식 범위·sanitize 정책은 design.
- Q5 댓글 부착: **붙이지 않음** (읽기 전용 채널). → W3-2 결합 없음.
- Q6 *(신규)* 유니티블로그 외부 피드 감시: 새 글 게시 감지 → 알림 형태. *미결*: 확인 방식(RSS/폴링)·알림 표면·갱신 주기.
- **후속 진입점**: design-advisor (W1 진행 확인 선행)
### W3-4 — 메인페이지 (게임 허브)
- **목적**: `index.jsp` 를 게임 허브로 확장 + 진행 중 잼 안내. 포스팅은 별도 메뉴(메인 통합 아님).
- **핵심 동작**: 평소엔 현 게임 카드 그리드 전체 노출(현 정렬 유지). 진행 중 잼 있을 때만 **검색창 아래에 "게임잼 진행 중" 안내 + 신규 출품작 강조**, 클릭 시 **게임잼 태그 검색(W3-1)으로 이동**. (별도 잼 섹션 그리드 아님.) 페이지네이션/무한스크롤 도입.
- **결합/의존**:
- C1: 현 `index.jsp``GamesMapper.getVisibleGames()`/`searchVisibleGames()` 단일 소스. — 코드사실
- C2: 잼 노출(검색창 아래 안내·신규작 강조·클릭 라우팅) = **W2(잼 엔티티·진행 상태) + W3-1(잼 태그 검색)** 의존. — 신규/해석
- C3: 일반 게임 허브 개선(페이지네이션·그리드)은 W2/W3-1 무관 독립.
- **미결질문** (합의된 방향 + 잔여):
- Q1 잼 노출 조건: 진행 중 잼 있을 때만.
- Q2 노출 형태: 별도 그리드 섹션 대신 검색창 아래 안내 배너 + 신규작 강조 → 클릭 시 잼 태그 검색. 평소 전체 게임 그대로. *(별도 그리드 없어 중복 노출 문제 해소)*
- Q3 정렬·추천: 현 정렬 유지(`sort_order` ASC + `created_at` DESC). 인기순은 후속.
- Q4 페이지네이션: 도입. *잔여*: 페이지네이션 vs 무한스크롤 택은 design.
- Q5 단계 착수: **단계 착수 가능** — 일반 허브(페이지네이션·그리드) 먼저, 잼 안내는 W2+W3-1 후.
- **후속 진입점**: design-advisor
### W3-5 — Unity WebGL 빌드 업로드 자동화 ⏸ deferred
> 골자 아님 — **선행 조사 스텁**. 조사 완료 후 골자/설계 진입.
- **목적**: 일반 게임 호스팅 자동화. 현 수동 호스팅 대체. 게임잼 무관 인프라.
- **현황**: 업로드 로직 부분 구현 존재(위 코드현황 5). zip-slip·크기상한·UUID 배치 됨. **권한 체크 없음 + `/game/**` 정적 핸들러 미등록.**
- **선행 조사 항목**:
- zip-slip 방어 충분성 — 현 `target.startsWith(targetDir)` 외 심볼릭 링크·인코딩 우회 케이스.
- WebGL 빌드 포맷 검증 범위 — index.html 외 필수 파일(Build/*.data, *.wasm, *.js) 존재 검증.
- 업로드 크기/타입 — zip 원본 크기 상한, Content-Type MIME+확장자 이중 체크 여부.
- 저장 경로 boundary — `app.upload.game-storage-path` 외부 주입 시 경계 검증.
- `/game/**` 정적 핸들러 미등록 — 서빙 동작 미보장(QG-3).
- 업로드 권한 게이트 — 현 로그인만, 권한 제한 없음.
- UUID 재사용 시 기존 레코드 덮어쓰기/삭제 정책.
- **착수 전 합의(이번 세션)**: 조사 항목 7개 그대로 유지. 업로드 권한 게이트는 QG-1 미결로 유지(조사 단계 확정). QG-3(`/game/**` 핸들러)는 코드 확인을 조사 단계로 미룸.
- **후속 진입점**: research-advisor → (조사 후) design-advisor
---
## 워크스트림 결합 요약
| 기능 | 결합 대상 | 결합 방식 | 독립 출시 |
|---|---|---|---|
| W3-1 태그+검색 | W2(잼 태그) + W3-2(리뷰수·점수 정렬) + 조회수 인프라(방문수 정렬) | 잼 태그·정렬 일부 의존, 게임 태그 코어는 독립 | 부분 (게임 태그 코어 먼저) |
| W3-2 댓글/리뷰 | W2-6(시상 집계) + W2-3(평점 계약 정합) + W3-1(정렬이 평점·리뷰수 소비) | 리뷰 평점을 W2-6 단방향 집계, W3-1 정렬이 역참조 | 가능 (댓글·리뷰 코어 독립, 평점 집계 계약은 W2-3 동결 후) |
| W3-3 포스팅 보드 | W1(포스터 권한/인터셉터) + 외부 fetch 인프라(OG·유니티블로그 피드) | 권한 게이트 의존, W1 완료 후 착수(임시 체크 안 함) | W1 선행 |
| W3-4 메인 허브 | W2(잼 엔티티·진행 상태) + W3-1(잼 태그 검색 라우팅) | 잼 안내·신규작 강조→잼 태그 검색 의존, 일반 허브는 독립 | 부분 (일반 허브 먼저, 잼 안내는 W2+W3-1 후) |
| W3-5 WebGL 자동화 | 없음 (일반 인프라) | 독립 | deferred (조사 선행) |
---
## 착수 순서 제언 (단정 아님 — 이번 세션 합의)
> 의존 사슬: W3-2(평점 공급) → W3-1(정렬이 평점 소비) → W3-4(잼 안내가 잼 태그 검색으로 라우팅). W3-3·W3-5 는 W1 권한 게이트 선행.
1. **W3-2 댓글/리뷰** — 기존 `game_comments` 확장, 코어 완전 독립, 착수 비용 최소. 다른 기능의 평점 공급원. 평점 집계 계약만 W2-3 동결 후 정합.
2. **W3-1 태그+검색** — W3-2 뒤에 오면 리뷰수·점수 정렬까지 완성. 게임 태그 코어는 독립, 정렬 일부는 W3-2·조회수 인프라 의존.
3. **W3-4 메인 허브 (일반 부분 먼저)** — 페이지네이션·그리드 개선은 독립 선착수. 잼 안내(검색창 아래 배너→잼 태그 검색)는 W2+W3-1 후.
4. **W3-3 포스팅** — W1 Interceptor 선행(임시 체크 안 함 확정). OG·유니티블로그 외부 fetch 인프라 동반.
5. **W3-5 WebGL 자동화** — deferred, 선행 조사 완료 후.
---
## 전체 수준 미결질문 (착수 전 확정 필요)
- **QG-1**: W1 인터셉터 완료 시점과 권한 게이트 착수. **W3-3 은 W1 완료 후 착수(임시 role 직접 체크 안 함)로 확정.** W3-5 업로드 권한은 미결 유지(조사 단계 확정). *잔여*: W1 지연 시 W3-5 임시 체크 허용 여부.
- **QG-2**: W3-2 기존 닉네임 자유입력 레코드 처리 — 마이그레이션/유지/레거시 표시. **미결 유지 확정**(골자 단계 해소 보류).
- **QG-3**: W3-5 `/game/**` 정적 핸들러 미등록이 의도인지 버그인지 — 현 WebGL 서빙 실제 동작 확인 필요. **코드 확인을 조사 단계로 미룸 확정.**
---
## 다음 단계
골자 합의 완료(이번 세션 — 5기능 + 착수 순서). 각 기능을 실제 착수할 때 위 "후속 진입점" advisor 로 진입한다. 착수 전 해당 기능의 *잔여* 미결 + 관련 QG 를 먼저 확정한다. **착수 1순위 = W3-2 로 확정.**