위협 가이드를 관리자 전용 옵션으로(기본 꺼짐) + 최고관리자 추가 + 계정 메뉴에 관리자 메뉴

- 엔진: GameDefinition.adminOnlyOptions — 방은 항상 관리자 값 사용(잠금처럼 강제, 잠금 안내는 안 띄움)
- 오목·체스·장기 threatHints, 바둑 atariWarning: 기본 false, 대기실 설정에서 뺌, 관리자 화면 게임 기본 규칙에서만 켬
- 체스·장기 hints는 off / moves만 남김
- 최고관리자 기본값에 1352267557213573160 추가(.env.example·문서 포함)
- 상단 계정 메뉴: 관리자·최고관리자면 [🛠 관리자 메뉴] → /admin
- 테스트: admin.test(관리자 전용 옵션 강제, 두 번째 최고관리자), admin.e2e(계정 메뉴, 위협 가이드 켜기 저장)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
EJClaw
2026-10-07 15:59:32 +09:00
parent 4cb71d8cbe
commit 373231b553
32 changed files with 207 additions and 45 deletions

View File

@@ -24,6 +24,7 @@
| `idleLimitSec` | `none`일 때 무응답 한도 | 300 / 600 | 600 |
| `undo` | 무르기 허용 횟수(1인당, 상대 동의) | `off` / `1` / `3` / `unlimited` | `3` |
| `drawOffer` | 무승부(빅) 합의 제안 허용 | `true` / `false` | `true` |
| `atariWarning` | **관리자 전용** 위협 가이드: 단수에 몰린 내 돌 표시(방장은 못 바꿈) | `true` / `false` | `false` |
| `scoringDeadlineSec` | 사석 확인 단계 제한 시간 | 120 / 180 / 300 | 180 |
| `disconnectGraceSec` | 연결 끊김 유예 | 60 / 120 / 300 | 120 |
@@ -191,7 +192,7 @@ interface BadukState {
### 8.3 공개/비공개 정보 (view)
- 모두 공개(플레이어·관전자 동일): 판, 차례, 포로 수, 기보, 단계, 사석/빅 표시와 계가 미리보기, 양쪽 동의 여부, 시계(기본 시간, 초읽기 남은 횟수, `deadline`), 대기 중인 요청, 결과.
- 차례인 플레이어에게만 편의 정보: `illegalPoints`(패·자충으로 둘 수 없는 점). 단수 경고 같은 위협 표시는 보내지 않는다.
- 차례인 플레이어에게만 편의 정보: `illegalPoints`(패·자충으로 둘 수 없는 점), `atariWarnings`.
- view에서 제외: `rng`, `positionHistory`(크기 문제로 제외, 필요하면 기보로 재구성), `situationCounts`.
### 8.4 랜덤 요소 (시드 RNG 사용 지점)
@@ -254,7 +255,7 @@ interface BadukResult {
- [ ] `scoring` 단계 시간 초과 → 미응답자 자동 동의 후 계가.
- [ ] 연결 끊김 유예 후 시간패, 재접속 시 유예 해제.
- [ ] 무르기 수락 시 따낸 돌이 복원되고 포로 수·슈퍼코 이력이 재생으로 정확히 복원.
- [ ] 정보 누출: view에 `rng`, `positionHistory`, `situationCounts`가 없는지. 관전자 view에 `illegalPoints` 없음.
- [ ] 정보 누출: view에 `rng`, `positionHistory`, `situationCounts`가 없는지. 관전자 view에 `illegalPoints`/`atariWarnings` 없음.
- [ ] 리플레이 결정성: 같은 시드·액션 로그 → 같은 결과.
## 11. 참고 자료

View File

@@ -20,7 +20,8 @@
| `drawOffer` | 무승부 제안 | `true` / `false` | `true` |
| `firstMoveSec` | 첫 수 제한(넘기면 대국 취소) | 15 / 30 / 60 | 30 |
| `idleLimitSec` | `timeControl=none`일 때 무응답 한도 | 300 / 600 | 600 |
| `hints` | 초보 도움말(이동 가능 칸 표시). 공격받는 기물 경고 같은 위협 표시는 두지 않는다 | `off` / `moves` | `moves` |
| `hints` | 초보 도움말(이동 가능 칸 표시) | `off` / `moves` | `moves` |
| `threatHints` | **관리자 전용** 위협 가이드: 공격받고 방어 안 된 내 기물 표시(방장은 못 바꿈) | `true` / `false` | `false` |
| `disconnectGraceSec` | 연결 끊김 유예 | 30 / 60 / 120 | 60 |
## 3. 구성물
@@ -140,9 +141,9 @@ interface ChessState {
### 8.3 공개/비공개 정보 (view)
- 공통 공개: `fen`, 기보(SAN), 마지막 수, 체크 여부, 시계, `deadline`, 잡은 기물 목록과 기물 점수 차(표시용: 퀸9 룩5 비숍3 나이트3 폰1), 대기 중인 요청, `claimable`, 결과.
- 차례인 플레이어에게: `legalMoves: { from; to; promotion?; castle? }[]`(하이라이트용).
- 차례인 플레이어에게: `legalMoves: { from; to; promotion?; castle? }[]`(하이라이트용). `threatHints`가 켜졌으면 `threatenedSquares`(내 기물 중 공격받고 방어 안 된 칸).
- 차례가 아닌 플레이어: 프리무브 UI를 위해 자기 기물의 의사 합법 수를 클라이언트에서 계산하지 않고, v1은 프리무브 미지원(단순성·공정성).
- 관전자: `legalMoves` 없음.
- 관전자: `legalMoves`/`threatenedSquares` 없음.
- 제외: `rng`(960 배치는 셋업 직후 공개되므로 문제없지만 다음 대국 배치 예측 방지).
### 8.4 랜덤 요소 (시드 RNG 사용 지점)
@@ -203,7 +204,7 @@ interface ChessResult {
- [ ] Chess960: n=518이 표준 배치, 960개 번호 모두 비숍 반대 색·킹이 두 룩 사이 조건 만족·서로 다름, 킹이 g열에 이미 있는 배치에서 킹사이드 캐슬링(킹 0칸 이동), 룩 경로·킹 경로·도착 칸 막힘/공격, 룩이 도착 칸을 가리던 경우, 권리 상실, 무르기 후 권리 복원, 무작위 960 대국(`chess.test.ts`), perft(`chess.perft.test.ts`).
- [ ] 무르기: 1/2 플라이 복원 후 `repetition` 카운트 정확, 거절 시 무변화.
- [ ] 연결 끊김 유예 후 시간패 처리.
- [ ] 정보 누출: 관전자·비차례 플레이어 view에 `legalMoves` 없음, 모든 view에 `rng` 없음.
- [ ] 정보 누출: 관전자·비차례 플레이어 view에 `legalMoves`/`threatenedSquares` 없음, 모든 view에 `rng` 없음.
- [ ] 리플레이 결정성(같은 시드 → 같은 960 배치와 결과).
## 11. 참고 자료

View File

@@ -23,7 +23,8 @@
| `idleLimitSec` | `none`일 때 무응답 한도 | 300 / 600 | 600 |
| `undo` | 무르기 허용 횟수(상대 동의) | `off` / `1` / `3` / `unlimited` | `3` |
| `drawOffer` | 무승부 제안 | `true` / `false` | `true` |
| `hints` | 이동 가능 칸 표시. 잡힐 위험 같은 위협 경고는 두지 않는다 | `off` / `moves` | `moves` |
| `hints` | 이동 가능 칸 표시 | `off` / `moves` | `moves` |
| `threatHints` | **관리자 전용** 위협 가이드: 잡힐 위험이 있는 내 기물 표시(방장은 못 바꿈) | `true` / `false` | `false` |
| `disconnectGraceSec` | 연결 끊김 유예 | 60 / 120 | 60 |
## 3. 구성물
@@ -180,7 +181,7 @@ interface JanggiState {
### 8.3 공개/비공개 정보 (view)
- 공개: 판, 차례, 기보, 잡은 기물, 현재 점수(덤 포함), 장군 상태, 빅장 응수 대기 여부, 반복 경고(같은 국면 3회째 도달 시 "한 번 더 반복하면 둘 수 없어요"), 시계, `deadline`, 대기 중인 요청, 결과.
- `setup` 단계 + `simultaneous`: 상대 선택값은 "선택 완료"(true/false)만 보이고 배치는 둘 다 확정될 때까지 숨긴다(플레이어·관전자 모두). `hanFirst`에서는 한의 선택이 즉시 공개.
- 차례인 플레이어에게만: `legalMoves`(하이라이트용).
- 차례인 플레이어에게만: `legalMoves`(하이라이트용), `threatHints`가 켜졌을 때 `threatened`(잡힐 위험 기물).
- 제외: `rng`, 상대의 미공개 상차림.
### 8.4 랜덤 요소 (시드 RNG 사용 지점)

View File

@@ -24,6 +24,7 @@
| `undo` | 무르기 요청 허용 횟수(1인당, 상대 동의 필요) | `off` / `1` / `3` / `unlimited` | `3` |
| `drawOffer` | 무승부 제안 허용 | `true` / `false` | `true` |
| `showForbidden` | 금수 자리 표시 (금수 있는 규칙만) | `true` / `false` | `true` |
| `threatHints` | **관리자 전용** 위협 가이드: 상대 3·4를 막을 자리 표시(방장은 못 바꿈) | `true` / `false` | `false` |
## 3. 구성물
- 15×15(교차점 225개) 또는 19×19(361개) 판. 돌은 교차점에 놓는다.
@@ -252,8 +253,8 @@ interface OmokState {
### 8.3 공개/비공개 정보 (view)
- 플레이어·관전자 공통 공개: 판, 차례, 기보, 승리 줄, 양쪽 남은 시간과 `deadline`, 대기 중인 무르기/무승부 요청 여부(누가 요청했는지), 남은 무르기 횟수, 결과.
- 차례인 플레이어에게만: `forbiddenPoints: Pt[]` (금수 표시 옵션이 켜져 있을 때). 상대의 3·4를 막으라는 경고(위협 표시)는 보내지 않는다.
- 관전자에게는 `forbiddenPoints`를 흑 기준으로 보여줄 수 있다(공개 정보이므로 허용, 해설용).
- 차례인 플레이어에게만: `forbiddenPoints: Pt[]` (금수 표시 옵션이 켜져 있을 때), `hints`(`threatHints`가 켜졌을 때만: 상대가 5목·4를 만들 자리).
- 관전자에게는 `forbiddenPoints`를 흑 기준으로 보여줄 수 있다(공개 정보이므로 허용, 해설용). 단 `hints`는 관전자에게 보내지 않는다(관전자가 플레이어에게 훈수 전달하는 것을 굳이 돕지 않기 위함).
- 절대 포함 금지: `rng`(시드/상태 — 자동 착수 위치 예측 가능), 서버 내부 메모이제이션.
### 8.4 랜덤 요소 (시드 RNG 사용 지점)
@@ -313,7 +314,7 @@ interface OmokResult {
- [ ] `perMove + autoMove`: 시간 초과 시 자동 착수가 합법 수이고 금수가 아니며, 같은 시드에서 항상 같은 자리. 3연속 자동 착수 시 시간패.
- [ ] `fischer`: 남은 시간 0 이후 도착한 착수는 거부되고 시간패, 정상 착수 시 증가분 가산.
- [ ] 연결 끊김: 끊긴 플레이어 차례에 유예 후 `onTimeout` 동작, 재접속 시 유예 타이머 해제.
- [ ] 정보 누출: 플레이어/관전자 view JSON에 `rng`가 없는지, 어떤 view에도 위협 표시(`hints`)가 없는지 스냅샷 테스트.
- [ ] 정보 누출: 플레이어/관전자 view JSON에 `rng`가 없는지, 관전자 view에 `hintThreats`가 없는지 스냅샷 테스트.
- [ ] 리플레이: 같은 시드 + 같은 액션 로그로 재실행 시 최종 상태 해시 동일.
## 11. 참고 자료