---
kind: work-log
title: W2(게임잼) + W3(잔여) + W4 풀설계 — 통합 요약 / 설계 인덱스
description: 남은 W 워크스트림 11개 기능(W2-1~6, W3-1/3-3/3-4/3-5, W4)의 풀설계 산출 인덱스 + 크로스-W 결정 매트릭스 + 교차정합 감사 verdict + 골자 stale 정정 3건. 설계 전용 세션(코드 0줄). 설계 본문은 work-session implementation/ 에, 본 문서는 진입 인덱스. 착수 순서·미해결(운영검증) 포함.
status: active
source_session: 20260623-104307
resumed_from: 20260622-180054
source_skeletons:
  - 2026-06-23-w2-w4-feature-skeletons.md
  - 2026-06-17-w3-feature-skeletons.md
source_roadmap: 2026-06-17-jam-platform-roadmap.md
created_at: 2026-06-23
owner: art
---

# W2 + W3(잔여) + W4 풀설계 — 통합 요약 / 설계 인덱스

설계 전용 세션(코드 0줄, src/·pom.xml 무변경). 골자 → 미결 확정(정석 결정) → 풀설계 단계를 거쳐 **11개 기능 풀설계**를 산출했다. 각 설계는 W1-design.md 깊이(목표/DDL/API계약/시퀀스/파일영향맵/대안비교/롤아웃/AC매핑/검증포인트), **오픈질문 0**.

> 설계 본문: `.atp/work-session/20260623-104307/implementation/<W>-*.md`. 코드 grounding: `.atp/work-session/20260623-104307/research/`. 교차정합 감사: `.atp/work-session/20260623-104307/implementation/_cross-consistency-audit.md`.

## 미결질문 처리 방식 (이 세션 한정)

사용자가 "전체 설계를 개입 없이 직접, 빠른길 아닌 **확실하고 정석적**으로" 지시 → orchestrator 가 골자 QG/기능별 미결을 **정석 기준으로 직접 확정**해 design 에 주입(AskUserQuestion 면제, 명시 위임). 각 결정은 해당 설계의 "대안 비교" 표에 근거 보존 → 사용자가 설계도를 리뷰해 사후 override 가능.

## 설계 인덱스 (11)

| W | 설계 문서 | 핵심 결정(정석) | 신규 테이블/뷰 | 보안 |
|---|---|---|---|---|
| W2-1 잼 엔티티/라이프사이클 | W2-1-jam-entity-design.md | 조인테이블 jam_entries(다회차·정규화) + 개인/팀 XOR + 명시 status+감사 전이 + GAME_JAM_MANAGE enforcement 연결 + keyset 페이징 | jams, jam_teams, jam_team_members, jam_entries, jam_status_log | CSRF·GAME_JAM_MANAGE 게이트 |
| W2-2 심사위원 역할 | W2-2-judge-role-design.md | **별도 jam_judges**(전역 RBAC 불변, 잼 스코프 게이트) + JamRoleGate.isJudge + 자기출품 충돌규칙 | jam_judges | ★잼 스코프 권한 게이트 |
| W2-3 잼 평가 동결 ⚠️클러스터 권위 | W2-3-eval-freeze-design.md | 동결 스키마 + **평가단위=(jam_id,game_id) 활성 자연키** + 유저평점=avg_rating 단방향(기간/최소리뷰수 임계·NULLS LAST) + 평가기간 게이트 계약 | jam_criteria, jam_scores, jam_votes, jam_awards, jam_score_stats(VIEW) | 평가기간 게이트·VIEW alias |
| W2-4 심사위원 평가 | W2-4-judge-scoring-design.md | criterion별 UPSERT + 가중집계 + 3중게이트(isJudge·평가기간·자기출품) | (W2-3 소비, 0) | isJudge+기간+CSRF |
| W2-5 인기투표 | W2-5-popular-vote-design.md | jam_votes 1인1표 UNIQUE(잼당 최애1) + 평가기간 게이트 + 종료후 공개(밴드왜건 회피) | (W2-3 소비, 0) | 로그인+기간+UNIQUE+CSRF |
| W2-6 시상 집계 | W2-6-award-aggregation-design.md | 3트랙(심사/유저평점/인기) 개별수상 + 가중 GRAND + NULL/임계 제외 + CLOSED 확정 멱등 | (W2-3 jam_awards 소비) | 산정 권한·VIEW alias |
| W3-1 태그+검색 | W3-1-tags-search-design.md | 통합 tags+조인 + 운영자/유저생성 하이브리드(sanitize+금칙어) + game_views(dedupe)+view_count + 검색 확장(다중태그 AND/OR·개발자·정렬키) | tags, game_tags, jam_tags, game_views (+games.view_count) | 태그 sanitize/금칙어·CONTENT_MODERATE 게이트·#{} |
| W3-3 포스팅 보드 | W3-3-posting-board-design.md | posts/categories + **POST_WRITE enforcement 연결** + commonmark+jsoup sanitize + **공용 SsrfSafeFetcher(9항목)** OG+유니티피드 + @Scheduled 폴링 dedupe | post_categories, posts, unity_feed_sources, unity_feed_items | ★SSRF 9항목·마크다운 sanitize·POST_WRITE·CSRF |
| W3-4 메인 허브 | W3-4-main-hub-design.md | keyset 페이징(검색·비검색 단일화) + 진행중 잼 배너→W3-1 `GET /games/search?jam={slug}` 라우팅 + 단계 분리 | (없음, GamesMapper 확장) | 파라미터 #{}·escape |
| W3-5 Unity 업로드 | W3-5-upload-design.md | **zip-slip canonical+심링크 거부+zip bomb** + 포맷검증(wasm/data/loader) + 권한게이트 + UUID 원자교체. QG-3 정정 반영(/game/** 정상 서빙) | game_upload_audit_log | ★zip-slip·경로 boundary·권한게이트 |
| W4 유저 배지/평판 | W4-badges-design.md | badges/user_badges/reputation_events + 자동임계+수동 하이브리드 + **BADGE_MANAGE 신규키** + 표시(프로필/리뷰/카드) | badges, user_badges, reputation_events (+PermissionKeys BADGE_MANAGE) | 부여/회수 CSRF+BADGE_MANAGE·멱등 UNIQUE |

## 크로스-W 결정 매트릭스 (정석 확정값)

| 결정축 | 확정 | 영향 W | 근거(정석) |
|---|---|---|---|
| 잼 스코프 권한 (QG-W2-A) | 별도 jam_judges 테이블 | W2-2/4 | 잼 회차별 역할 = 잼 스코프 조인. 전역 user_permissions(RBAC) 오염 0 |
| 평가 단위 | (jam_id, game_id) 활성 자연키 | W2-1/3/4/5/6 | orchestrator 동결 컬럼 일치 + game_review_stats(game_id) join 정합 + entrant 종류 불투명 유지. jam_entries active-UNIQUE 가 1:1 보장(jam_entries.id surrogate FK 아님) |
| 유저평점 트랙 (QG-W2-B) | overall avg_rating | W2-3/6 | game_review_stats VIEW 기존 노출. 6축은 표시전용. 최소 review_count 임계 미달 제외·NULLS LAST |
| 잼 연결 (QG-W2-C1) | 조인테이블 jam_entries | W2-1 | 정규화·다회차 출품·games 무변경(허브 회귀 0) |
| 팀 출품 (QG-W2-C2) | 1차 포함(jam_teams) | W2-1 | 잼은 팀 이벤트 본질. XOR 로 개인/팀 정합 |
| 인기투표 단위 | 잼당 1인1표 최애(UNIQUE(jam_id,voter_user_id)) | W2-5 | game_likes(user_key varchar·비권위 UNIQUE) 재활용 안 함. 로그인 user_id 기반 |
| 권한키 | GAME_JAM_MANAGE/POST_WRITE/CONTENT_MODERATE(W1) + **BADGE_MANAGE 신규**. 태그=CONTENT_MODERATE 재사용 | W2-1/2, W3-1/3, W4 | POST_WRITE·GAME_JAM_MANAGE = W1 선언키 enforcement 연결(소비처 0→연결 신규). BADGE_MANAGE 만 신규(권한 분리) — **W1 AC-T1 카탈로그 카운트 3→4 갱신 필요** |
| 외부 fetch (SSRF) | 공용 SsrfSafeFetcher 9항목 | W3-3 | OG 미리보기+유니티피드 단일화. scheme allowlist·사설IP차단·DNS rebinding·redirect 재검증·size/timeout |
| DDL 권위 | docs/<feature>-ddl.sql 멱등 + schema.sql 동기 | 전 W | W1 docs/rbac-ddl.sql 선례. apply-local-ddl.sh 알파벳 멱등 적용 |

## 교차정합 감사 verdict

`_cross-consistency-audit.md` (general-purpose opus). **동결 단일권위(W2-3) 유지, 하류 W2-4/5/6 소비 정합 PASS.**
- HIGH 1건 → **해소**: W2-1 본문 "평가단위=jam_entries.id" 표현 drift(DDL 은 정합) → (jam_id,game_id) 자연키로 5개소 정정.
- MED 0. LOW 3(게이트 순서 표현차·vote mapper 시그니처·경로 예시차 — 전부 동결 허용범위/무해).
- Clean: 컬럼 정합·중복 DDL 없음(W2-5 jam_votes 는 참조 인용)·권한키 정합·cross-W 라우트·보안 존재성(잼게이트/SSRF/zip-slip 실재·비자명).

## 골자 stale 정정 3건 (착지 코드 대비)

1. **RBAC 인프라 실재** (W3 skeletons #3 "Interceptor 없음" 뒤집힘) — 단 enforcement 갭(POST_WRITE·GAME_JAM_MANAGE 키 선언만, 소비처 0). W2-1/W3-3 이 연결.
2. **리뷰 인프라 실재** (W3 skeletons #2 "review 테이블 없음" 뒤집힘) — 하이브리드(overall + 6축) + game_review_stats VIEW. W2-3/6·W3-1·W4 가 소비, 단일평균 가정 금지.
3. **/game/** 서빙 정상** (W3 skeletons QG-3 해소) — GameAssetController 가 전용 처리(버그 아님). W3-5 실 결함은 zip-slip 심링크·업로드 권한게이트 전무로 재조준.

## 착수 순서 (크리티컬 패스 + 병렬)

크리티컬 패스: W1(완료) → **W2-1 → W2-3 동결 → W2-6**.
1. W2-1 잼 엔티티(jams/entries/teams + GAME_JAM_MANAGE 연결)
2. W2-2 심사위원(jam_judges) — W2-1 후
3. W2-3 동결 — ⚠️클러스터 게이트, W2-4/5/6 착수 전 필수
4. W2-4 / W2-5 — 동결 후 병렬
5. W2-6 시상 — W2-4/5 후
6. 독립 병렬: W3-1(태그검색) · W3-3(포스팅) · W4(배지) — W2 무관. W3-4(허브)는 W3-1 후. W3-5(업로드)는 독립.

## 미해결 / 운영 검증 필요 (설계로 닫지 못한 것)

- **game_likes 운영 DB UNIQUE 제약** — schema.sql 비권위라 추정(grounding concern). W2-5 는 신규 jam_votes 로 무관하나, game_likes 정합은 별도 운영 DB 확인 권장.
- **구현 단계 점검 항목**(각 설계 concerns): 신규 매퍼 @MockBean full-test(§30), DB-방언 alias(§33), 시그니처 inflate(§11.2), W3-3 pom 의존(commonmark/jsoup)·@EnableScheduling, W4 의 W1 AC-T1 카운트 3→4 재측정, SSRF rebinding 라이브러리 제약 단위테스트.
- 이 미결들은 **설계 오픈질문이 아니라 구현/운영 단계 게이트** — 각 설계 concerns 에 이관됨.

## 다음 단계

설계 합의 후 착수 순서대로 implementation-advisor 진입(코드·마이그레이션). 착수 기능의 concerns(구현 점검) 를 verification-strategies L레벨로 통과시킨다. **이 세션은 설계까지 — 코드 0줄.**

## 구현 추적

- **W2 (W2-1~6) 구현 완료** — 2026-06-24, commit `ccf1e42`(W2-1)~`a74bf74`(W2-6), 6 feat. 최종 L1 190/190 GREEN(회귀 0) + L2 dev DB contract 전 PASS(격리 throwaway DB). 변경 이력: [changes/2026-06-24-w2-jam-platform.md](../changes/2026-06-24-w2-jam-platform.md). dev DB 마이그레이션·L3 스모크는 needs_user_verification.
- **W3(잔여)·W4 (W3-1·W3-4·W3-3·W3-5·W4) 구현 완료** — 2026-06-29(session 20260629-100849), commit `35f1dc3`(W3-1)~`305cc73`(W4), 5 feat. W3-2(댓글/리뷰)는 선행 완료. 최종 L1 347/347 GREEN(baseline 190→347, +157, 회귀 0) + L2 dev DB contract 전 PASS(격리 throwaway DB) + adversarial SSRF/zip-slip 감사(W3-3 vacuous SSRF 포착→option-b 전환). 변경 이력: [changes/2026-06-29-w3-w4-features.md](../changes/2026-06-29-w3-w4-features.md). 실 dev DB DDL 8종 일괄 적용·L3 스모크·W4 표시 deferral(게임카드 creator 배지)은 needs_user_verification.
- **풀설계 11기능 전부 구현 완료** (W2-1~6 + W3-1/3/4/5 + W4). W3-2 는 별도 선행. 잔여 미구현 설계 0.
